aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/go-hclog/int.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/go-hclog/int.go')
-rw-r--r--vendor/github.com/hashicorp/go-hclog/int.go385
1 files changed, 385 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/go-hclog/int.go b/vendor/github.com/hashicorp/go-hclog/int.go
new file mode 100644
index 0000000..9f90c28
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-hclog/int.go
@@ -0,0 +1,385 @@
1package hclog
2
3import (
4 "bufio"
5 "encoding/json"
6 "fmt"
7 "log"
8 "os"
9 "runtime"
10 "strconv"
11 "strings"
12 "sync"
13 "time"
14)
15
16var (
17 _levelToBracket = map[Level]string{
18 Debug: "[DEBUG]",
19 Trace: "[TRACE]",
20 Info: "[INFO ]",
21 Warn: "[WARN ]",
22 Error: "[ERROR]",
23 }
24)
25
26// Given the options (nil for defaults), create a new Logger
27func New(opts *LoggerOptions) Logger {
28 if opts == nil {
29 opts = &LoggerOptions{}
30 }
31
32 output := opts.Output
33 if output == nil {
34 output = os.Stderr
35 }
36
37 level := opts.Level
38 if level == NoLevel {
39 level = DefaultLevel
40 }
41
42 return &intLogger{
43 m: new(sync.Mutex),
44 json: opts.JSONFormat,
45 caller: opts.IncludeLocation,
46 name: opts.Name,
47 w: bufio.NewWriter(output),
48 level: level,
49 }
50}
51
52// The internal logger implementation. Internal in that it is defined entirely
53// by this package.
54type intLogger struct {
55 json bool
56 caller bool
57 name string
58
59 // this is a pointer so that it's shared by any derived loggers, since
60 // those derived loggers share the bufio.Writer as well.
61 m *sync.Mutex
62 w *bufio.Writer
63 level Level
64
65 implied []interface{}
66}
67
68// Make sure that intLogger is a Logger
69var _ Logger = &intLogger{}
70
71// The time format to use for logging. This is a version of RFC3339 that
72// contains millisecond precision
73const TimeFormat = "2006-01-02T15:04:05.000Z0700"
74
75// Log a message and a set of key/value pairs if the given level is at
76// or more severe that the threshold configured in the Logger.
77func (z *intLogger) Log(level Level, msg string, args ...interface{}) {
78 if level < z.level {
79 return
80 }
81
82 t := time.Now()
83
84 z.m.Lock()
85 defer z.m.Unlock()
86
87 if z.json {
88 z.logJson(t, level, msg, args...)
89 } else {
90 z.log(t, level, msg, args...)
91 }
92
93 z.w.Flush()
94}
95
96// Cleanup a path by returning the last 2 segments of the path only.
97func trimCallerPath(path string) string {
98 // lovely borrowed from zap
99 // nb. To make sure we trim the path correctly on Windows too, we
100 // counter-intuitively need to use '/' and *not* os.PathSeparator here,
101 // because the path given originates from Go stdlib, specifically
102 // runtime.Caller() which (as of Mar/17) returns forward slashes even on
103 // Windows.
104 //
105 // See https://github.com/golang/go/issues/3335
106 // and https://github.com/golang/go/issues/18151
107 //
108 // for discussion on the issue on Go side.
109 //
110
111 // Find the last separator.
112 //
113 idx := strings.LastIndexByte(path, '/')
114 if idx == -1 {
115 return path
116 }
117
118 // Find the penultimate separator.
119 idx = strings.LastIndexByte(path[:idx], '/')
120 if idx == -1 {
121 return path
122 }
123
124 return path[idx+1:]
125}
126
127// Non-JSON logging format function
128func (z *intLogger) log(t time.Time, level Level, msg string, args ...interface{}) {
129 z.w.WriteString(t.Format(TimeFormat))
130 z.w.WriteByte(' ')
131
132 s, ok := _levelToBracket[level]
133 if ok {
134 z.w.WriteString(s)
135 } else {
136 z.w.WriteString("[UNKN ]")
137 }
138
139 if z.caller {
140 if _, file, line, ok := runtime.Caller(3); ok {
141 z.w.WriteByte(' ')
142 z.w.WriteString(trimCallerPath(file))
143 z.w.WriteByte(':')
144 z.w.WriteString(strconv.Itoa(line))
145 z.w.WriteByte(':')
146 }
147 }
148
149 z.w.WriteByte(' ')
150
151 if z.name != "" {
152 z.w.WriteString(z.name)
153 z.w.WriteString(": ")
154 }
155
156 z.w.WriteString(msg)
157
158 args = append(z.implied, args...)
159
160 var stacktrace CapturedStacktrace
161
162 if args != nil && len(args) > 0 {
163 if len(args)%2 != 0 {
164 cs, ok := args[len(args)-1].(CapturedStacktrace)
165 if ok {
166 args = args[:len(args)-1]
167 stacktrace = cs
168 } else {
169 args = append(args, "<unknown>")
170 }
171 }
172
173 z.w.WriteByte(':')
174
175 FOR:
176 for i := 0; i < len(args); i = i + 2 {
177 var val string
178
179 switch st := args[i+1].(type) {
180 case string:
181 val = st
182 case int:
183 val = strconv.FormatInt(int64(st), 10)
184 case int64:
185 val = strconv.FormatInt(int64(st), 10)
186 case int32:
187 val = strconv.FormatInt(int64(st), 10)
188 case int16:
189 val = strconv.FormatInt(int64(st), 10)
190 case int8:
191 val = strconv.FormatInt(int64(st), 10)
192 case uint:
193 val = strconv.FormatUint(uint64(st), 10)
194 case uint64:
195 val = strconv.FormatUint(uint64(st), 10)
196 case uint32:
197 val = strconv.FormatUint(uint64(st), 10)
198 case uint16:
199 val = strconv.FormatUint(uint64(st), 10)
200 case uint8:
201 val = strconv.FormatUint(uint64(st), 10)
202 case CapturedStacktrace:
203 stacktrace = st
204 continue FOR
205 default:
206 val = fmt.Sprintf("%v", st)
207 }
208
209 z.w.WriteByte(' ')
210 z.w.WriteString(args[i].(string))
211 z.w.WriteByte('=')
212
213 if strings.ContainsAny(val, " \t\n\r") {
214 z.w.WriteByte('"')
215 z.w.WriteString(val)
216 z.w.WriteByte('"')
217 } else {
218 z.w.WriteString(val)
219 }
220 }
221 }
222
223 z.w.WriteString("\n")
224
225 if stacktrace != "" {
226 z.w.WriteString(string(stacktrace))
227 }
228}
229
230// JSON logging function
231func (z *intLogger) logJson(t time.Time, level Level, msg string, args ...interface{}) {
232 vals := map[string]interface{}{
233 "@message": msg,
234 "@timestamp": t.Format("2006-01-02T15:04:05.000000Z07:00"),
235 }
236
237 var levelStr string
238 switch level {
239 case Error:
240 levelStr = "error"
241 case Warn:
242 levelStr = "warn"
243 case Info:
244 levelStr = "info"
245 case Debug:
246 levelStr = "debug"
247 case Trace:
248 levelStr = "trace"
249 default:
250 levelStr = "all"
251 }
252
253 vals["@level"] = levelStr
254
255 if z.name != "" {
256 vals["@module"] = z.name
257 }
258
259 if z.caller {
260 if _, file, line, ok := runtime.Caller(3); ok {
261 vals["@caller"] = fmt.Sprintf("%s:%d", file, line)
262 }
263 }
264
265 if args != nil && len(args) > 0 {
266 if len(args)%2 != 0 {
267 cs, ok := args[len(args)-1].(CapturedStacktrace)
268 if ok {
269 args = args[:len(args)-1]
270 vals["stacktrace"] = cs
271 } else {
272 args = append(args, "<unknown>")
273 }
274 }
275
276 for i := 0; i < len(args); i = i + 2 {
277 if _, ok := args[i].(string); !ok {
278 // As this is the logging function not much we can do here
279 // without injecting into logs...
280 continue
281 }
282 vals[args[i].(string)] = args[i+1]
283 }
284 }
285
286 err := json.NewEncoder(z.w).Encode(vals)
287 if err != nil {
288 panic(err)
289 }
290}
291
292// Emit the message and args at DEBUG level
293func (z *intLogger) Debug(msg string, args ...interface{}) {
294 z.Log(Debug, msg, args...)
295}
296
297// Emit the message and args at TRACE level
298func (z *intLogger) Trace(msg string, args ...interface{}) {
299 z.Log(Trace, msg, args...)
300}
301
302// Emit the message and args at INFO level
303func (z *intLogger) Info(msg string, args ...interface{}) {
304 z.Log(Info, msg, args...)
305}
306
307// Emit the message and args at WARN level
308func (z *intLogger) Warn(msg string, args ...interface{}) {
309 z.Log(Warn, msg, args...)
310}
311
312// Emit the message and args at ERROR level
313func (z *intLogger) Error(msg string, args ...interface{}) {
314 z.Log(Error, msg, args...)
315}
316
317// Indicate that the logger would emit TRACE level logs
318func (z *intLogger) IsTrace() bool {
319 return z.level == Trace
320}
321
322// Indicate that the logger would emit DEBUG level logs
323func (z *intLogger) IsDebug() bool {
324 return z.level <= Debug
325}
326
327// Indicate that the logger would emit INFO level logs
328func (z *intLogger) IsInfo() bool {
329 return z.level <= Info
330}
331
332// Indicate that the logger would emit WARN level logs
333func (z *intLogger) IsWarn() bool {
334 return z.level <= Warn
335}
336
337// Indicate that the logger would emit ERROR level logs
338func (z *intLogger) IsError() bool {
339 return z.level <= Error
340}
341
342// Return a sub-Logger for which every emitted log message will contain
343// the given key/value pairs. This is used to create a context specific
344// Logger.
345func (z *intLogger) With(args ...interface{}) Logger {
346 var nz intLogger = *z
347
348 nz.implied = append(nz.implied, args...)
349
350 return &nz
351}
352
353// Create a new sub-Logger that a name decending from the current name.
354// This is used to create a subsystem specific Logger.
355func (z *intLogger) Named(name string) Logger {
356 var nz intLogger = *z
357
358 if nz.name != "" {
359 nz.name = nz.name + "." + name
360 }
361
362 return &nz
363}
364
365// Create a new sub-Logger with an explicit name. This ignores the current
366// name. This is used to create a standalone logger that doesn't fall
367// within the normal hierarchy.
368func (z *intLogger) ResetNamed(name string) Logger {
369 var nz intLogger = *z
370
371 nz.name = name
372
373 return &nz
374}
375
376// Create a *log.Logger that will send it's data through this Logger. This
377// allows packages that expect to be using the standard library log to actually
378// use this logger.
379func (z *intLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger {
380 if opts == nil {
381 opts = &StandardLoggerOptions{}
382 }
383
384 return log.New(&stdlogAdapter{z, opts.InferLevels}, "", 0)
385}