1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
package log
// Wrapper package around logrus whose main purpose is to support having
// different output streams for error and non-error messages.
//
// Does not wrap every method of logrus package. If you need direct access,
// use log.Log() to get the actual logrus logger object.
//
// It might seem redundant, but we really want the different output streams.
import (
"fmt"
"io"
"os"
"strings"
"sync"
"github.com/sirupsen/logrus"
)
// Internal Logger object
var logger *logrus.Logger
// LogContext contains a structured context for logging
type LogContext struct {
fields logrus.Fields
normalOut io.Writer
errorOut io.Writer
mutex sync.RWMutex
}
// NewContext returns a LogContext with default settings
func NewContext() *LogContext {
var logctx LogContext
logctx.fields = make(logrus.Fields)
logctx.normalOut = os.Stdout
logctx.errorOut = os.Stderr
return &logctx
}
// SetLogLevel sets the log level to use for the logger
func SetLogLevel(logLevel string) error {
switch strings.ToLower(logLevel) {
case "trace":
logger.SetLevel(logrus.TraceLevel)
case "debug":
logger.SetLevel(logrus.DebugLevel)
case "info":
logger.SetLevel(logrus.InfoLevel)
case "warn":
logger.SetLevel(logrus.WarnLevel)
case "error":
logger.SetLevel(logrus.ErrorLevel)
default:
return fmt.Errorf("invalid loglevel: %s", logLevel)
}
return nil
}
// WithContext is an alias for NewContext
func WithContext() *LogContext {
return NewContext()
}
// AddField adds a structured field to logctx
func (logctx *LogContext) AddField(key string, value interface{}) *LogContext {
logctx.mutex.Lock()
logctx.fields[key] = value
logctx.mutex.Unlock()
return logctx
}
// Log retrieves the native logger interface. Use with care.
func Log() *logrus.Logger {
return logger
}
// Tracef logs a debug message for logctx to stdout
func (logctx *LogContext) Tracef(format string, args ...interface{}) {
logger.SetOutput(logctx.normalOut)
if len(logctx.fields) > 0 {
logger.WithFields(logctx.fields).Tracef(format, args...)
} else {
logger.Tracef(format, args...)
}
}
// Debugf logs a debug message for logctx to stdout
func (logctx *LogContext) Debugf(format string, args ...interface{}) {
logger.SetOutput(logctx.normalOut)
if len(logctx.fields) > 0 {
logger.WithFields(logctx.fields).Debugf(format, args...)
} else {
logger.Debugf(format, args...)
}
}
// Infof logs an informational message for logctx to stdout
func (logctx *LogContext) Infof(format string, args ...interface{}) {
logger.SetOutput(logctx.normalOut)
if len(logctx.fields) > 0 {
logger.WithFields(logctx.fields).Infof(format, args...)
} else {
logger.Infof(format, args...)
}
}
// Warnf logs a warning message for logctx to stdout
func (logctx *LogContext) Warnf(format string, args ...interface{}) {
logger.SetOutput(logctx.normalOut)
if len(logctx.fields) > 0 {
logger.WithFields(logctx.fields).Warnf(format, args...)
} else {
logger.Warnf(format, args...)
}
}
// Errorf logs a non-fatal error message for logctx to stdout
func (logctx *LogContext) Errorf(format string, args ...interface{}) {
logger.SetOutput(logctx.errorOut)
if len(logctx.fields) > 0 {
logger.WithFields(logctx.fields).Errorf(format, args...)
} else {
logger.Errorf(format, args...)
}
}
// Fatalf logs a fatal error message for logctx to stdout
func (logctx *LogContext) Fatalf(format string, args ...interface{}) {
logger.SetOutput(logctx.errorOut)
if len(logctx.fields) > 0 {
logger.WithFields(logctx.fields).Fatalf(format, args...)
} else {
logger.Fatalf(format, args...)
}
}
// Tracef logs a warning message without context to stdout
func Tracef(format string, args ...interface{}) {
logCtx := NewContext()
logCtx.Tracef(format, args...)
}
// Debugf logs a warning message without context to stdout
func Debugf(format string, args ...interface{}) {
logCtx := NewContext()
logCtx.Debugf(format, args...)
}
// Infof logs a warning message without context to stdout
func Infof(format string, args ...interface{}) {
logCtx := NewContext()
logCtx.Infof(format, args...)
}
// Warnf logs a warning message without context to stdout
func Warnf(format string, args ...interface{}) {
logCtx := NewContext()
logCtx.Warnf(format, args...)
}
// Errorf logs an error message without context to stderr
func Errorf(format string, args ...interface{}) {
logCtx := NewContext()
logCtx.Errorf(format, args...)
}
// Fatalf logs a non-recoverable error message without context to stderr
func Fatalf(format string, args ...interface{}) {
logCtx := NewContext()
logCtx.Fatalf(format, args...)
}
func disableLogColors() bool {
return strings.ToLower(os.Getenv("ENABLE_LOG_COLORS")) == "false"
}
// Initializes the logging subsystem with default values
func init() {
logger = logrus.New()
logger.SetFormatter(&logrus.TextFormatter{DisableColors: disableLogColors()})
logger.SetLevel(logrus.DebugLevel)
}
|