package logrusx import ( "os" "github.com/sirupsen/logrus" gelf "github.com/seatgeek/logrus-gelf-formatter" "github.com/ory/x/stringsx" ) type ( options struct { l *logrus.Logger level *logrus.Level formatter logrus.Formatter format string reportCaller bool exitFunc func(int) leakSensitive bool hooks []logrus.Hook c configurator } Option func(*options) nullConfigurator struct{} configurator interface { Bool(key string) bool String(key string) string } ) func newLogger(parent *logrus.Logger, o *options) *logrus.Logger { l := parent if l == nil { l = logrus.New() } if o.exitFunc != nil { l.ExitFunc = o.exitFunc } setLevel(l, o) setFormatter(l, o) for _, hook := range o.hooks { l.AddHook(hook) } l.ReportCaller = o.reportCaller || l.IsLevelEnabled(logrus.TraceLevel) return l } func setLevel(l *logrus.Logger, o *options) { if o.level != nil { l.Level = *o.level } else { var err error l.Level, err = logrus.ParseLevel(stringsx.Coalesce( o.c.String("log.level"), os.Getenv("LOG_LEVEL"))) if err != nil { l.Level = logrus.InfoLevel } } } func setFormatter(l *logrus.Logger, o *options) { if o.formatter != nil { l.Formatter = o.formatter } else { switch stringsx.Coalesce(o.format, o.c.String("log.format"), os.Getenv("LOG_FORMAT")) { case "json": l.Formatter = &logrus.JSONFormatter{PrettyPrint: false} case "json_pretty": l.Formatter = &logrus.JSONFormatter{PrettyPrint: true} case "gelf": l.Formatter = new(gelf.GelfFormatter) default: l.Formatter = &logrus.TextFormatter{ DisableQuote: true, DisableTimestamp: false, FullTimestamp: true, } } } } func ForceLevel(level logrus.Level) Option { return func(o *options) { o.level = &level } } func ForceFormatter(formatter logrus.Formatter) Option { return func(o *options) { o.formatter = formatter } } func WithConfigurator(c configurator) Option { return func(o *options) { o.c = c } } func ForceFormat(format string) Option { return func(o *options) { o.format = format } } func WithHook(hook logrus.Hook) Option { return func(o *options) { o.hooks = append(o.hooks, hook) } } func WithExitFunc(exitFunc func(int)) Option { return func(o *options) { o.exitFunc = exitFunc } } func ReportCaller(reportCaller bool) Option { return func(o *options) { o.reportCaller = reportCaller } } func UseLogger(l *logrus.Logger) Option { return func(o *options) { o.l = l } } func LeakSensitive() Option { return func(o *options) { o.leakSensitive = true } } func (c *nullConfigurator) Bool(_ string) bool { return false } func (c *nullConfigurator) String(_ string) string { return "" } func newOptions(opts []Option) *options { o := new(options) o.c = new(nullConfigurator) for _, f := range opts { f(o) } return o } // New creates a new logger with all the important fields set. func New(name string, version string, opts ...Option) *Logger { o := newOptions(opts) return &Logger{ opts: opts, name: name, version: version, leakSensitive: o.leakSensitive || o.c.Bool("log.leak_sensitive_values"), Entry: newLogger(o.l, o).WithFields(logrus.Fields{ "audience": "application", "service_name": name, "service_version": version}), } } func NewAudit(name string, version string, opts ...Option) *Logger { return New(name, version, opts...).WithField("audience", "audit") } func (l *Logger) UseConfig(c configurator) { l.leakSensitive = l.leakSensitive || c.Bool("log.leak_sensitive_values") o := newOptions(append(l.opts, WithConfigurator(c))) setLevel(l.Entry.Logger, o) setFormatter(l.Entry.Logger, o) }