Add file logger support (#269)
This commit is contained in:
parent
fffd60d675
commit
0c4603d825
|
@ -7,7 +7,6 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/status-im/status-go/geth/api"
|
"github.com/status-im/status-go/geth/api"
|
||||||
"github.com/status-im/status-go/geth/log"
|
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
@ -87,7 +86,14 @@ var (
|
||||||
LogLevelFlag = cli.StringFlag{
|
LogLevelFlag = cli.StringFlag{
|
||||||
Name: "log",
|
Name: "log",
|
||||||
Usage: `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE"`,
|
Usage: `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE"`,
|
||||||
Value: "INFO",
|
Value: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogFileFlag defines a log filename
|
||||||
|
LogFileFlag = cli.StringFlag{
|
||||||
|
Name: "logfile",
|
||||||
|
Usage: `Path to the log file`,
|
||||||
|
Value: "",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -107,6 +113,7 @@ func init() {
|
||||||
DataDirFlag,
|
DataDirFlag,
|
||||||
NetworkIDFlag,
|
NetworkIDFlag,
|
||||||
LogLevelFlag,
|
LogLevelFlag,
|
||||||
|
LogFileFlag,
|
||||||
}
|
}
|
||||||
app.Before = func(ctx *cli.Context) error {
|
app.Before = func(ctx *cli.Context) error {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
@ -151,10 +158,11 @@ func makeNodeConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
||||||
|
|
||||||
nodeConfig.NodeKeyFile = ctx.GlobalString(NodeKeyFileFlag.Name)
|
nodeConfig.NodeKeyFile = ctx.GlobalString(NodeKeyFileFlag.Name)
|
||||||
|
|
||||||
if logLevel := ctx.GlobalString(LogLevelFlag.Name); len(logLevel) > 0 {
|
if logLevel := ctx.GlobalString(LogLevelFlag.Name); logLevel != "" {
|
||||||
nodeConfig.LogEnabled = true
|
|
||||||
nodeConfig.LogLevel = logLevel
|
nodeConfig.LogLevel = logLevel
|
||||||
log.SetLevel(logLevel)
|
}
|
||||||
|
if logFile := ctx.GlobalString(LogFileFlag.Name); logFile != "" {
|
||||||
|
nodeConfig.LogFile = logFile
|
||||||
}
|
}
|
||||||
|
|
||||||
return nodeConfig, nil
|
return nodeConfig, nil
|
||||||
|
|
|
@ -33,7 +33,6 @@ var nodeConfigJSON = `{
|
||||||
"DataDir": "` + TestDataDir + `",
|
"DataDir": "` + TestDataDir + `",
|
||||||
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
|
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
|
||||||
"WSPort": ` + strconv.Itoa(TestConfig.Node.WSPort) + `,
|
"WSPort": ` + strconv.Itoa(TestConfig.Node.WSPort) + `,
|
||||||
"LogEnabled": true,
|
|
||||||
"LogLevel": "INFO"
|
"LogLevel": "INFO"
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ func (s *APITestSuite) TestCHTUpdate() {
|
||||||
configJSON := `{
|
configJSON := `{
|
||||||
"NetworkId": ` + strconv.Itoa(params.RopstenNetworkID) + `,
|
"NetworkId": ` + strconv.Itoa(params.RopstenNetworkID) + `,
|
||||||
"DataDir": "` + tmpDir + `",
|
"DataDir": "` + tmpDir + `",
|
||||||
"LogEnabled": true,
|
|
||||||
"LogLevel": "INFO",
|
"LogLevel": "INFO",
|
||||||
"RPCEnabled": true
|
"RPCEnabled": true
|
||||||
}`
|
}`
|
||||||
|
|
|
@ -2,16 +2,28 @@ package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// logger is package scope instance of log.Logger
|
// Logger is a wrapper around log.Logger.
|
||||||
var logger = log.New("geth", "StatusIM")
|
type Logger struct {
|
||||||
|
log.Logger
|
||||||
|
Level log.Lvl
|
||||||
|
Handler log.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// logger is package scope instance of Logger
|
||||||
|
var logger = Logger{
|
||||||
|
Logger: log.New("geth", "StatusIM"),
|
||||||
|
Level: log.LvlError,
|
||||||
|
Handler: log.StreamHandler(os.Stdout, log.TerminalFormat(true)),
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
SetLevel("INFO")
|
setHandler(logger.Level, logger.Handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLevel inits status and ethereum-go logging packages,
|
// SetLevel inits status and ethereum-go logging packages,
|
||||||
|
@ -20,17 +32,36 @@ func init() {
|
||||||
// Our log levels are in form "DEBUG|ERROR|WARN|etc", while
|
// Our log levels are in form "DEBUG|ERROR|WARN|etc", while
|
||||||
// ethereum-go expects names in lower case: "debug|error|warn|etc".
|
// ethereum-go expects names in lower case: "debug|error|warn|etc".
|
||||||
func SetLevel(level string) {
|
func SetLevel(level string) {
|
||||||
lvl, err := log.LvlFromString(strings.ToLower(level))
|
lvl := levelFromString(level)
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Incorrect log level: %s, using defaults\n", level)
|
|
||||||
lvl = log.LvlInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
setHandler(lvl, log.StdoutHandler)
|
logger.Level = lvl
|
||||||
|
setHandler(lvl, logger.Handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setHandler is a init helper that allows (re)initialization
|
// SetLogFile configures logger to write output into file.
|
||||||
// with different handler. Useful for testing.
|
// This call preserves current logging level.
|
||||||
|
func SetLogFile(filename string) error {
|
||||||
|
handler, err := log.FileHandler(filename, log.TerminalFormat(false))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Handler = handler
|
||||||
|
setHandler(logger.Level, handler)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func levelFromString(level string) log.Lvl {
|
||||||
|
lvl, err := log.LvlFromString(strings.ToLower(level))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Incorrect log level: %s, using defaults\n", level)
|
||||||
|
lvl = log.LvlInfo
|
||||||
|
}
|
||||||
|
return lvl
|
||||||
|
}
|
||||||
|
|
||||||
|
// setHandler is a helper that allows log (re)initialization
|
||||||
|
// with different level and handler. Useful for testing.
|
||||||
func setHandler(lvl log.Lvl, handler log.Handler) {
|
func setHandler(lvl log.Lvl, handler log.Handler) {
|
||||||
h := log.LvlFilterHandler(lvl, handler)
|
h := log.LvlFilterHandler(lvl, handler)
|
||||||
logger.SetHandler(h)
|
logger.SetHandler(h)
|
||||||
|
|
|
@ -2,9 +2,11 @@ package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -44,8 +46,28 @@ func TestLogLevels(t *testing.T) {
|
||||||
Warn(warn)
|
Warn(warn)
|
||||||
Error(err)
|
Error(err)
|
||||||
|
|
||||||
if buf.String() != test.out {
|
require.Equal(t, test.out, buf.String())
|
||||||
t.Errorf("Expecting log output to be '%s', got '%s'", test.out, buf.String())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLogFile(t *testing.T) {
|
||||||
|
file, err := ioutil.TempFile("", "statusim_log_test")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// setup log
|
||||||
|
SetLevel("INFO")
|
||||||
|
SetLogFile(file.Name())
|
||||||
|
|
||||||
|
// test log output to file
|
||||||
|
Info(info)
|
||||||
|
Debug(debug)
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(file)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
got := string(data)
|
||||||
|
require.Contains(t, got, info)
|
||||||
|
require.NotContains(t, got, debug)
|
||||||
|
}
|
||||||
|
|
|
@ -70,6 +70,8 @@ func (m *NodeManager) startNode(config *params.NodeConfig) (<-chan struct{}, err
|
||||||
return nil, ErrNodeExists
|
return nil, ErrNodeExists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.initLog(config)
|
||||||
|
|
||||||
ethNode, err := MakeNode(config)
|
ethNode, err := MakeNode(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -580,3 +582,16 @@ func (m *NodeManager) RPCServer() (*rpc.Server, error) {
|
||||||
|
|
||||||
return m.rpcServer, nil
|
return m.rpcServer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initLog initializes global logger parameters based on
|
||||||
|
// provided node configurations.
|
||||||
|
func (m *NodeManager) initLog(config *params.NodeConfig) {
|
||||||
|
log.SetLevel(config.LogLevel)
|
||||||
|
|
||||||
|
if config.LogFile != "" {
|
||||||
|
err := log.SetLogFile(config.LogFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to open log file, using stdout")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -287,9 +287,6 @@ type NodeConfig struct {
|
||||||
// handshake phase, counted separately for inbound and outbound connections.
|
// handshake phase, counted separately for inbound and outbound connections.
|
||||||
MaxPendingPeers int
|
MaxPendingPeers int
|
||||||
|
|
||||||
// LogToFile specified whether logs should be saved into file
|
|
||||||
LogEnabled bool
|
|
||||||
|
|
||||||
// LogFile is filename where exposed logs get written to
|
// LogFile is filename where exposed logs get written to
|
||||||
LogFile string
|
LogFile string
|
||||||
|
|
||||||
|
|
|
@ -52,10 +52,10 @@ const (
|
||||||
DatabaseCache = 16
|
DatabaseCache = 16
|
||||||
|
|
||||||
// LogFile defines where to write logs to
|
// LogFile defines where to write logs to
|
||||||
LogFile = "geth.log"
|
LogFile = ""
|
||||||
|
|
||||||
// LogLevel defines the minimum log level to report
|
// LogLevel defines the minimum log level to report
|
||||||
LogLevel = "INFO"
|
LogLevel = "ERROR"
|
||||||
|
|
||||||
// LogLevelSuccinct defines the log level when only errors are reported.
|
// LogLevelSuccinct defines the log level when only errors are reported.
|
||||||
// Useful when the default INFO level becomes too verbose.
|
// Useful when the default INFO level becomes too verbose.
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
"TLSEnabled": false,
|
"TLSEnabled": false,
|
||||||
"MaxPeers": 25,
|
"MaxPeers": 25,
|
||||||
"MaxPendingPeers": 0,
|
"MaxPendingPeers": 0,
|
||||||
"LogEnabled": false,
|
"LogFile": "",
|
||||||
"LogFile": "geth.log",
|
"LogLevel": "ERROR",
|
||||||
"LogLevel": "INFO",
|
|
||||||
"LogToStderr": true,
|
"LogToStderr": true,
|
||||||
"UpstreamConfig": {
|
"UpstreamConfig": {
|
||||||
"Enabled": false,
|
"Enabled": false,
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
"TLSEnabled": false,
|
"TLSEnabled": false,
|
||||||
"MaxPeers": 25,
|
"MaxPeers": 25,
|
||||||
"MaxPendingPeers": 0,
|
"MaxPendingPeers": 0,
|
||||||
"LogEnabled": false,
|
"LogFile": "",
|
||||||
"LogFile": "geth.log",
|
"LogLevel": "ERROR",
|
||||||
"LogLevel": "INFO",
|
|
||||||
"LogToStderr": true,
|
"LogToStderr": true,
|
||||||
"UpstreamConfig": {
|
"UpstreamConfig": {
|
||||||
"Enabled": false,
|
"Enabled": false,
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
"TLSEnabled": false,
|
"TLSEnabled": false,
|
||||||
"MaxPeers": 25,
|
"MaxPeers": 25,
|
||||||
"MaxPendingPeers": 0,
|
"MaxPendingPeers": 0,
|
||||||
"LogEnabled": false,
|
"LogFile": "",
|
||||||
"LogFile": "geth.log",
|
"LogLevel": "ERROR",
|
||||||
"LogLevel": "INFO",
|
|
||||||
"LogToStderr": true,
|
"LogToStderr": true,
|
||||||
"UpstreamConfig": {
|
"UpstreamConfig": {
|
||||||
"Enabled": false,
|
"Enabled": false,
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
|
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/status-im/status-go/geth/common"
|
"github.com/status-im/status-go/geth/common"
|
||||||
"github.com/status-im/status-go/geth/log"
|
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
assertions "github.com/stretchr/testify/require"
|
assertions "github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
@ -54,8 +53,6 @@ func init() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.SetLevel("ERROR")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseTestSuite defines a base tests suit which others suites can embedded to
|
// BaseTestSuite defines a base tests suit which others suites can embedded to
|
||||||
|
@ -131,8 +128,7 @@ func MakeTestNodeConfig(networkID int) (*params.NodeConfig, error) {
|
||||||
"DataDir": "` + filepath.Join(TestDataDir, TestNetworkNames[networkID]) + `",
|
"DataDir": "` + filepath.Join(TestDataDir, TestNetworkNames[networkID]) + `",
|
||||||
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
|
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
|
||||||
"WSPort": ` + strconv.Itoa(TestConfig.Node.WSPort) + `,
|
"WSPort": ` + strconv.Itoa(TestConfig.Node.WSPort) + `,
|
||||||
"LogEnabled": true,
|
"LogLevel": "INFO"
|
||||||
"LogLevel": "ERROR"
|
|
||||||
}`
|
}`
|
||||||
nodeConfig, err := params.LoadNodeConfig(configJSON)
|
nodeConfig, err := params.LoadNodeConfig(configJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue