mirror of
https://github.com/sot-tech/mochi.git
synced 2026-07-17 13:48:11 -07:00
(tested) complete replace logrus with zerolog
* remove cobra dependency and split execs to mochi and e2e * add log init synchronization
This commit is contained in:
@@ -19,6 +19,7 @@ var ErrNilConfigMap = errors.New("unable to process nil map")
|
||||
// MapConfig is just alias for map[string]any
|
||||
type MapConfig map[string]any
|
||||
|
||||
// MarshalZerologObject writes map into zerolog event
|
||||
func (m MapConfig) MarshalZerologObject(e *zerolog.Event) {
|
||||
e.Fields(map[string]any(m))
|
||||
}
|
||||
|
||||
+233
-10
@@ -1,21 +1,37 @@
|
||||
// Package log adds a thin wrapper around logrus to improve non-debug logging
|
||||
// performance.
|
||||
// Package log adds a thin wrapper around zerolog to improve logging performance.
|
||||
//
|
||||
// Root logger (called by log.Info, log.Warn etc.) uses global zerolog.Logger instance
|
||||
// until ConfigureLogger called. Any child logger created with NewLogger will not
|
||||
// produce any events until logger configured, so any function which uses child
|
||||
// logger will come stuck because of root initialization synchronization.
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"sync"
|
||||
// needs for async file logging
|
||||
_ "code.cloudfoundry.org/go-diodes"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/diode"
|
||||
zl "github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var root = zl.Logger
|
||||
var (
|
||||
root = zl.Logger
|
||||
rootWg = sync.WaitGroup{}
|
||||
customOut io.WriteCloser
|
||||
customOutMu = sync.Mutex{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootWg.Add(1)
|
||||
}
|
||||
|
||||
// ConfigureLogger initializes root and all child loggers.
|
||||
// NOTE: this function MUST be called before any child log call
|
||||
// otherwise any goroutine, which uses logger will wait logger initialization
|
||||
func ConfigureLogger(output, level string, formatted, colored bool) (err error) {
|
||||
lvl := zerolog.WarnLevel
|
||||
output = strings.ToLower(output)
|
||||
@@ -27,11 +43,13 @@ func ConfigureLogger(output, level string, formatted, colored bool) (err error)
|
||||
case "stdout":
|
||||
w, stdAny = os.Stdout, true
|
||||
default:
|
||||
if w, err = os.OpenFile(output, os.O_APPEND|os.O_CREATE, 0600); err == nil {
|
||||
w = diode.NewWriter(w, 1000, 10*time.Millisecond, func(missed int) {
|
||||
if w, err = os.OpenFile(output, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o600); err == nil {
|
||||
customOutMu.Lock()
|
||||
defer customOutMu.Unlock()
|
||||
customOut = diode.NewWriter(w, 1000, 0, func(missed int) {
|
||||
zl.Warn().Int("count", missed).Msg("Logger dropped messages")
|
||||
})
|
||||
|
||||
w = customOut
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
@@ -52,29 +70,234 @@ func ConfigureLogger(output, level string, formatted, colored bool) (err error)
|
||||
}
|
||||
root = zerolog.New(w).With().Timestamp().Logger()
|
||||
zerolog.SetGlobalLevel(lvl)
|
||||
rootWg.Done()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Logger is the holder for zerolog.Logger which
|
||||
// waits until root logger initialized to prevent
|
||||
// mixed logging format and output
|
||||
type Logger struct {
|
||||
comp string
|
||||
zlOnce sync.Once
|
||||
zerolog.Logger
|
||||
}
|
||||
|
||||
func (l *Logger) init() {
|
||||
l.zlOnce.Do(func() {
|
||||
rootWg.Wait()
|
||||
l.Logger = root.With().Str("component", l.comp).Logger()
|
||||
})
|
||||
}
|
||||
|
||||
// ==== copied from zerolog ====
|
||||
|
||||
// Trace starts a new message with trace level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l *Logger) Trace() *zerolog.Event {
|
||||
l.init()
|
||||
return l.Logger.Trace()
|
||||
}
|
||||
|
||||
// Debug starts a new message with debug level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l *Logger) Debug() *zerolog.Event {
|
||||
l.init()
|
||||
return l.Logger.Debug()
|
||||
}
|
||||
|
||||
// Info starts a new message with info level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l *Logger) Info() *zerolog.Event {
|
||||
l.init()
|
||||
return l.Logger.Info()
|
||||
}
|
||||
|
||||
// Warn starts a new message with warn level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l *Logger) Warn() *zerolog.Event {
|
||||
l.init()
|
||||
return l.Logger.Warn()
|
||||
}
|
||||
|
||||
// Error starts a new message with error level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l *Logger) Error() *zerolog.Event {
|
||||
l.init()
|
||||
return l.Logger.Error()
|
||||
}
|
||||
|
||||
// Err starts a new message with error level with err as a field if not nil or
|
||||
// with info level if err is nil.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l *Logger) Err(err error) *zerolog.Event {
|
||||
l.init()
|
||||
return l.Logger.Err(err)
|
||||
}
|
||||
|
||||
// Fatal starts a new message with fatal level. The os.Exit(1) function
|
||||
// is called by the Msg method, which terminates the program immediately.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l *Logger) Fatal() *zerolog.Event {
|
||||
l.init()
|
||||
return l.Logger.Fatal()
|
||||
}
|
||||
|
||||
// Panic starts a new message with panic level. The panic() function
|
||||
// is called by the Msg method, which stops the ordinary flow of a goroutine.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l *Logger) Panic() *zerolog.Event {
|
||||
l.init()
|
||||
return l.Logger.Panic()
|
||||
}
|
||||
|
||||
// WithLevel starts a new message with level. Unlike Fatal and Panic
|
||||
// methods, WithLevel does not terminate the program or stop the ordinary
|
||||
// flow of a gourotine when used with their respective levels.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l *Logger) WithLevel(level zerolog.Level) *zerolog.Event {
|
||||
l.init()
|
||||
return l.Logger.WithLevel(level)
|
||||
}
|
||||
|
||||
// Log starts a new message with no level. Setting GlobalLevel to Disabled
|
||||
// will still disable events produced by this method.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l *Logger) Log() *zerolog.Event {
|
||||
l.init()
|
||||
return l.Logger.Log()
|
||||
}
|
||||
|
||||
// Print sends a log event using debug level and no extra field.
|
||||
// Arguments are handled in the manner of fmt.Print.
|
||||
func (l *Logger) Print(v ...interface{}) {
|
||||
l.init()
|
||||
l.Logger.Print(v...)
|
||||
}
|
||||
|
||||
// Printf sends a log event using debug level and no extra field.
|
||||
// Arguments are handled in the manner of fmt.Printf.
|
||||
func (l *Logger) Printf(format string, v ...interface{}) {
|
||||
l.init()
|
||||
l.Logger.Printf(format, v...)
|
||||
}
|
||||
|
||||
// Write implements the io.Writer interface. This is useful to set as a writer
|
||||
// for the standard library log.
|
||||
func (l *Logger) Write(p []byte) (n int, err error) {
|
||||
l.init()
|
||||
return l.Logger.Write(p)
|
||||
}
|
||||
|
||||
// Err starts a new message with error level with err as a field if not nil or
|
||||
// with info level if err is nil.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func Err(err error) *zerolog.Event {
|
||||
return root.Err(err)
|
||||
}
|
||||
|
||||
// Trace starts a new message with trace level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func Trace() *zerolog.Event {
|
||||
return root.Trace()
|
||||
}
|
||||
|
||||
// Debug starts a new message with debug level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func Debug() *zerolog.Event {
|
||||
return root.Debug()
|
||||
}
|
||||
|
||||
// Info starts a new message with info level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func Info() *zerolog.Event {
|
||||
return root.Info()
|
||||
}
|
||||
|
||||
// Warn starts a new message with warn level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func Warn() *zerolog.Event {
|
||||
return root.Warn()
|
||||
}
|
||||
|
||||
// Error starts a new message with error level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func Error() *zerolog.Event {
|
||||
return root.Error()
|
||||
}
|
||||
|
||||
// Fatal starts a new message with fatal level. The os.Exit(1) function
|
||||
// is called by the Msg method.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func Fatal() *zerolog.Event {
|
||||
return root.Fatal()
|
||||
}
|
||||
|
||||
func NewLogger(component string) zerolog.Logger {
|
||||
return root.With().Str("component", component).Logger()
|
||||
// Panic starts a new message with panic level. The message is also sent
|
||||
// to the panic function.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func Panic() *zerolog.Event {
|
||||
return root.Panic()
|
||||
}
|
||||
|
||||
// WithLevel starts a new message with level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func WithLevel(level zerolog.Level) *zerolog.Event {
|
||||
return root.WithLevel(level)
|
||||
}
|
||||
|
||||
// Log starts a new message with no level. Setting zerolog.GlobalLevel to
|
||||
// zerolog.Disabled will still disable events produced by this method.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func Log() *zerolog.Event {
|
||||
return root.Log()
|
||||
}
|
||||
|
||||
// Print sends a log event using debug level and no extra field.
|
||||
// Arguments are handled in the manner of fmt.Print.
|
||||
func Print(v ...interface{}) {
|
||||
root.Print(v...)
|
||||
}
|
||||
|
||||
// Printf sends a log event using debug level and no extra field.
|
||||
// Arguments are handled in the manner of fmt.Printf.
|
||||
func Printf(format string, v ...interface{}) {
|
||||
root.Printf(format, v...)
|
||||
}
|
||||
|
||||
// Close closes custom output writer if it configured
|
||||
func Close() {
|
||||
customOutMu.Lock()
|
||||
defer customOutMu.Unlock()
|
||||
if customOut != nil {
|
||||
_ = customOut.Close()
|
||||
customOut = nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewLogger creates child logger with specified component name
|
||||
// NOTE: root logger MUST be initialized with ConfigureLogger
|
||||
// before any logger call
|
||||
func NewLogger(component string) *Logger {
|
||||
return &Logger{comp: component}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,10 @@ import (
|
||||
"github.com/sot-tech/mochi/pkg/stop"
|
||||
)
|
||||
|
||||
var serverCounter = new(int32)
|
||||
var (
|
||||
logger = log.NewLogger("metrics")
|
||||
serverCounter = new(int32)
|
||||
)
|
||||
|
||||
// Enabled indicates that configured at least one metrics server
|
||||
func Enabled() bool {
|
||||
@@ -74,7 +77,7 @@ func NewServer(addr string) *Server {
|
||||
atomic.AddInt32(serverCounter, 1)
|
||||
defer atomic.AddInt32(serverCounter, -1)
|
||||
if err := s.srv.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
|
||||
log.Fatal("failed while serving prometheus", log.Err(err))
|
||||
logger.Error().Err(err).Msg("failed while serving prometheus")
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user