From 91b4a5711c6c24fcafb7df83eac242c186e13984 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Tue, 29 Oct 2013 10:38:51 -0400 Subject: [PATCH] Fix logger formatting. This change copies the behavior of btcd for using seelog for logging, including making timestamps human readable, and setting the default logging level to info. Fixes #8. --- cmd.go | 16 +++++++- config.go | 28 ++++++++++++++ log.go | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 log.go diff --git a/cmd.go b/cmd.go index ce32049..cc97966 100644 --- a/cmd.go +++ b/cmd.go @@ -26,7 +26,6 @@ import ( "github.com/conformal/btcwallet/tx" "github.com/conformal/btcwallet/wallet" "github.com/conformal/btcwire" - "github.com/conformal/seelog" "os" "path/filepath" "sync" @@ -43,7 +42,6 @@ var ( ErrNoWallet = errors.New("wallet file does not exist") cfg *config - log = seelog.Default curHeight = struct { sync.RWMutex @@ -617,6 +615,15 @@ func JSONIDGenerator(c chan uint64) { } func main() { + // Initialize logging and setup deferred flushing to ensure all + // outstanding messages are written on shutdown + loggers := setLogLevel(defaultLogLevel) + defer func() { + for _, logger := range loggers { + logger.Flush() + } + }() + tcfg, _, err := loadConfig() if err != nil { log.Error(err) @@ -624,6 +631,11 @@ func main() { } cfg = tcfg + // Change the logging level if needed. + if cfg.DebugLevel != defaultLogLevel { + loggers = setLogLevel(cfg.DebugLevel) + } + // Open default wallet w, err := OpenWallet(cfg, "") if err != nil { diff --git a/config.go b/config.go index 4452604..0477dc3 100644 --- a/config.go +++ b/config.go @@ -167,5 +167,33 @@ func loadConfig() (*config, []string, error) { } updateConfigWithActiveParams(&cfg) + // Validate debug log level + if !validLogLevel(cfg.DebugLevel) { + str := "%s: The specified debug level [%v] is invalid" + err := fmt.Errorf(str, "loadConfig", cfg.DebugLevel) + fmt.Fprintln(os.Stderr, err) + parser.WriteHelp(os.Stderr) + return nil, nil, err + } + return &cfg, remainingArgs, nil } + +// validLogLevel returns whether or not logLevel is a valid debug log level. +func validLogLevel(logLevel string) bool { + switch logLevel { + case "trace": + fallthrough + case "debug": + fallthrough + case "info": + fallthrough + case "warn": + fallthrough + case "error": + fallthrough + case "critical": + return true + } + return false +} diff --git a/log.go b/log.go new file mode 100644 index 0000000..484a70b --- /dev/null +++ b/log.go @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013 Conformal Systems LLC + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package main + +import ( + "fmt" + "github.com/conformal/seelog" + "os" +) + +const ( + // lockTimeThreshold is the number below which a lock time is + // interpreted to be a block number. Since an average of one block + // is generated per 10 minutes, this allows blocks for about 9,512 + // years. However, if the field is interpreted as a timestamp, given + // the lock time is a uint32, the max is sometime around 2106. + lockTimeThreshold uint32 = 5e8 // Tue Nov 5 00:53:20 1985 UTC +) + +var ( + log = seelog.Disabled +) + +// logClosure is used to provide a closure over expensive logging operations +// so don't have to be performed when the logging level doesn't warrant it. +type logClosure func() string + +// String invokes the underlying function and returns the result. +func (c logClosure) String() string { + return c() +} + +// newLogClosure returns a new closure over a function that returns a string +// which itself provides a Stringer interface so that it can be used with the +// logging system. +func newLogClosure(c func() string) logClosure { + return logClosure(c) +} + +// newLogger creates a new seelog logger using the provided logging level and +// log message prefix. +func newLogger(level string, prefix string) seelog.LoggerInterface { + // + + fmtstring := ` + + + + + + + + ` + config := fmt.Sprintf(fmtstring, level, prefix) + + logger, err := seelog.LoggerFromConfigAsString(config) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to create logger: %v", err) + os.Exit(1) + } + + return logger +} + +// useLogger sets the btcd logger to the passed logger. +func useLogger(logger seelog.LoggerInterface) { + log = logger +} + +// setLogLevel sets the log level for the logging system. It initializes a +// logger for each subsystem at the provided level. +func setLogLevel(logLevel string) []seelog.LoggerInterface { + var loggers []seelog.LoggerInterface + + // Define sub-systems. + subSystems := []struct { + level string + prefix string + useLogger func(seelog.LoggerInterface) + }{ + {logLevel, "BTCW", useLogger}, + } + + // Configure all sub-systems with new loggers while keeping track of + // the created loggers to return so they can be flushed. + for _, s := range subSystems { + newLog := newLogger(s.level, s.prefix) + loggers = append(loggers, newLog) + s.useLogger(newLog) + } + + return loggers +}