github.com/sharovik/devbot@v1.0.1-0.20240308094637-4a0387c40516/internal/log/logger.go (about)

     1  package log
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/pkg/errors"
     8  	"github.com/rs/zerolog"
     9  	"github.com/rs/zerolog/log"
    10  	"github.com/rs/zerolog/pkgerrors"
    11  )
    12  
    13  var loggerInstance LoggerInstance
    14  
    15  // Config configuration required by Logger
    16  type Config struct {
    17  	Env               string
    18  	Output            string
    19  	Level             string
    20  	FieldContext      string
    21  	FieldLevelName    string
    22  	FieldErrorMessage string
    23  }
    24  
    25  // LoggerInstance shared state
    26  type LoggerInstance struct {
    27  	config      Config
    28  	env         string
    29  	context     map[string]interface{}
    30  	initialized bool
    31  }
    32  
    33  // default constants
    34  const (
    35  	FieldContext      = "context"
    36  	FieldLevelName    = "level_name"
    37  	FieldErrorMessage = "error_message"
    38  
    39  	appEnvTesting = "testing"
    40  
    41  	Dbg   = "debug"
    42  	Inf   = "info"
    43  	Err   = "error"
    44  	Warn  = "warn"
    45  	Fatal = "fatal"
    46  	Panic = "panic"
    47  
    48  	OutputConsole = "console"
    49  	OutputJSON    = "json"
    50  )
    51  
    52  func (l *LoggerInstance) setLogLevel() {
    53  	switch l.config.Level {
    54  	case Dbg:
    55  		zerolog.SetGlobalLevel(zerolog.DebugLevel)
    56  	case Inf:
    57  		zerolog.SetGlobalLevel(zerolog.InfoLevel)
    58  	case Err:
    59  		zerolog.SetGlobalLevel(zerolog.ErrorLevel)
    60  	case Warn:
    61  		zerolog.SetGlobalLevel(zerolog.WarnLevel)
    62  	case Fatal:
    63  		zerolog.SetGlobalLevel(zerolog.FatalLevel)
    64  	case Panic:
    65  		zerolog.SetGlobalLevel(zerolog.PanicLevel)
    66  	default:
    67  		zerolog.SetGlobalLevel(zerolog.InfoLevel)
    68  	}
    69  }
    70  
    71  func (l *LoggerInstance) getOutput() zerolog.Context {
    72  	switch l.config.Output {
    73  	case OutputConsole:
    74  		return log.Output(zerolog.NewConsoleWriter()).With()
    75  	case OutputJSON:
    76  		return log.With()
    77  	}
    78  
    79  	return log.With()
    80  }
    81  
    82  // Init initializes the logger (required before use)
    83  func Init(config Config) error {
    84  	loggerInstance = LoggerInstance{
    85  		config:      config,
    86  		env:         config.Env,
    87  		context:     make(map[string]interface{}),
    88  		initialized: true,
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  // Refresh refreshes the logger instance
    95  func Refresh() {
    96  	loggerInstance = LoggerInstance{}
    97  }
    98  
    99  // IsInitialized function retrieves current status of logger instance
   100  func IsInitialized() bool {
   101  	return loggerInstance.initialized
   102  }
   103  
   104  // Logger returns a pointer to the singleton Logger loggerInstance
   105  func Logger() *LoggerInstance {
   106  	if !loggerInstance.initialized {
   107  		panic("logger not initialized")
   108  	}
   109  	return &loggerInstance
   110  }
   111  
   112  // AppendGlobalContext for setting global context
   113  func (l *LoggerInstance) AppendGlobalContext(context map[string]interface{}) {
   114  	if l.context == nil {
   115  		l.context = context
   116  	}
   117  
   118  	for field, value := range context {
   119  		l.context[field] = value
   120  	}
   121  
   122  	l.Debug().Interface("context_changes", context).Msg("Append new global context")
   123  }
   124  
   125  // GlobalContext method retrieve the GlobalContext variable
   126  func (l *LoggerInstance) GlobalContext() map[string]interface{} {
   127  	return l.context
   128  }
   129  
   130  // DestroyGlobalContext method for global context destroy
   131  func (l *LoggerInstance) DestroyGlobalContext() {
   132  	l.context = make(map[string]interface{})
   133  }
   134  
   135  // AddError for correct error messages parse
   136  func (l *LoggerInstance) AddError(err error) *zerolog.Event {
   137  	err = errors.Wrap(err, err.Error())
   138  	return l.Error().Stack().Err(err)
   139  }
   140  
   141  // DefaultContext method which returns Logger with default context
   142  func (l *LoggerInstance) DefaultContext() *zerolog.Logger {
   143  	l.setLogLevel()
   144  	var context = zerolog.Context{}
   145  	switch l.config.Env {
   146  	case appEnvTesting:
   147  		//For testing environment we need to disable the logs
   148  		context = log.Output(io.Discard).With()
   149  	default:
   150  		context = l.getOutput()
   151  	}
   152  
   153  	zerolog.TimestampFieldName = "@timestamp"
   154  	zerolog.LevelFieldName = l.config.FieldLevelName
   155  	zerolog.ErrorFieldName = l.config.FieldErrorMessage
   156  	zerolog.TimeFieldFormat = "2006-01-02T15:04:05.000000"
   157  	zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
   158  
   159  	logger := context.
   160  		Interface(l.config.FieldContext, l.context).
   161  		Logger()
   162  
   163  	return &logger
   164  }
   165  
   166  // Debug method for messages with level DEBUG
   167  func (l *LoggerInstance) Debug() *zerolog.Event {
   168  	return l.DefaultContext().Debug()
   169  }
   170  
   171  // Info method for messages with level INFO
   172  func (l *LoggerInstance) Info() *zerolog.Event {
   173  	return l.DefaultContext().Info()
   174  }
   175  
   176  // Error method for messages with level ERROR
   177  func (l *LoggerInstance) Error() *zerolog.Event {
   178  	return l.DefaultContext().Error()
   179  }
   180  
   181  // Warn method for messages with level WARNING
   182  func (l *LoggerInstance) Warn() *zerolog.Event {
   183  	return l.DefaultContext().Warn()
   184  }
   185  
   186  // StartMessage adds message with START postfix
   187  func (l *LoggerInstance) StartMessage(msg string) {
   188  	l.DefaultContext().Info().Msg(fmt.Sprintf("%s: %s", msg, "START"))
   189  }
   190  
   191  // FinishMessage adds message with FINISH postfix
   192  func (l *LoggerInstance) FinishMessage(msg string) {
   193  	l.DefaultContext().Info().Msg(fmt.Sprintf("%s: %s", msg, "FINISH"))
   194  }