Add file logger support (#269)

This commit is contained in:
Ivan Daniluk 2017-09-01 20:44:50 +02:00 committed by Ivan Tomilov
parent fffd60d675
commit 0c4603d825
12 changed files with 107 additions and 43 deletions

View File

@ -7,7 +7,6 @@ import (
"runtime"
"github.com/status-im/status-go/geth/api"
"github.com/status-im/status-go/geth/log"
"github.com/status-im/status-go/geth/params"
"gopkg.in/urfave/cli.v1"
)
@ -87,7 +86,14 @@ var (
LogLevelFlag = cli.StringFlag{
Name: "log",
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,
NetworkIDFlag,
LogLevelFlag,
LogFileFlag,
}
app.Before = func(ctx *cli.Context) error {
runtime.GOMAXPROCS(runtime.NumCPU())
@ -151,10 +158,11 @@ func makeNodeConfig(ctx *cli.Context) (*params.NodeConfig, error) {
nodeConfig.NodeKeyFile = ctx.GlobalString(NodeKeyFileFlag.Name)
if logLevel := ctx.GlobalString(LogLevelFlag.Name); len(logLevel) > 0 {
nodeConfig.LogEnabled = true
if logLevel := ctx.GlobalString(LogLevelFlag.Name); logLevel != "" {
nodeConfig.LogLevel = logLevel
log.SetLevel(logLevel)
}
if logFile := ctx.GlobalString(LogFileFlag.Name); logFile != "" {
nodeConfig.LogFile = logFile
}
return nodeConfig, nil

View File

@ -33,7 +33,6 @@ var nodeConfigJSON = `{
"DataDir": "` + TestDataDir + `",
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
"WSPort": ` + strconv.Itoa(TestConfig.Node.WSPort) + `,
"LogEnabled": true,
"LogLevel": "INFO"
}`

View File

@ -43,7 +43,6 @@ func (s *APITestSuite) TestCHTUpdate() {
configJSON := `{
"NetworkId": ` + strconv.Itoa(params.RopstenNetworkID) + `,
"DataDir": "` + tmpDir + `",
"LogEnabled": true,
"LogLevel": "INFO",
"RPCEnabled": true
}`

View File

@ -2,16 +2,28 @@ package log
import (
"fmt"
"os"
"strings"
"github.com/ethereum/go-ethereum/log"
)
// logger is package scope instance of log.Logger
var logger = log.New("geth", "StatusIM")
// Logger is a wrapper around log.Logger.
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() {
SetLevel("INFO")
setHandler(logger.Level, logger.Handler)
}
// 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
// ethereum-go expects names in lower case: "debug|error|warn|etc".
func SetLevel(level string) {
lvl, err := log.LvlFromString(strings.ToLower(level))
if err != nil {
fmt.Printf("Incorrect log level: %s, using defaults\n", level)
lvl = log.LvlInfo
}
lvl := levelFromString(level)
setHandler(lvl, log.StdoutHandler)
logger.Level = lvl
setHandler(lvl, logger.Handler)
}
// setHandler is a init helper that allows (re)initialization
// with different handler. Useful for testing.
// SetLogFile configures logger to write output into file.
// 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) {
h := log.LvlFilterHandler(lvl, handler)
logger.SetHandler(h)

View File

@ -2,9 +2,11 @@ package log
import (
"bytes"
"io/ioutil"
"testing"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
const (
@ -44,8 +46,28 @@ func TestLogLevels(t *testing.T) {
Warn(warn)
Error(err)
if buf.String() != test.out {
t.Errorf("Expecting log output to be '%s', got '%s'", test.out, buf.String())
}
require.Equal(t, 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)
}

View File

@ -70,6 +70,8 @@ func (m *NodeManager) startNode(config *params.NodeConfig) (<-chan struct{}, err
return nil, ErrNodeExists
}
m.initLog(config)
ethNode, err := MakeNode(config)
if err != nil {
return nil, err
@ -580,3 +582,16 @@ func (m *NodeManager) RPCServer() (*rpc.Server, error) {
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")
}
}
}

View File

@ -287,9 +287,6 @@ type NodeConfig struct {
// handshake phase, counted separately for inbound and outbound connections.
MaxPendingPeers int
// LogToFile specified whether logs should be saved into file
LogEnabled bool
// LogFile is filename where exposed logs get written to
LogFile string

View File

@ -52,10 +52,10 @@ const (
DatabaseCache = 16
// LogFile defines where to write logs to
LogFile = "geth.log"
LogFile = ""
// LogLevel defines the minimum log level to report
LogLevel = "INFO"
LogLevel = "ERROR"
// LogLevelSuccinct defines the log level when only errors are reported.
// Useful when the default INFO level becomes too verbose.

View File

@ -18,9 +18,8 @@
"TLSEnabled": false,
"MaxPeers": 25,
"MaxPendingPeers": 0,
"LogEnabled": false,
"LogFile": "geth.log",
"LogLevel": "INFO",
"LogFile": "",
"LogLevel": "ERROR",
"LogToStderr": true,
"UpstreamConfig": {
"Enabled": false,
@ -62,4 +61,4 @@
"SwarmConfig": {
"Enabled": false
}
}
}

View File

@ -18,9 +18,8 @@
"TLSEnabled": false,
"MaxPeers": 25,
"MaxPendingPeers": 0,
"LogEnabled": false,
"LogFile": "geth.log",
"LogLevel": "INFO",
"LogFile": "",
"LogLevel": "ERROR",
"LogToStderr": true,
"UpstreamConfig": {
"Enabled": false,
@ -62,4 +61,4 @@
"SwarmConfig": {
"Enabled": false
}
}
}

View File

@ -18,9 +18,8 @@
"TLSEnabled": false,
"MaxPeers": 25,
"MaxPendingPeers": 0,
"LogEnabled": false,
"LogFile": "geth.log",
"LogLevel": "INFO",
"LogFile": "",
"LogLevel": "ERROR",
"LogToStderr": true,
"UpstreamConfig": {
"Enabled": false,
@ -74,4 +73,4 @@
"SwarmConfig": {
"Enabled": false
}
}
}

View File

@ -11,7 +11,6 @@ import (
gethcommon "github.com/ethereum/go-ethereum/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"
assertions "github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
@ -54,8 +53,6 @@ func init() {
if err != nil {
panic(err)
}
log.SetLevel("ERROR")
}
// 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]) + `",
"HTTPPort": ` + strconv.Itoa(TestConfig.Node.HTTPPort) + `,
"WSPort": ` + strconv.Itoa(TestConfig.Node.WSPort) + `,
"LogEnabled": true,
"LogLevel": "ERROR"
"LogLevel": "INFO"
}`
nodeConfig, err := params.LoadNodeConfig(configJSON)
if err != nil {