zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/log/log.go (about)

     1  package log
     2  
     3  import (
     4  	"os"
     5  	"runtime"
     6  	"strconv"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/rs/zerolog"
    12  )
    13  
    14  const defaultPerms = 0o0600
    15  
    16  //nolint:gochecknoglobals
    17  var loggerSetTimeFormat sync.Once
    18  
    19  // Logger extends zerolog's Logger.
    20  type Logger struct {
    21  	zerolog.Logger
    22  }
    23  
    24  func (l Logger) Println(v ...interface{}) {
    25  	l.Logger.Error().Msg("panic recovered") //nolint: check-logs
    26  }
    27  
    28  func NewLogger(level, output string) Logger {
    29  	loggerSetTimeFormat.Do(func() {
    30  		zerolog.TimeFieldFormat = time.RFC3339Nano
    31  	})
    32  
    33  	lvl, err := zerolog.ParseLevel(level)
    34  	if err != nil {
    35  		panic(err)
    36  	}
    37  
    38  	zerolog.SetGlobalLevel(lvl)
    39  
    40  	var log zerolog.Logger
    41  
    42  	if output == "" {
    43  		log = zerolog.New(os.Stdout)
    44  	} else {
    45  		file, err := os.OpenFile(output, os.O_APPEND|os.O_WRONLY|os.O_CREATE, defaultPerms)
    46  		if err != nil {
    47  			panic(err)
    48  		}
    49  		log = zerolog.New(file)
    50  	}
    51  
    52  	return Logger{Logger: log.Hook(goroutineHook{}).With().Caller().Timestamp().Logger()}
    53  }
    54  
    55  func NewAuditLogger(level, output string) *Logger {
    56  	loggerSetTimeFormat.Do(func() {
    57  		zerolog.TimeFieldFormat = time.RFC3339Nano
    58  	})
    59  
    60  	lvl, err := zerolog.ParseLevel(level)
    61  	if err != nil {
    62  		panic(err)
    63  	}
    64  
    65  	zerolog.SetGlobalLevel(lvl)
    66  
    67  	var auditLog zerolog.Logger
    68  
    69  	if output == "" {
    70  		auditLog = zerolog.New(os.Stdout)
    71  	} else {
    72  		auditFile, err := os.OpenFile(output, os.O_APPEND|os.O_WRONLY|os.O_CREATE, defaultPerms)
    73  		if err != nil {
    74  			panic(err)
    75  		}
    76  
    77  		auditLog = zerolog.New(auditFile)
    78  	}
    79  
    80  	return &Logger{Logger: auditLog.With().Timestamp().Logger()}
    81  }
    82  
    83  // GoroutineID adds goroutine-id to logs to help debug concurrency issues.
    84  func GoroutineID() int {
    85  	var buf [64]byte
    86  	n := runtime.Stack(buf[:], false)
    87  	idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
    88  
    89  	id, err := strconv.Atoi(idField)
    90  	if err != nil {
    91  		return -1
    92  	}
    93  
    94  	return id
    95  }
    96  
    97  type goroutineHook struct{}
    98  
    99  func (h goroutineHook) Run(e *zerolog.Event, level zerolog.Level, _ string) {
   100  	if level != zerolog.NoLevel {
   101  		e.Int("goroutine", GoroutineID())
   102  	}
   103  }