github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/aeron/logging/logging.go (about)

     1  // Copyright (C) 2021 Talos, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Provides a transition layer from "github.com/op/go-logging" to
    16  // "go.uber.org/zap" to simply resolve some reentrancy issues in go-logging.
    17  //
    18  // This provides a largely api compatible layer so we can quickly
    19  // drop in a replacement.
    20  package logging
    21  
    22  import (
    23  	"sync"
    24  
    25  	"go.uber.org/zap"
    26  	"go.uber.org/zap/zapcore"
    27  )
    28  
    29  // Zaplogger is a container to wrap zap logging with the parts of the go-logging API we use
    30  type ZapLogger struct {
    31  	name   string
    32  	sugar  *zap.SugaredLogger
    33  	logger *zap.Logger
    34  	config zap.Config
    35  }
    36  
    37  // Mapping of go-logging to zap log levels. It's imperfect but good enough
    38  const (
    39  	DEBUG    = zapcore.DebugLevel
    40  	INFO     = zapcore.InfoLevel
    41  	WARNING  = zapcore.WarnLevel
    42  	NOTICE   = zapcore.InfoLevel // Map to info
    43  	ERROR    = zapcore.ErrorLevel
    44  	CRITICAL = zapcore.DPanicLevel
    45  )
    46  
    47  // The go-logging package creates named loggers and allows them to be
    48  // accessed by name This is used in aeron to allow parent code to set
    49  // the logging level of library components so we need to provide a
    50  // mechanism for that
    51  var namedLoggers sync.Map // [string]*ZapLogger
    52  
    53  // MustGetLogger returns a new logger or panic()s
    54  func MustGetLogger(name string) *ZapLogger {
    55  	z := new(ZapLogger)
    56  	z.name = name
    57  
    58  	z.config = aeronLoggingConfig()
    59  	logger, err := z.config.Build()
    60  	if err != nil {
    61  		panic("Failed to make logger")
    62  	}
    63  	z.logger = logger.Named(name).WithOptions(zap.AddCallerSkip(1))
    64  	z.sugar = z.logger.Sugar()
    65  
    66  	// Keep a reference
    67  	namedLoggers.Store(name, z)
    68  
    69  	return z
    70  }
    71  
    72  // newAeronEncoderConfig returns a default opinionated EncoderConfig for aeron
    73  func newAeronEncoderConfig() zapcore.EncoderConfig {
    74  	return zapcore.EncoderConfig{
    75  		TimeKey:        "ts",
    76  		LevelKey:       "level",
    77  		NameKey:        "logger",
    78  		CallerKey:      "caller",
    79  		FunctionKey:    zapcore.OmitKey,
    80  		MessageKey:     "msg",
    81  		StacktraceKey:  "stacktrace",
    82  		LineEnding:     zapcore.DefaultLineEnding,
    83  		EncodeLevel:    zapcore.LowercaseLevelEncoder,
    84  		EncodeTime:     zapcore.ISO8601TimeEncoder,
    85  		EncodeDuration: zapcore.SecondsDurationEncoder,
    86  		EncodeCaller:   zapcore.ShortCallerEncoder,
    87  	}
    88  }
    89  
    90  // Default config
    91  func aeronLoggingConfig() zap.Config {
    92  	return zap.Config{
    93  		Level:       zap.NewAtomicLevelAt(zap.InfoLevel),
    94  		Development: false,
    95  		Sampling: &zap.SamplingConfig{
    96  			Initial:    100,
    97  			Thereafter: 100,
    98  		},
    99  		Encoding:         "console",
   100  		EncoderConfig:    newAeronEncoderConfig(),
   101  		OutputPaths:      []string{"stderr"},
   102  		ErrorOutputPaths: []string{"stderr"},
   103  	}
   104  }
   105  
   106  // SetConfigAndRebuild so you can replace the default config
   107  func (z *ZapLogger) SetConfigAndRebuild(c zap.Config) error {
   108  	z.config = c
   109  	logger, err := z.config.Build()
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	z.logger = logger.Named(z.name)
   115  	z.sugar = z.logger.Sugar()
   116  	return nil
   117  }
   118  
   119  // SetLevel on a named logger
   120  func SetLevel(l zapcore.Level, name string) {
   121  	z, ok := namedLoggers.Load(name)
   122  	if ok {
   123  		zlogger := z.(*ZapLogger)
   124  		zlogger.SetLevel(l)
   125  	}
   126  }
   127  
   128  // GetLevel on a named logger
   129  func GetLevel(name string) zapcore.Level {
   130  	z, ok := namedLoggers.Load(name)
   131  	if ok {
   132  		zlogger := z.(*ZapLogger)
   133  		return zlogger.GetLevel()
   134  	}
   135  
   136  	// Bogus return but that's the API we are emulating and shouldn't happen
   137  	return zapcore.InfoLevel
   138  }
   139  
   140  // Sugar returns the internal Sugared logger
   141  func (z *ZapLogger) Sugar() *zap.SugaredLogger {
   142  	return z.sugar
   143  }
   144  
   145  // SetSugar sets our internal Sugared logger
   146  func (z *ZapLogger) SetSugar(s *zap.SugaredLogger) {
   147  	z.sugar = s
   148  }
   149  
   150  // Logger returns the internal zap logger
   151  func (z *ZapLogger) Logger() *zap.Logger {
   152  	return z.logger
   153  }
   154  
   155  // SetLogger sets the internal zap logger
   156  func (z *ZapLogger) SetLogger(l *zap.Logger) {
   157  	z.logger = l
   158  }
   159  
   160  // SetLevel sets the log level at which we will log
   161  func (z *ZapLogger) SetLevel(l zapcore.Level) {
   162  	z.config.Level.SetLevel(l)
   163  }
   164  
   165  // GetLevel returns the log level at which we will log
   166  func (z *ZapLogger) GetLevel() zapcore.Level {
   167  	return z.config.Level.Level()
   168  }
   169  
   170  // IsEnabledFor returns true if logging is enabled for the specified level
   171  func (z *ZapLogger) IsEnabledFor(level zapcore.Level) bool {
   172  	return level >= z.GetLevel()
   173  }
   174  
   175  // Fatalf logs a formatted string at log level Fatal and will then always exit()
   176  func (z *ZapLogger) Fatalf(template string, args ...interface{}) {
   177  	z.sugar.Fatalf(template, args...)
   178  }
   179  
   180  // Errorf logs a formatted string at log level Error
   181  func (z *ZapLogger) Errorf(template string, args ...interface{}) {
   182  	z.sugar.Errorf(template, args...)
   183  }
   184  
   185  // Warningf logs a formatted string at log level Warning
   186  func (z *ZapLogger) Warningf(template string, args ...interface{}) {
   187  	z.sugar.Warnf(template, args...)
   188  }
   189  
   190  // Infof logs a formatted string at log level Info
   191  func (z *ZapLogger) Infof(template string, args ...interface{}) {
   192  	z.sugar.Infof(template, args...)
   193  }
   194  
   195  // Noticef logs a formatted string at log level *Info*
   196  func (z *ZapLogger) Noticef(template string, args ...interface{}) {
   197  	z.sugar.Infof(template, args...)
   198  }
   199  
   200  // Debugf logs a formatted string at log level Debug
   201  func (z *ZapLogger) Debugf(template string, args ...interface{}) {
   202  	z.sugar.Debugf(template, args...)
   203  }
   204  
   205  // Fatal logs it's arguments at log level Fatal
   206  func (z *ZapLogger) Fatal(args ...interface{}) {
   207  	z.sugar.Fatal(args...)
   208  }
   209  
   210  // Error logs it's arguments at log level Error
   211  func (z *ZapLogger) Error(args ...interface{}) {
   212  	z.sugar.Error(args...)
   213  }
   214  
   215  // Warning logs it's arguments at log level Warning
   216  func (z *ZapLogger) Warning(args ...interface{}) {
   217  	z.sugar.Warn(args...)
   218  }
   219  
   220  // Info logs it's arguments at log level Info
   221  func (z *ZapLogger) Info(args ...interface{}) {
   222  	z.sugar.Info(args...)
   223  }
   224  
   225  // Notice logs it's arguments at log level *Info*
   226  func (z *ZapLogger) Notice(args ...interface{}) {
   227  	z.sugar.Info(args...)
   228  }
   229  
   230  // Debug logs it's arguments at log level Debug
   231  func (z *ZapLogger) Debug(args ...interface{}) {
   232  	z.sugar.Debug(args...)
   233  }