diff --git a/cmd/nano2nano/main.go b/cmd/nano2nano/main.go index 9e320f1..607bbd1 100644 --- a/cmd/nano2nano/main.go +++ b/cmd/nano2nano/main.go @@ -36,7 +36,7 @@ func main() { return } - logger := stdlogfmt.New(stdlog.Default(), *flDebug) + logger := stdlogfmt.New(stdlogfmt.WithDebugFlag(*flDebug)) var skipServer bool if *flURL == "" || *flAPIKey == "" { diff --git a/cmd/nanomdm/main.go b/cmd/nanomdm/main.go index 0dd95b6..c0d14dd 100644 --- a/cmd/nanomdm/main.go +++ b/cmd/nanomdm/main.go @@ -72,7 +72,7 @@ func main() { stdlog.Fatal("nothing for server to do") } - logger := stdlogfmt.New(stdlog.Default(), *flDebug) + logger := stdlogfmt.New(stdlogfmt.WithDebugFlag(*flDebug)) if *flRootsPath == "" { stdlog.Fatal("must supply CA cert path flag") diff --git a/log/stdlogfmt/stdlog.go b/log/stdlogfmt/stdlog.go index a24d186..9accbfb 100644 --- a/log/stdlogfmt/stdlog.go +++ b/log/stdlogfmt/stdlog.go @@ -1,33 +1,93 @@ package stdlogfmt import ( + "fmt" stdlog "log" + "os" + "path/filepath" + "runtime" "strings" + "time" "github.com/micromdm/nanomdm/log" ) // Logger wraps a standard library logger and adapts it to pkg/log. type Logger struct { - stdLogger *stdlog.Logger - context []interface{} - logDebug bool + logger *stdlog.Logger + context []interface{} + debug bool + depth int + ts bool } -// New creates a new logger that adapts the standard log package to pkg/log. -func New(logger *stdlog.Logger, logDebug bool) *Logger { - return &Logger{ - stdLogger: logger, - logDebug: logDebug, +type Option func(*Logger) + +// WithLogger sets the Go standard logger to use. +func WithLogger(logger *stdlog.Logger) Option { + return func(l *Logger) { + l.logger = logger + } +} + +// WithDebug turns on debug logging. +func WithDebug() Option { + return func(l *Logger) { + l.debug = true + } +} + +// WithDebugFlag sets debug logging on or off. +func WithDebugFlag(flag bool) Option { + return func(l *Logger) { + l.debug = flag + } +} + +// WithCallerDepth sets the call depth of the logger for filename and line +// logging. Set depth to 0 to disable filename and line logging. +func WithCallerDepth(depth int) Option { + return func(l *Logger) { + l.depth = depth } } +// WithoutTimestamp disables outputting an RFC3339 timestamp. +func WithoutTimestamp() Option { + return func(l *Logger) { + l.ts = false + } +} + +// New creates a new logger that adapts the Go standard log package to Logger. +func New(opts ...Option) *Logger { + l := &Logger{ + logger: stdlog.New(os.Stderr, "", 0), + depth: 1, + ts: true, + } + for _, opt := range opts { + opt(l) + } + return l +} + func (l *Logger) print(args ...interface{}) { + if l.ts { + args = append([]interface{}{"ts", time.Now().Format(time.RFC3339)}, args...) + } + if l.depth > 0 { + _, filename, line, ok := runtime.Caller(l.depth + 1) + if ok { + caller := fmt.Sprintf("%s:%d", filepath.Base(filename), line) + args = append(args, "caller", caller) + } + } f := strings.Repeat(" %s=%v", len(args)/2)[1:] if len(args)%2 == 1 { f += " UNKNOWN=%v" } - l.stdLogger.Printf(f, args...) + l.logger.Printf(f, args...) } // Info logs using the "info" level @@ -40,7 +100,7 @@ func (l *Logger) Info(args ...interface{}) { // Info logs using the "debug" level func (l *Logger) Debug(args ...interface{}) { - if l.logDebug { + if l.debug { logs := []interface{}{"level", "debug"} logs = append(logs, l.context...) logs = append(logs, args...) @@ -50,11 +110,7 @@ func (l *Logger) Debug(args ...interface{}) { // With creates a new logger using args as context func (l *Logger) With(args ...interface{}) log.Logger { - newLogger := &Logger{ - stdLogger: l.stdLogger, - context: l.context, - logDebug: l.logDebug, - } - newLogger.context = append(newLogger.context, args...) - return newLogger + l2 := *l + l2.context = append(l2.context, args...) + return &l2 }