...
1 package logrusx
2
3 import (
4 "os"
5
6 "github.com/sirupsen/logrus"
7
8 gelf "github.com/seatgeek/logrus-gelf-formatter"
9
10 "github.com/ory/x/stringsx"
11 )
12
13 type (
14 options struct {
15 l *logrus.Logger
16 level *logrus.Level
17 formatter logrus.Formatter
18 format string
19 reportCaller bool
20 exitFunc func(int)
21 leakSensitive bool
22 hooks []logrus.Hook
23 c configurator
24 }
25 Option func(*options)
26 nullConfigurator struct{}
27 configurator interface {
28 Bool(key string) bool
29 String(key string) string
30 }
31 )
32
33 func newLogger(parent *logrus.Logger, o *options) *logrus.Logger {
34 l := parent
35 if l == nil {
36 l = logrus.New()
37 }
38
39 if o.exitFunc != nil {
40 l.ExitFunc = o.exitFunc
41 }
42
43 setLevel(l, o)
44 setFormatter(l, o)
45
46 for _, hook := range o.hooks {
47 l.AddHook(hook)
48 }
49
50 l.ReportCaller = o.reportCaller || l.IsLevelEnabled(logrus.TraceLevel)
51 return l
52 }
53
54 func setLevel(l *logrus.Logger, o *options) {
55 if o.level != nil {
56 l.Level = *o.level
57 } else {
58 var err error
59 l.Level, err = logrus.ParseLevel(stringsx.Coalesce(
60 o.c.String("log.level"),
61 os.Getenv("LOG_LEVEL")))
62 if err != nil {
63 l.Level = logrus.InfoLevel
64 }
65 }
66 }
67
68 func setFormatter(l *logrus.Logger, o *options) {
69 if o.formatter != nil {
70 l.Formatter = o.formatter
71 } else {
72 switch stringsx.Coalesce(o.format, o.c.String("log.format"), os.Getenv("LOG_FORMAT")) {
73 case "json":
74 l.Formatter = &logrus.JSONFormatter{PrettyPrint: false}
75 case "json_pretty":
76 l.Formatter = &logrus.JSONFormatter{PrettyPrint: true}
77 case "gelf":
78 l.Formatter = new(gelf.GelfFormatter)
79 default:
80 l.Formatter = &logrus.TextFormatter{
81 DisableQuote: true,
82 DisableTimestamp: false,
83 FullTimestamp: true,
84 }
85 }
86 }
87 }
88
89 func ForceLevel(level logrus.Level) Option {
90 return func(o *options) {
91 o.level = &level
92 }
93 }
94
95 func ForceFormatter(formatter logrus.Formatter) Option {
96 return func(o *options) {
97 o.formatter = formatter
98 }
99 }
100
101 func WithConfigurator(c configurator) Option {
102 return func(o *options) {
103 o.c = c
104 }
105 }
106
107 func ForceFormat(format string) Option {
108 return func(o *options) {
109 o.format = format
110 }
111 }
112
113 func WithHook(hook logrus.Hook) Option {
114 return func(o *options) {
115 o.hooks = append(o.hooks, hook)
116 }
117 }
118
119 func WithExitFunc(exitFunc func(int)) Option {
120 return func(o *options) {
121 o.exitFunc = exitFunc
122 }
123 }
124
125 func ReportCaller(reportCaller bool) Option {
126 return func(o *options) {
127 o.reportCaller = reportCaller
128 }
129 }
130
131 func UseLogger(l *logrus.Logger) Option {
132 return func(o *options) {
133 o.l = l
134 }
135 }
136
137 func LeakSensitive() Option {
138 return func(o *options) {
139 o.leakSensitive = true
140 }
141 }
142
143 func (c *nullConfigurator) Bool(_ string) bool {
144 return false
145 }
146
147 func (c *nullConfigurator) String(_ string) string {
148 return ""
149 }
150
151 func newOptions(opts []Option) *options {
152 o := new(options)
153 o.c = new(nullConfigurator)
154 for _, f := range opts {
155 f(o)
156 }
157 return o
158 }
159
160
161 func New(name string, version string, opts ...Option) *Logger {
162 o := newOptions(opts)
163 return &Logger{
164 opts: opts,
165 name: name,
166 version: version,
167 leakSensitive: o.leakSensitive || o.c.Bool("log.leak_sensitive_values"),
168 Entry: newLogger(o.l, o).WithFields(logrus.Fields{
169 "audience": "application", "service_name": name, "service_version": version}),
170 }
171 }
172
173 func NewAudit(name string, version string, opts ...Option) *Logger {
174 return New(name, version, opts...).WithField("audience", "audit")
175 }
176
177 func (l *Logger) UseConfig(c configurator) {
178 l.leakSensitive = l.leakSensitive || c.Bool("log.leak_sensitive_values")
179 o := newOptions(append(l.opts, WithConfigurator(c)))
180 setLevel(l.Entry.Logger, o)
181 setFormatter(l.Entry.Logger, o)
182 }
183
View as plain text