package logger import ( "context" "io" "log/slog" "os" "reflect" "time" "go.unistack.org/micro/v4/options" rutil "go.unistack.org/micro/v4/util/reflect" ) // Options holds logger options type Options struct { // Out holds the output writer Out io.Writer // Context holds exernal options Context context.Context // TimeFunc used to obtain current time TimeFunc func() time.Time // TimeKey is the key used for the time of the log call TimeKey string // Name holds the logger name Name string // LevelKey is the key used for the level of the log call LevelKey string // MessageKey is the key used for the message of the log call MessageKey string // ErrorKey is the key used for the error info ErrorKey string // SourceKey is the key used for the source file and line of the log call SourceKey string // StacktraceKey is the key used for the stacktrace StacktraceKey string // Attrs holds additional attributes Attrs []interface{} // ContextAttrFuncs contains funcs that executed before log func on context ContextAttrFuncs []ContextAttrFunc // CallerSkipCount number of frmaes to skip CallerSkipCount int // The logging level the logger should log Level Level // AddStacktrace controls writing of stacktaces on error AddStacktrace bool // AddSource enabled writing source file and position in log AddSource bool } // NewOptions creates new options struct func NewOptions(opts ...options.Option) Options { options := Options{ Level: DefaultLevel, Attrs: make([]interface{}, 0, 6), Out: os.Stderr, CallerSkipCount: DefaultCallerSkipCount, Context: context.Background(), ContextAttrFuncs: DefaultContextAttrFuncs, AddSource: true, TimeFunc: time.Now, } _ = WithMicroKeys()(&options) for _, o := range opts { _ = o(&options) } return options } // WithContextAttrFuncs appends default funcs for the context arrts filler func WithContextAttrFuncs(fncs ...ContextAttrFunc) options.Option { return func(src interface{}) error { v, err := options.Get(src, ".ContextAttrFuncs") if err != nil { return err } else if rutil.IsZero(v) { v = reflect.MakeSlice(reflect.TypeOf(v), 0, len(fncs)).Interface() } cv := reflect.ValueOf(v) for _, l := range fncs { cv = reflect.Append(cv, reflect.ValueOf(l)) } return options.Set(src, cv.Interface(), ".ContextAttrFuncs") } } // WithAttrs set default fields for the logger func WithAttrs(attrs ...interface{}) options.Option { return func(src interface{}) error { return options.Set(src, attrs, ".Attrs") } } // WithLevel set default level for the logger func WithLevel(lvl Level) options.Option { return func(src interface{}) error { return options.Set(src, lvl, ".Level") } } // WithOutput set default output writer for the logger func WithOutput(out io.Writer) options.Option { return func(src interface{}) error { return options.Set(src, out, ".Out") } } // WithCallerSkipCount set frame count to skip func WithCallerSkipCount(c int) options.Option { return func(src interface{}) error { return options.Set(src, c, ".CallerSkipCount") } } func WithZapKeys() options.Option { return func(src interface{}) error { var err error if err = options.Set(src, "@timestamp", ".TimeKey"); err != nil { return err } if err = options.Set(src, "level", ".LevelKey"); err != nil { return err } if err = options.Set(src, "msg", ".MessageKey"); err != nil { return err } if err = options.Set(src, "caller", ".SourceKey"); err != nil { return err } if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil { return err } if err = options.Set(src, "error", ".ErrorKey"); err != nil { return err } return nil } } func WithZerologKeys() options.Option { return func(src interface{}) error { var err error if err = options.Set(src, "time", ".TimeKey"); err != nil { return err } if err = options.Set(src, "level", ".LevelKey"); err != nil { return err } if err = options.Set(src, "message", ".MessageKey"); err != nil { return err } if err = options.Set(src, "caller", ".SourceKey"); err != nil { return err } if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil { return err } if err = options.Set(src, "error", ".ErrorKey"); err != nil { return err } return nil } } func WithSlogKeys() options.Option { return func(src interface{}) error { var err error if err = options.Set(src, slog.TimeKey, ".TimeKey"); err != nil { return err } if err = options.Set(src, slog.LevelKey, ".LevelKey"); err != nil { return err } if err = options.Set(src, slog.MessageKey, ".MessageKey"); err != nil { return err } if err = options.Set(src, slog.SourceKey, ".SourceKey"); err != nil { return err } if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil { return err } if err = options.Set(src, "error", ".ErrorKey"); err != nil { return err } return nil } } func WithMicroKeys() options.Option { return func(src interface{}) error { var err error if err = options.Set(src, "timestamp", ".TimeKey"); err != nil { return err } if err = options.Set(src, "level", ".LevelKey"); err != nil { return err } if err = options.Set(src, "msg", ".MessageKey"); err != nil { return err } if err = options.Set(src, "caller", ".SourceKey"); err != nil { return err } if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil { return err } if err = options.Set(src, "error", ".ErrorKey"); err != nil { return err } return nil } } // WithAddCallerSkipCount add skip count for copy logger func WithAddCallerSkipCount(n int) options.Option { return func(src interface{}) error { c, err := options.Get(src, ".CallerSkipCount") if err != nil { return err } if err = options.Set(src, c.(int)+n, ".CallerSkipCount"); err != nil { return err } return nil } } // WithAddStacktrace controls writing stacktrace on error func WithAddStacktrace(v bool) options.Option { return func(src interface{}) error { return options.Set(src, v, ".AddStacktrace") } } // WitAddSource controls writing source file and pos in log func WithAddSource(v bool) options.Option { return func(src interface{}) error { return options.Set(src, v, ".AddSource") } }