aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/go-hclog
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/go-hclog')
-rw-r--r--vendor/github.com/hashicorp/go-hclog/LICENSE21
-rw-r--r--vendor/github.com/hashicorp/go-hclog/README.md123
-rw-r--r--vendor/github.com/hashicorp/go-hclog/global.go34
-rw-r--r--vendor/github.com/hashicorp/go-hclog/int.go385
-rw-r--r--vendor/github.com/hashicorp/go-hclog/log.go138
-rw-r--r--vendor/github.com/hashicorp/go-hclog/stacktrace.go108
-rw-r--r--vendor/github.com/hashicorp/go-hclog/stdlog.go62
7 files changed, 871 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/go-hclog/LICENSE b/vendor/github.com/hashicorp/go-hclog/LICENSE
new file mode 100644
index 0000000..abaf1e4
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-hclog/LICENSE
@@ -0,0 +1,21 @@
1MIT License
2
3Copyright (c) 2017 HashiCorp
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
diff --git a/vendor/github.com/hashicorp/go-hclog/README.md b/vendor/github.com/hashicorp/go-hclog/README.md
new file mode 100644
index 0000000..614342b
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-hclog/README.md
@@ -0,0 +1,123 @@
1# go-hclog
2
3[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]
4
5[godocs]: https://godoc.org/github.com/hashicorp/go-hclog
6
7`go-hclog` is a package for Go that provides a simple key/value logging
8interface for use in development and production environments.
9
10It provides logging levels that provide decreased output based upon the
11desired amount of output, unlike the standard library `log` package.
12
13It does not provide `Printf` style logging, only key/value logging that is
14exposed as arguments to the logging functions for simplicity.
15
16It provides a human readable output mode for use in development as well as
17JSON output mode for production.
18
19## Stability Note
20
21While this library is fully open source and HashiCorp will be maintaining it
22(since we are and will be making extensive use of it), the API and output
23format is subject to minor changes as we fully bake and vet it in our projects.
24This notice will be removed once it's fully integrated into our major projects
25and no further changes are anticipated.
26
27## Installation and Docs
28
29Install using `go get github.com/hashicorp/go-hclog`.
30
31Full documentation is available at
32http://godoc.org/github.com/hashicorp/go-hclog
33
34## Usage
35
36### Use the global logger
37
38```go
39hclog.Default().Info("hello world")
40```
41
42```text
432017-07-05T16:15:55.167-0700 [INFO ] hello world
44```
45
46(Note timestamps are removed in future examples for brevity.)
47
48### Create a new logger
49
50```go
51appLogger := hclog.New(&hclog.LoggerOptions{
52 Name: "my-app",
53 Level: hclog.LevelFromString("DEBUG"),
54})
55```
56
57### Emit an Info level message with 2 key/value pairs
58
59```go
60input := "5.5"
61_, err := strconv.ParseInt(input, 10, 32)
62if err != nil {
63 appLogger.Info("Invalid input for ParseInt", "input", input, "error", err)
64}
65```
66
67```text
68... [INFO ] my-app: Invalid input for ParseInt: input=5.5 error="strconv.ParseInt: parsing "5.5": invalid syntax"
69```
70
71### Create a new Logger for a major subsystem
72
73```go
74subsystemLogger := appLogger.Named("transport")
75subsystemLogger.Info("we are transporting something")
76```
77
78```text
79... [INFO ] my-app.transport: we are transporting something
80```
81
82Notice that logs emitted by `subsystemLogger` contain `my-app.transport`,
83reflecting both the application and subsystem names.
84
85### Create a new Logger with fixed key/value pairs
86
87Using `With()` will include a specific key-value pair in all messages emitted
88by that logger.
89
90```go
91requestID := "5fb446b6-6eba-821d-df1b-cd7501b6a363"
92requestLogger := subsystemLogger.With("request", requestID)
93requestLogger.Info("we are transporting a request")
94```
95
96```text
97... [INFO ] my-app.transport: we are transporting a request: request=5fb446b6-6eba-821d-df1b-cd7501b6a363
98```
99
100This allows sub Loggers to be context specific without having to thread that
101into all the callers.
102
103### Use this with code that uses the standard library logger
104
105If you want to use the standard library's `log.Logger` interface you can wrap
106`hclog.Logger` by calling the `StandardLogger()` method. This allows you to use
107it with the familiar `Println()`, `Printf()`, etc. For example:
108
109```go
110stdLogger := appLogger.StandardLogger(&hclog.StandardLoggerOptions{
111 InferLevels: true,
112})
113// Printf() is provided by stdlib log.Logger interface, not hclog.Logger
114stdLogger.Printf("[DEBUG] %+v", stdLogger)
115```
116
117```text
118... [DEBUG] my-app: &{mu:{state:0 sema:0} prefix: flag:0 out:0xc42000a0a0 buf:[]}
119```
120
121Notice that if `appLogger` is initialized with the `INFO` log level _and_ you
122specify `InferLevels: true`, you will not see any output here. You must change
123`appLogger` to `DEBUG` to see output. See the docs for more information.
diff --git a/vendor/github.com/hashicorp/go-hclog/global.go b/vendor/github.com/hashicorp/go-hclog/global.go
new file mode 100644
index 0000000..55ce439
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-hclog/global.go
@@ -0,0 +1,34 @@
1package hclog
2
3import (
4 "sync"
5)
6
7var (
8 protect sync.Once
9 def Logger
10
11 // The options used to create the Default logger. These are
12 // read only when the Default logger is created, so set them
13 // as soon as the process starts.
14 DefaultOptions = &LoggerOptions{
15 Level: DefaultLevel,
16 Output: DefaultOutput,
17 }
18)
19
20// Return a logger that is held globally. This can be a good starting
21// place, and then you can use .With() and .Name() to create sub-loggers
22// to be used in more specific contexts.
23func Default() Logger {
24 protect.Do(func() {
25 def = New(DefaultOptions)
26 })
27
28 return def
29}
30
31// A short alias for Default()
32func L() Logger {
33 return Default()
34}
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}
diff --git a/vendor/github.com/hashicorp/go-hclog/log.go b/vendor/github.com/hashicorp/go-hclog/log.go
new file mode 100644
index 0000000..6bb16ba
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-hclog/log.go
@@ -0,0 +1,138 @@
1package hclog
2
3import (
4 "io"
5 "log"
6 "os"
7 "strings"
8)
9
10var (
11 DefaultOutput = os.Stderr
12 DefaultLevel = Info
13)
14
15type Level int
16
17const (
18 // This is a special level used to indicate that no level has been
19 // set and allow for a default to be used.
20 NoLevel Level = 0
21
22 // The most verbose level. Intended to be used for the tracing of actions
23 // in code, such as function enters/exits, etc.
24 Trace Level = 1
25
26 // For programmer lowlevel analysis.
27 Debug Level = 2
28
29 // For information about steady state operations.
30 Info Level = 3
31
32 // For information about rare but handled events.
33 Warn Level = 4
34
35 // For information about unrecoverable events.
36 Error Level = 5
37)
38
39// LevelFromString returns a Level type for the named log level, or "NoLevel" if
40// the level string is invalid. This facilitates setting the log level via
41// config or environment variable by name in a predictable way.
42func LevelFromString(levelStr string) Level {
43 // We don't care about case. Accept "INFO" or "info"
44 levelStr = strings.ToLower(strings.TrimSpace(levelStr))
45 switch levelStr {
46 case "trace":
47 return Trace
48 case "debug":
49 return Debug
50 case "info":
51 return Info
52 case "warn":
53 return Warn
54 case "error":
55 return Error
56 default:
57 return NoLevel
58 }
59}
60
61// The main Logger interface. All code should code against this interface only.
62type Logger interface {
63 // Args are alternating key, val pairs
64 // keys must be strings
65 // vals can be any type, but display is implementation specific
66 // Emit a message and key/value pairs at the TRACE level
67 Trace(msg string, args ...interface{})
68
69 // Emit a message and key/value pairs at the DEBUG level
70 Debug(msg string, args ...interface{})
71
72 // Emit a message and key/value pairs at the INFO level
73 Info(msg string, args ...interface{})
74
75 // Emit a message and key/value pairs at the WARN level
76 Warn(msg string, args ...interface{})
77
78 // Emit a message and key/value pairs at the ERROR level
79 Error(msg string, args ...interface{})
80
81 // Indicate if TRACE logs would be emitted. This and the other Is* guards
82 // are used to elide expensive logging code based on the current level.
83 IsTrace() bool
84
85 // Indicate if DEBUG logs would be emitted. This and the other Is* guards
86 IsDebug() bool
87
88 // Indicate if INFO logs would be emitted. This and the other Is* guards
89 IsInfo() bool
90
91 // Indicate if WARN logs would be emitted. This and the other Is* guards
92 IsWarn() bool
93
94 // Indicate if ERROR logs would be emitted. This and the other Is* guards
95 IsError() bool
96
97 // Creates a sublogger that will always have the given key/value pairs
98 With(args ...interface{}) Logger
99
100 // Create a logger that will prepend the name string on the front of all messages.
101 // If the logger already has a name, the new value will be appended to the current
102 // name. That way, a major subsystem can use this to decorate all it's own logs
103 // without losing context.
104 Named(name string) Logger
105
106 // Create a logger that will prepend the name string on the front of all messages.
107 // This sets the name of the logger to the value directly, unlike Named which honor
108 // the current name as well.
109 ResetNamed(name string) Logger
110
111 // Return a value that conforms to the stdlib log.Logger interface
112 StandardLogger(opts *StandardLoggerOptions) *log.Logger
113}
114
115type StandardLoggerOptions struct {
116 // Indicate that some minimal parsing should be done on strings to try
117 // and detect their level and re-emit them.
118 // This supports the strings like [ERROR], [ERR] [TRACE], [WARN], [INFO],
119 // [DEBUG] and strip it off before reapplying it.
120 InferLevels bool
121}
122
123type LoggerOptions struct {
124 // Name of the subsystem to prefix logs with
125 Name string
126
127 // The threshold for the logger. Anything less severe is supressed
128 Level Level
129
130 // Where to write the logs to. Defaults to os.Stdout if nil
131 Output io.Writer
132
133 // Control if the output should be in JSON.
134 JSONFormat bool
135
136 // Intclude file and line information in each log line
137 IncludeLocation bool
138}
diff --git a/vendor/github.com/hashicorp/go-hclog/stacktrace.go b/vendor/github.com/hashicorp/go-hclog/stacktrace.go
new file mode 100644
index 0000000..8af1a3b
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-hclog/stacktrace.go
@@ -0,0 +1,108 @@
1// Copyright (c) 2016 Uber Technologies, Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19// THE SOFTWARE.
20
21package hclog
22
23import (
24 "bytes"
25 "runtime"
26 "strconv"
27 "strings"
28 "sync"
29)
30
31var (
32 _stacktraceIgnorePrefixes = []string{
33 "runtime.goexit",
34 "runtime.main",
35 }
36 _stacktracePool = sync.Pool{
37 New: func() interface{} {
38 return newProgramCounters(64)
39 },
40 }
41)
42
43// A stacktrace gathered by a previous call to log.Stacktrace. If passed
44// to a logging function, the stacktrace will be appended.
45type CapturedStacktrace string
46
47// Gather a stacktrace of the current goroutine and return it to be passed
48// to a logging function.
49func Stacktrace() CapturedStacktrace {
50 return CapturedStacktrace(takeStacktrace())
51}
52
53func takeStacktrace() string {
54 programCounters := _stacktracePool.Get().(*programCounters)
55 defer _stacktracePool.Put(programCounters)
56
57 var buffer bytes.Buffer
58
59 for {
60 // Skip the call to runtime.Counters and takeStacktrace so that the
61 // program counters start at the caller of takeStacktrace.
62 n := runtime.Callers(2, programCounters.pcs)
63 if n < cap(programCounters.pcs) {
64 programCounters.pcs = programCounters.pcs[:n]
65 break
66 }
67 // Don't put the too-short counter slice back into the pool; this lets
68 // the pool adjust if we consistently take deep stacktraces.
69 programCounters = newProgramCounters(len(programCounters.pcs) * 2)
70 }
71
72 i := 0
73 frames := runtime.CallersFrames(programCounters.pcs)
74 for frame, more := frames.Next(); more; frame, more = frames.Next() {
75 if shouldIgnoreStacktraceFunction(frame.Function) {
76 continue
77 }
78 if i != 0 {
79 buffer.WriteByte('\n')
80 }
81 i++
82 buffer.WriteString(frame.Function)
83 buffer.WriteByte('\n')
84 buffer.WriteByte('\t')
85 buffer.WriteString(frame.File)
86 buffer.WriteByte(':')
87 buffer.WriteString(strconv.Itoa(int(frame.Line)))
88 }
89
90 return buffer.String()
91}
92
93func shouldIgnoreStacktraceFunction(function string) bool {
94 for _, prefix := range _stacktraceIgnorePrefixes {
95 if strings.HasPrefix(function, prefix) {
96 return true
97 }
98 }
99 return false
100}
101
102type programCounters struct {
103 pcs []uintptr
104}
105
106func newProgramCounters(size int) *programCounters {
107 return &programCounters{make([]uintptr, size)}
108}
diff --git a/vendor/github.com/hashicorp/go-hclog/stdlog.go b/vendor/github.com/hashicorp/go-hclog/stdlog.go
new file mode 100644
index 0000000..2bb927f
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-hclog/stdlog.go
@@ -0,0 +1,62 @@
1package hclog
2
3import (
4 "bytes"
5 "strings"
6)
7
8// Provides a io.Writer to shim the data out of *log.Logger
9// and back into our Logger. This is basically the only way to
10// build upon *log.Logger.
11type stdlogAdapter struct {
12 hl Logger
13 inferLevels bool
14}
15
16// Take the data, infer the levels if configured, and send it through
17// a regular Logger
18func (s *stdlogAdapter) Write(data []byte) (int, error) {
19 str := string(bytes.TrimRight(data, " \t\n"))
20
21 if s.inferLevels {
22 level, str := s.pickLevel(str)
23 switch level {
24 case Trace:
25 s.hl.Trace(str)
26 case Debug:
27 s.hl.Debug(str)
28 case Info:
29 s.hl.Info(str)
30 case Warn:
31 s.hl.Warn(str)
32 case Error:
33 s.hl.Error(str)
34 default:
35 s.hl.Info(str)
36 }
37 } else {
38 s.hl.Info(str)
39 }
40
41 return len(data), nil
42}
43
44// Detect, based on conventions, what log level this is
45func (s *stdlogAdapter) pickLevel(str string) (Level, string) {
46 switch {
47 case strings.HasPrefix(str, "[DEBUG]"):
48 return Debug, strings.TrimSpace(str[7:])
49 case strings.HasPrefix(str, "[TRACE]"):
50 return Trace, strings.TrimSpace(str[7:])
51 case strings.HasPrefix(str, "[INFO]"):
52 return Info, strings.TrimSpace(str[6:])
53 case strings.HasPrefix(str, "[WARN]"):
54 return Warn, strings.TrimSpace(str[7:])
55 case strings.HasPrefix(str, "[ERROR]"):
56 return Error, strings.TrimSpace(str[7:])
57 case strings.HasPrefix(str, "[ERR]"):
58 return Error, strings.TrimSpace(str[5:])
59 default:
60 return Info, str
61 }
62}