github.com/MetalBlockchain/metalgo@v1.11.9/utils/logging/log.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package logging 5 6 import ( 7 "io" 8 "os" 9 10 "go.uber.org/zap" 11 "go.uber.org/zap/zapcore" 12 ) 13 14 var _ Logger = (*log)(nil) 15 16 type log struct { 17 wrappedCores []WrappedCore 18 internalLogger *zap.Logger 19 } 20 21 type WrappedCore struct { 22 Core zapcore.Core 23 Writer io.WriteCloser 24 WriterDisabled bool 25 AtomicLevel zap.AtomicLevel 26 } 27 28 func NewWrappedCore(level Level, rw io.WriteCloser, encoder zapcore.Encoder) WrappedCore { 29 atomicLevel := zap.NewAtomicLevelAt(zapcore.Level(level)) 30 31 core := zapcore.NewCore(encoder, zapcore.AddSync(rw), atomicLevel) 32 return WrappedCore{AtomicLevel: atomicLevel, Core: core, Writer: rw} 33 } 34 35 func newZapLogger(prefix string, wrappedCores ...WrappedCore) *zap.Logger { 36 cores := make([]zapcore.Core, len(wrappedCores)) 37 for i, wc := range wrappedCores { 38 cores[i] = wc.Core 39 } 40 core := zapcore.NewTee(cores...) 41 logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(2)) 42 if prefix != "" { 43 logger = logger.Named(prefix) 44 } 45 46 return logger 47 } 48 49 // New returns a new logger set up according to [config] 50 func NewLogger(prefix string, wrappedCores ...WrappedCore) Logger { 51 return &log{ 52 internalLogger: newZapLogger(prefix, wrappedCores...), 53 wrappedCores: wrappedCores, 54 } 55 } 56 57 // TODO: return errors here 58 func (l *log) Write(p []byte) (int, error) { 59 for _, wc := range l.wrappedCores { 60 if wc.WriterDisabled { 61 continue 62 } 63 _, _ = wc.Writer.Write(p) 64 } 65 return len(p), nil 66 } 67 68 // TODO: return errors here 69 func (l *log) Stop() { 70 for _, wc := range l.wrappedCores { 71 if wc.Writer != os.Stdout && wc.Writer != os.Stderr { 72 _ = wc.Writer.Close() 73 } 74 } 75 } 76 77 // Enabled returns true if the given level is at or above this level. 78 func (l *log) Enabled(lvl Level) bool { 79 return l.internalLogger.Level().Enabled(zapcore.Level(lvl)) 80 } 81 82 // Should only be called from [Level] functions. 83 func (l *log) log(level Level, msg string, fields ...zap.Field) { 84 if ce := l.internalLogger.Check(zapcore.Level(level), msg); ce != nil { 85 ce.Write(fields...) 86 } 87 } 88 89 func (l *log) Fatal(msg string, fields ...zap.Field) { 90 l.log(Fatal, msg, fields...) 91 } 92 93 func (l *log) Error(msg string, fields ...zap.Field) { 94 l.log(Error, msg, fields...) 95 } 96 97 func (l *log) Warn(msg string, fields ...zap.Field) { 98 l.log(Warn, msg, fields...) 99 } 100 101 func (l *log) Info(msg string, fields ...zap.Field) { 102 l.log(Info, msg, fields...) 103 } 104 105 func (l *log) Trace(msg string, fields ...zap.Field) { 106 l.log(Trace, msg, fields...) 107 } 108 109 func (l *log) Debug(msg string, fields ...zap.Field) { 110 l.log(Debug, msg, fields...) 111 } 112 113 func (l *log) Verbo(msg string, fields ...zap.Field) { 114 l.log(Verbo, msg, fields...) 115 } 116 117 func (l *log) SetLevel(level Level) { 118 for _, core := range l.wrappedCores { 119 core.AtomicLevel.SetLevel(zapcore.Level(level)) 120 } 121 } 122 123 func (l *log) StopOnPanic() { 124 if r := recover(); r != nil { 125 l.Fatal("panicking", zap.Any("reason", r), zap.Stack("from")) 126 l.Stop() 127 panic(r) 128 } 129 } 130 131 func (l *log) RecoverAndPanic(f func()) { 132 defer l.StopOnPanic() 133 f() 134 } 135 136 func (l *log) stopAndExit(exit func()) { 137 if r := recover(); r != nil { 138 l.Fatal("panicking", zap.Any("reason", r), zap.Stack("from")) 139 l.Stop() 140 exit() 141 } 142 } 143 144 func (l *log) RecoverAndExit(f, exit func()) { 145 defer l.stopAndExit(exit) 146 f() 147 }