toolkit/log/log.go (101 lines of code) (raw):

package log import ( "context" "crypto/rand" "runtime" "github.com/sirupsen/logrus" otelTrace "go.opentelemetry.io/otel/trace" ) const ( upperCaseAlphanumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" epochFieldName = "env_epoch" fileNameFieldName = "fileName" lineNumberFieldName = "lineNumber" ) type Logger struct { logger *logrus.Entry } type loggerKeyType string const loggerKey loggerKeyType = "web-tls-manager" func (logger *Logger) WithLogger(ctx context.Context) context.Context { return context.WithValue(ctx, loggerKey, logger) } func MustGetLogger(ctx context.Context) *Logger { logger, loggerFound := ctx.Value(loggerKey).(*Logger) if !loggerFound { panic("Logger not found in context. Use WithLogger(ctx, logger) to create a context with a logger") } return logger } func getEpochRandomString() (string, error) { randomBytes := make([]byte, 5) _, err := rand.Read(randomBytes) if err != nil { return "", err } for index, randomByte := range randomBytes { foldedOffset := randomByte % byte(len(upperCaseAlphanumeric)) randomBytes[index] = upperCaseAlphanumeric[foldedOffset] } return string(randomBytes), nil } func NewLogger(loggerLevel int) *Logger { logger := logrus.New() switch loggerLevel { case 4: logger.SetLevel(logrus.DebugLevel) case 5: logger.SetLevel(logrus.TraceLevel) default: logger.SetLevel(logrus.InfoLevel) } logger.Formatter = &logrus.JSONFormatter{} epoch, _ := getEpochRandomString() return &Logger{logger: logger.WithField(epochFieldName, epoch)} } func (logger *Logger) withCallerInfo() *logrus.Entry { _, file, line, _ := runtime.Caller(3) fields := make(map[string]interface{}) fields[fileNameFieldName] = file fields[lineNumberFieldName] = line return logger.logger.WithFields(fields) } func GetOtelSpanFromContext(ctx context.Context) Span { span := otelTrace.SpanFromContext(ctx) return &otelSpan{span: span} } func (logger *Logger) withSpanInfo(ctx context.Context) *Logger { if ctx == nil { return logger } span := GetOtelSpanFromContext(ctx) if !span.IsValid() { return logger } logrusLogger := logger.logger.WithFields(map[string]interface{}{ "spanID": span.GetSpanID(), "traceID": span.GetTraceID(), }) return &Logger{logrusLogger} } func (logger *Logger) Info(ctx context.Context, msg string) { logger.withSpanInfo(ctx).withCallerInfo().Info(msg) } func (logger *Logger) Infof(ctx context.Context, fmt string, args ...interface{}) { logger.withSpanInfo(ctx).withCallerInfo().Infof(fmt, args...) } func (logger *Logger) Error(ctx context.Context, msg string) { logger.withSpanInfo(ctx).withCallerInfo().Error(msg) } func (logger *Logger) Errorf(ctx context.Context, fmt string, args ...interface{}) { logger.withSpanInfo(ctx).withCallerInfo().Errorf(fmt, args...) } func (logger *Logger) Warning(ctx context.Context, msg string) { logger.withSpanInfo(ctx).withCallerInfo().Error(msg) } func (logger *Logger) Warningf(ctx context.Context, fmt string, args ...interface{}) { logger.withSpanInfo(ctx).withCallerInfo().Warningf(fmt, args...) } func (logger *Logger) Debugf(ctx context.Context, fmt string, args ...interface{}) { logger.withSpanInfo(ctx).withCallerInfo().Debugf(fmt, args...) }