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  }