Merge branch 'ethersphere-jsonlog' into develop

This commit is contained in:
obscuren 2015-03-22 21:43:58 +01:00
commit 59eab49cb8
9 changed files with 106 additions and 111 deletions

View File

@ -21,8 +21,7 @@ func TestFunc(t *testing.T) {
*/ */
func LogInit() { func LogInit() {
once.Do(func() { once.Do(func() {
var logsys = logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(logger.WarnLevel)) logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(logger.DebugDetailLevel))
logger.AddLogSystem(logsys)
}) })
} }
@ -41,11 +40,8 @@ func Testlog(t *testing.T) testLogger {
return l return l
} }
func (testLogger) GetLogLevel() logger.LogLevel { return logger.DebugLevel } func (l testLogger) LogPrint(msg logger.LogMsg) {
func (testLogger) SetLogLevel(logger.LogLevel) {} l.t.Log(msg.String())
func (l testLogger) LogPrint(level logger.LogLevel, msg string) {
l.t.Logf("%s", msg)
} }
func (testLogger) Detach() { func (testLogger) Detach() {
@ -68,12 +64,10 @@ func Benchlog(b *testing.B) benchLogger {
return l return l
} }
func (benchLogger) GetLogLevel() logger.LogLevel { return logger.Silence } func (l benchLogger) LogPrint(msg logger.LogMsg) {
l.b.Log(msg.String())
func (benchLogger) SetLogLevel(logger.LogLevel) {}
func (l benchLogger) LogPrint(level logger.LogLevel, msg string) {
l.b.Logf("%s", msg)
} }
func (benchLogger) Detach() { func (benchLogger) Detach() {
logger.Flush() logger.Flush()
logger.Reset() logger.Reset()

View File

@ -135,7 +135,7 @@ The Ethereum JavaScript VM exposes a node admin interface as well as the DAPP Ja
utils.JSpathFlag, utils.JSpathFlag,
utils.ListenPortFlag, utils.ListenPortFlag,
utils.LogFileFlag, utils.LogFileFlag,
utils.LogFormatFlag, utils.LogJSONFlag,
utils.LogLevelFlag, utils.LogLevelFlag,
utils.MaxPeersFlag, utils.MaxPeersFlag,
utils.MinerThreadsFlag, utils.MinerThreadsFlag,

View File

@ -117,10 +117,10 @@ var (
Usage: "0-5 (silent, error, warn, info, debug, debug detail)", Usage: "0-5 (silent, error, warn, info, debug, debug detail)",
Value: int(logger.InfoLevel), Value: int(logger.InfoLevel),
} }
LogFormatFlag = cli.StringFlag{ LogJSONFlag = cli.StringFlag{
Name: "logformat", Name: "logjson",
Usage: `"std" or "raw"`, Usage: "Send json structured log output to a file or '-' for standard output (default: no json output)",
Value: "std", Value: "",
} }
VMDebugFlag = cli.BoolFlag{ VMDebugFlag = cli.BoolFlag{
Name: "vmdebug", Name: "vmdebug",
@ -213,7 +213,7 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
NetworkId: ctx.GlobalInt(NetworkIdFlag.Name), NetworkId: ctx.GlobalInt(NetworkIdFlag.Name),
LogFile: ctx.GlobalString(LogFileFlag.Name), LogFile: ctx.GlobalString(LogFileFlag.Name),
LogLevel: ctx.GlobalInt(LogLevelFlag.Name), LogLevel: ctx.GlobalInt(LogLevelFlag.Name),
LogFormat: ctx.GlobalString(LogFormatFlag.Name), LogJSON: ctx.GlobalString(LogJSONFlag.Name),
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name), MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
AccountManager: GetAccountManager(ctx), AccountManager: GetAccountManager(ctx),
VmDebug: ctx.GlobalBool(VMDebugFlag.Name), VmDebug: ctx.GlobalBool(VMDebugFlag.Name),

View File

@ -42,11 +42,11 @@ type Config struct {
ProtocolVersion int ProtocolVersion int
NetworkId int NetworkId int
DataDir string DataDir string
LogFile string LogFile string
LogLevel int LogLevel int
LogFormat string LogJSON string
VmDebug bool VmDebug bool
MaxPeers int MaxPeers int
Port string Port string
@ -136,7 +136,7 @@ type Ethereum struct {
blockSub event.Subscription blockSub event.Subscription
miner *miner.Miner miner *miner.Miner
logger logger.LogSystem // logger logger.LogSystem
Mining bool Mining bool
DataDir string DataDir string
@ -147,7 +147,10 @@ type Ethereum struct {
func New(config *Config) (*Ethereum, error) { func New(config *Config) (*Ethereum, error) {
// Boostrap database // Boostrap database
servlogsystem := logger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat) logger.New(config.DataDir, config.LogFile, config.LogLevel)
if len(config.LogJSON) > 0 {
logger.NewJSONsystem(config.DataDir, config.LogJSON)
}
newdb := config.NewDB newdb := config.NewDB
if newdb == nil { if newdb == nil {
@ -174,12 +177,12 @@ func New(config *Config) (*Ethereum, error) {
servlogger.Infof("Protocol Version: %v, Network Id: %v", config.ProtocolVersion, config.NetworkId) servlogger.Infof("Protocol Version: %v, Network Id: %v", config.ProtocolVersion, config.NetworkId)
eth := &Ethereum{ eth := &Ethereum{
shutdownChan: make(chan bool), shutdownChan: make(chan bool),
blockDb: blockDb, blockDb: blockDb,
stateDb: stateDb, stateDb: stateDb,
extraDb: extraDb, extraDb: extraDb,
eventMux: &event.TypeMux{}, eventMux: &event.TypeMux{},
logger: servlogsystem, // logger: servlogsystem,
accountManager: config.AccountManager, accountManager: config.AccountManager,
DataDir: config.DataDir, DataDir: config.DataDir,
version: config.Name, // TODO should separate from Name version: config.Name, // TODO should separate from Name
@ -300,10 +303,11 @@ func (s *Ethereum) StartMining() error {
return nil return nil
} }
func (s *Ethereum) StopMining() { s.miner.Stop() } func (s *Ethereum) StopMining() { s.miner.Stop() }
func (s *Ethereum) IsMining() bool { return s.miner.Mining() } func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) Miner() *miner.Miner { return s.miner }
func (s *Ethereum) Logger() logger.LogSystem { return s.logger }
// func (s *Ethereum) Logger() logger.LogSystem { return s.logger }
func (s *Ethereum) Name() string { return s.net.Name } func (s *Ethereum) Name() string { return s.net.Name }
func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager }
func (s *Ethereum) ChainManager() *core.ChainManager { return s.chainManager } func (s *Ethereum) ChainManager() *core.ChainManager { return s.chainManager }

View File

@ -18,7 +18,7 @@ func openLogFile(datadir string, filename string) *os.File {
return file return file
} }
func New(datadir string, logFile string, logLevel int, logFormat string) LogSystem { func New(datadir string, logFile string, logLevel int) LogSystem {
var writer io.Writer var writer io.Writer
if logFile == "" { if logFile == "" {
writer = os.Stdout writer = os.Stdout
@ -27,14 +27,22 @@ func New(datadir string, logFile string, logLevel int, logFormat string) LogSyst
} }
var sys LogSystem var sys LogSystem
switch logFormat { sys = NewStdLogSystem(writer, log.LstdFlags, LogLevel(logLevel))
case "raw": AddLogSystem(sys)
sys = NewRawLogSystem(writer, 0, LogLevel(logLevel))
case "json": return sys
sys = NewJsonLogSystem(writer, 0, LogLevel(logLevel)) }
default:
sys = NewStdLogSystem(writer, log.LstdFlags, LogLevel(logLevel)) func NewJSONsystem(datadir string, logFile string) LogSystem {
} var writer io.Writer
if logFile == "-" {
writer = os.Stdout
} else {
writer = openLogFile(datadir, logFile)
}
var sys LogSystem
sys = NewJsonLogSystem(writer)
AddLogSystem(sys) AddLogSystem(sys)
return sys return sys

View File

@ -28,7 +28,6 @@ const (
InfoLevel InfoLevel
DebugLevel DebugLevel
DebugDetailLevel DebugDetailLevel
JsonLevel = 1000
) )
// A Logger prints messages prefixed by a given tag. It provides named // A Logger prints messages prefixed by a given tag. It provides named
@ -43,11 +42,11 @@ func NewLogger(tag string) *Logger {
} }
func (logger *Logger) Sendln(level LogLevel, v ...interface{}) { func (logger *Logger) Sendln(level LogLevel, v ...interface{}) {
logMessageC <- message{level, logger.tag + fmt.Sprintln(v...)} logMessageC <- stdMsg{level, logger.tag + fmt.Sprintln(v...)}
} }
func (logger *Logger) Sendf(level LogLevel, format string, v ...interface{}) { func (logger *Logger) Sendf(level LogLevel, format string, v ...interface{}) {
logMessageC <- message{level, logger.tag + fmt.Sprintf(format, v...)} logMessageC <- stdMsg{level, logger.tag + fmt.Sprintf(format, v...)}
} }
// Errorln writes a message with ErrorLevel. // Errorln writes a message with ErrorLevel.
@ -129,6 +128,6 @@ func (logger *JsonLogger) LogJson(v JsonLog) {
} }
jsontxt, _ := json.Marshal(obj) jsontxt, _ := json.Marshal(obj)
logMessageC <- message{JsonLevel, string(jsontxt)} logMessageC <- (jsonMsg(jsontxt))
} }

View File

@ -15,9 +15,11 @@ type TestLogSystem struct {
level LogLevel level LogLevel
} }
func (ls *TestLogSystem) LogPrint(level LogLevel, msg string) { func (ls *TestLogSystem) LogPrint(msg LogMsg) {
ls.mutex.Lock() ls.mutex.Lock()
ls.output += msg if ls.level >= msg.Level() {
ls.output += msg.String()
}
ls.mutex.Unlock() ls.mutex.Unlock()
} }
@ -47,9 +49,9 @@ type blockedLogSystem struct {
unblock chan struct{} unblock chan struct{}
} }
func (ls blockedLogSystem) LogPrint(level LogLevel, msg string) { func (ls blockedLogSystem) LogPrint(msg LogMsg) {
<-ls.unblock <-ls.unblock
ls.LogSystem.LogPrint(level, msg) ls.LogSystem.LogPrint(msg)
} }
func TestLoggerFlush(t *testing.T) { func TestLoggerFlush(t *testing.T) {

View File

@ -9,9 +9,7 @@ import (
// LogSystem is implemented by log output devices. // LogSystem is implemented by log output devices.
// All methods can be called concurrently from multiple goroutines. // All methods can be called concurrently from multiple goroutines.
type LogSystem interface { type LogSystem interface {
GetLogLevel() LogLevel LogPrint(LogMsg)
SetLogLevel(i LogLevel)
LogPrint(LogLevel, string)
} }
// NewStdLogSystem creates a LogSystem that prints to the given writer. // NewStdLogSystem creates a LogSystem that prints to the given writer.
@ -26,8 +24,13 @@ type stdLogSystem struct {
level uint32 level uint32
} }
func (t *stdLogSystem) LogPrint(level LogLevel, msg string) { func (t *stdLogSystem) LogPrint(msg LogMsg) {
t.logger.Print(msg) stdmsg, ok := msg.(stdMsg)
if ok {
if t.GetLogLevel() >= stdmsg.Level() {
t.logger.Print(stdmsg.String())
}
}
} }
func (t *stdLogSystem) SetLogLevel(i LogLevel) { func (t *stdLogSystem) SetLogLevel(i LogLevel) {
@ -38,50 +41,20 @@ func (t *stdLogSystem) GetLogLevel() LogLevel {
return LogLevel(atomic.LoadUint32(&t.level)) return LogLevel(atomic.LoadUint32(&t.level))
} }
// NewRawLogSystem creates a LogSystem that prints to the given writer without // NewJSONLogSystem creates a LogSystem that prints to the given writer without
// adding extra information. Suitable for preformatted output // adding extra information irrespective of loglevel only if message is JSON type
func NewRawLogSystem(writer io.Writer, flags int, level LogLevel) LogSystem { func NewJsonLogSystem(writer io.Writer) LogSystem {
logger := log.New(writer, "", 0) logger := log.New(writer, "", 0)
return &rawLogSystem{logger, uint32(level)} return &jsonLogSystem{logger}
}
type rawLogSystem struct {
logger *log.Logger
level uint32
}
func (t *rawLogSystem) LogPrint(level LogLevel, msg string) {
t.logger.Print(msg)
}
func (t *rawLogSystem) SetLogLevel(i LogLevel) {
atomic.StoreUint32(&t.level, uint32(i))
}
func (t *rawLogSystem) GetLogLevel() LogLevel {
return LogLevel(atomic.LoadUint32(&t.level))
}
// NewRawLogSystem creates a LogSystem that prints to the given writer without
// adding extra information. Suitable for preformatted output
func NewJsonLogSystem(writer io.Writer, flags int, level LogLevel) LogSystem {
logger := log.New(writer, "", 0)
return &jsonLogSystem{logger, uint32(level)}
} }
type jsonLogSystem struct { type jsonLogSystem struct {
logger *log.Logger logger *log.Logger
level uint32
} }
func (t *jsonLogSystem) LogPrint(level LogLevel, msg string) { func (t *jsonLogSystem) LogPrint(msg LogMsg) {
t.logger.Print(msg) jsonmsg, ok := msg.(jsonMsg)
} if ok {
t.logger.Print(jsonmsg.String())
func (t *jsonLogSystem) SetLogLevel(i LogLevel) { }
atomic.StoreUint32(&t.level, uint32(i))
}
func (t *jsonLogSystem) GetLogLevel() LogLevel {
return LogLevel(atomic.LoadUint32(&t.level))
} }

View File

@ -1,16 +1,40 @@
package logger package logger
import ( import (
"fmt"
"sync" "sync"
) )
type message struct { type stdMsg struct {
level LogLevel level LogLevel
msg string msg string
} }
type jsonMsg []byte
func (m jsonMsg) Level() LogLevel {
return 0
}
func (m jsonMsg) String() string {
return string(m)
}
type LogMsg interface {
Level() LogLevel
fmt.Stringer
}
func (m stdMsg) Level() LogLevel {
return m.level
}
func (m stdMsg) String() string {
return m.msg
}
var ( var (
logMessageC = make(chan message) logMessageC = make(chan LogMsg)
addSystemC = make(chan LogSystem) addSystemC = make(chan LogSystem)
flushC = make(chan chan struct{}) flushC = make(chan chan struct{})
resetC = make(chan chan struct{}) resetC = make(chan chan struct{})
@ -27,11 +51,11 @@ const sysBufferSize = 500
func dispatchLoop() { func dispatchLoop() {
var ( var (
systems []LogSystem systems []LogSystem
systemIn []chan message systemIn []chan LogMsg
systemWG sync.WaitGroup systemWG sync.WaitGroup
) )
bootSystem := func(sys LogSystem) { bootSystem := func(sys LogSystem) {
in := make(chan message, sysBufferSize) in := make(chan LogMsg, sysBufferSize)
systemIn = append(systemIn, in) systemIn = append(systemIn, in)
systemWG.Add(1) systemWG.Add(1)
go sysLoop(sys, in, &systemWG) go sysLoop(sys, in, &systemWG)
@ -73,18 +97,9 @@ func dispatchLoop() {
} }
} }
func sysLoop(sys LogSystem, in <-chan message, wg *sync.WaitGroup) { func sysLoop(sys LogSystem, in <-chan LogMsg, wg *sync.WaitGroup) {
for msg := range in { for msg := range in {
switch sys.(type) { sys.LogPrint(msg)
case *jsonLogSystem:
if msg.level == JsonLevel {
sys.LogPrint(msg.level, msg.msg)
}
default:
if sys.GetLogLevel() >= msg.level {
sys.LogPrint(msg.level, msg.msg)
}
}
} }
wg.Done() wg.Done()
} }