vendor: update github.com/hashicorp/go-hclog

This commit is contained in:
Nick Ethier 2018-07-26 22:26:04 -04:00
parent 8abf4f9e25
commit bba732b2c3
No known key found for this signature in database
GPG key ID: 07C1A3ECED90D24A
5 changed files with 177 additions and 25 deletions

View file

@ -10,8 +10,7 @@ interface for use in development and production environments.
It provides logging levels that provide decreased output based upon the It provides logging levels that provide decreased output based upon the
desired amount of output, unlike the standard library `log` package. desired amount of output, unlike the standard library `log` package.
It does not provide `Printf` style logging, only key/value logging that is It provides `Printf` style logging of values via `hclog.Fmt()`.
exposed as arguments to the logging functions for simplicity.
It provides a human readable output mode for use in development as well as It provides a human readable output mode for use in development as well as
JSON output mode for production. JSON output mode for production.
@ -100,6 +99,17 @@ requestLogger.Info("we are transporting a request")
This allows sub Loggers to be context specific without having to thread that This allows sub Loggers to be context specific without having to thread that
into all the callers. into all the callers.
### Using `hclog.Fmt()`
```go
var int totalBandwidth = 200
appLogger.Info("total bandwidth exceeded", "bandwidth", hclog.Fmt("%d GB/s", totalBandwidth))
```
```text
... [INFO ] my-app: total bandwidth exceeded: bandwidth="200 GB/s"
```
### Use this with code that uses the standard library logger ### Use this with code that uses the standard library logger
If you want to use the standard library's `log.Logger` interface you can wrap If you want to use the standard library's `log.Logger` interface you can wrap

View file

@ -2,14 +2,17 @@ package hclog
import ( import (
"bufio" "bufio"
"encoding"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log" "log"
"os" "os"
"runtime" "runtime"
"sort"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
) )
@ -39,28 +42,40 @@ func New(opts *LoggerOptions) Logger {
level = DefaultLevel level = DefaultLevel
} }
return &intLogger{ mtx := opts.Mutex
m: new(sync.Mutex), if mtx == nil {
json: opts.JSONFormat, mtx = new(sync.Mutex)
caller: opts.IncludeLocation,
name: opts.Name,
w: bufio.NewWriter(output),
level: level,
} }
ret := &intLogger{
m: mtx,
json: opts.JSONFormat,
caller: opts.IncludeLocation,
name: opts.Name,
timeFormat: TimeFormat,
w: bufio.NewWriter(output),
level: new(int32),
}
if opts.TimeFormat != "" {
ret.timeFormat = opts.TimeFormat
}
atomic.StoreInt32(ret.level, int32(level))
return ret
} }
// The internal logger implementation. Internal in that it is defined entirely // The internal logger implementation. Internal in that it is defined entirely
// by this package. // by this package.
type intLogger struct { type intLogger struct {
json bool json bool
caller bool caller bool
name string name string
timeFormat string
// this is a pointer so that it's shared by any derived loggers, since // this is a pointer so that it's shared by any derived loggers, since
// those derived loggers share the bufio.Writer as well. // those derived loggers share the bufio.Writer as well.
m *sync.Mutex m *sync.Mutex
w *bufio.Writer w *bufio.Writer
level Level level *int32
implied []interface{} implied []interface{}
} }
@ -75,7 +90,7 @@ const TimeFormat = "2006-01-02T15:04:05.000Z0700"
// Log a message and a set of key/value pairs if the given level is at // Log a message and a set of key/value pairs if the given level is at
// or more severe that the threshold configured in the Logger. // or more severe that the threshold configured in the Logger.
func (z *intLogger) Log(level Level, msg string, args ...interface{}) { func (z *intLogger) Log(level Level, msg string, args ...interface{}) {
if level < z.level { if level < Level(atomic.LoadInt32(z.level)) {
return return
} }
@ -126,7 +141,7 @@ func trimCallerPath(path string) string {
// Non-JSON logging format function // Non-JSON logging format function
func (z *intLogger) log(t time.Time, level Level, msg string, args ...interface{}) { func (z *intLogger) log(t time.Time, level Level, msg string, args ...interface{}) {
z.w.WriteString(t.Format(TimeFormat)) z.w.WriteString(t.Format(z.timeFormat))
z.w.WriteByte(' ') z.w.WriteByte(' ')
s, ok := _levelToBracket[level] s, ok := _levelToBracket[level]
@ -202,6 +217,8 @@ func (z *intLogger) log(t time.Time, level Level, msg string, args ...interface{
case CapturedStacktrace: case CapturedStacktrace:
stacktrace = st stacktrace = st
continue FOR continue FOR
case Format:
val = fmt.Sprintf(st[0].(string), st[1:]...)
default: default:
val = fmt.Sprintf("%v", st) val = fmt.Sprintf("%v", st)
} }
@ -262,6 +279,8 @@ func (z *intLogger) logJson(t time.Time, level Level, msg string, args ...interf
} }
} }
args = append(z.implied, args...)
if args != nil && len(args) > 0 { if args != nil && len(args) > 0 {
if len(args)%2 != 0 { if len(args)%2 != 0 {
cs, ok := args[len(args)-1].(CapturedStacktrace) cs, ok := args[len(args)-1].(CapturedStacktrace)
@ -279,7 +298,22 @@ func (z *intLogger) logJson(t time.Time, level Level, msg string, args ...interf
// without injecting into logs... // without injecting into logs...
continue continue
} }
vals[args[i].(string)] = args[i+1] val := args[i+1]
switch sv := val.(type) {
case error:
// Check if val is of type error. If error type doesn't
// implement json.Marshaler or encoding.TextMarshaler
// then set val to err.Error() so that it gets marshaled
switch sv.(type) {
case json.Marshaler, encoding.TextMarshaler:
default:
val = sv.Error()
}
case Format:
val = fmt.Sprintf(sv[0].(string), sv[1:]...)
}
vals[args[i].(string)] = val
} }
} }
@ -316,36 +350,66 @@ func (z *intLogger) Error(msg string, args ...interface{}) {
// Indicate that the logger would emit TRACE level logs // Indicate that the logger would emit TRACE level logs
func (z *intLogger) IsTrace() bool { func (z *intLogger) IsTrace() bool {
return z.level == Trace return Level(atomic.LoadInt32(z.level)) == Trace
} }
// Indicate that the logger would emit DEBUG level logs // Indicate that the logger would emit DEBUG level logs
func (z *intLogger) IsDebug() bool { func (z *intLogger) IsDebug() bool {
return z.level <= Debug return Level(atomic.LoadInt32(z.level)) <= Debug
} }
// Indicate that the logger would emit INFO level logs // Indicate that the logger would emit INFO level logs
func (z *intLogger) IsInfo() bool { func (z *intLogger) IsInfo() bool {
return z.level <= Info return Level(atomic.LoadInt32(z.level)) <= Info
} }
// Indicate that the logger would emit WARN level logs // Indicate that the logger would emit WARN level logs
func (z *intLogger) IsWarn() bool { func (z *intLogger) IsWarn() bool {
return z.level <= Warn return Level(atomic.LoadInt32(z.level)) <= Warn
} }
// Indicate that the logger would emit ERROR level logs // Indicate that the logger would emit ERROR level logs
func (z *intLogger) IsError() bool { func (z *intLogger) IsError() bool {
return z.level <= Error return Level(atomic.LoadInt32(z.level)) <= Error
} }
// Return a sub-Logger for which every emitted log message will contain // Return a sub-Logger for which every emitted log message will contain
// the given key/value pairs. This is used to create a context specific // the given key/value pairs. This is used to create a context specific
// Logger. // Logger.
func (z *intLogger) With(args ...interface{}) Logger { func (z *intLogger) With(args ...interface{}) Logger {
if len(args)%2 != 0 {
panic("With() call requires paired arguments")
}
var nz intLogger = *z var nz intLogger = *z
nz.implied = append(nz.implied, args...) result := make(map[string]interface{}, len(z.implied)+len(args))
keys := make([]string, 0, len(z.implied)+len(args))
// Read existing args, store map and key for consistent sorting
for i := 0; i < len(z.implied); i += 2 {
key := z.implied[i].(string)
keys = append(keys, key)
result[key] = z.implied[i+1]
}
// Read new args, store map and key for consistent sorting
for i := 0; i < len(args); i += 2 {
key := args[i].(string)
_, exists := result[key]
if !exists {
keys = append(keys, key)
}
result[key] = args[i+1]
}
// Sort keys to be consistent
sort.Strings(keys)
nz.implied = make([]interface{}, 0, len(z.implied)+len(args))
for _, k := range keys {
nz.implied = append(nz.implied, k)
nz.implied = append(nz.implied, result[k])
}
return &nz return &nz
} }
@ -357,6 +421,8 @@ func (z *intLogger) Named(name string) Logger {
if nz.name != "" { if nz.name != "" {
nz.name = nz.name + "." + name nz.name = nz.name + "." + name
} else {
nz.name = name
} }
return &nz return &nz
@ -373,6 +439,12 @@ func (z *intLogger) ResetNamed(name string) Logger {
return &nz return &nz
} }
// Update the logging level on-the-fly. This will affect all subloggers as
// well.
func (z *intLogger) SetLevel(level Level) {
atomic.StoreInt32(z.level, int32(level))
}
// Create a *log.Logger that will send it's data through this Logger. This // Create a *log.Logger that will send it's data through this Logger. This
// allows packages that expect to be using the standard library log to actually // allows packages that expect to be using the standard library log to actually
// use this logger. // use this logger.

View file

@ -5,6 +5,7 @@ import (
"log" "log"
"os" "os"
"strings" "strings"
"sync"
) )
var ( var (
@ -12,7 +13,7 @@ var (
DefaultLevel = Info DefaultLevel = Info
) )
type Level int type Level int32
const ( const (
// This is a special level used to indicate that no level has been // This is a special level used to indicate that no level has been
@ -36,6 +37,18 @@ const (
Error Level = 5 Error Level = 5
) )
// When processing a value of this type, the logger automatically treats the first
// argument as a Printf formatting string and passes the rest as the values to be
// formatted. For example: L.Info(Fmt{"%d beans/day", beans}). This is a simple
// convience type for when formatting is required.
type Format []interface{}
// Fmt returns a Format type. This is a convience function for creating a Format
// type.
func Fmt(str string, args ...interface{}) Format {
return append(Format{str}, args...)
}
// LevelFromString returns a Level type for the named log level, or "NoLevel" if // LevelFromString returns a Level type for the named log level, or "NoLevel" if
// the level string is invalid. This facilitates setting the log level via // the level string is invalid. This facilitates setting the log level via
// config or environment variable by name in a predictable way. // config or environment variable by name in a predictable way.
@ -108,6 +121,10 @@ type Logger interface {
// the current name as well. // the current name as well.
ResetNamed(name string) Logger ResetNamed(name string) Logger
// Updates the level. This should affect all sub-loggers as well. If an
// implementation cannot update the level on the fly, it should no-op.
SetLevel(level Level)
// Return a value that conforms to the stdlib log.Logger interface // Return a value that conforms to the stdlib log.Logger interface
StandardLogger(opts *StandardLoggerOptions) *log.Logger StandardLogger(opts *StandardLoggerOptions) *log.Logger
} }
@ -130,9 +147,15 @@ type LoggerOptions struct {
// Where to write the logs to. Defaults to os.Stdout if nil // Where to write the logs to. Defaults to os.Stdout if nil
Output io.Writer Output io.Writer
// An optional mutex pointer in case Output is shared
Mutex *sync.Mutex
// Control if the output should be in JSON. // Control if the output should be in JSON.
JSONFormat bool JSONFormat bool
// Intclude file and line information in each log line // Include file and line information in each log line
IncludeLocation bool IncludeLocation bool
// The time format to use instead of the default
TimeFormat string
} }

47
vendor/github.com/hashicorp/go-hclog/nulllogger.go generated vendored Normal file
View file

@ -0,0 +1,47 @@
package hclog
import (
"io/ioutil"
"log"
)
// NewNullLogger instantiates a Logger for which all calls
// will succeed without doing anything.
// Useful for testing purposes.
func NewNullLogger() Logger {
return &nullLogger{}
}
type nullLogger struct{}
func (l *nullLogger) Trace(msg string, args ...interface{}) {}
func (l *nullLogger) Debug(msg string, args ...interface{}) {}
func (l *nullLogger) Info(msg string, args ...interface{}) {}
func (l *nullLogger) Warn(msg string, args ...interface{}) {}
func (l *nullLogger) Error(msg string, args ...interface{}) {}
func (l *nullLogger) IsTrace() bool { return false }
func (l *nullLogger) IsDebug() bool { return false }
func (l *nullLogger) IsInfo() bool { return false }
func (l *nullLogger) IsWarn() bool { return false }
func (l *nullLogger) IsError() bool { return false }
func (l *nullLogger) With(args ...interface{}) Logger { return l }
func (l *nullLogger) Named(name string) Logger { return l }
func (l *nullLogger) ResetNamed(name string) Logger { return l }
func (l *nullLogger) SetLevel(level Level) {}
func (l *nullLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger {
return log.New(ioutil.Discard, "", log.LstdFlags)
}

2
vendor/vendor.json vendored
View file

@ -150,7 +150,7 @@
{"path":"github.com/hashicorp/go-envparse","checksumSHA1":"FKmqR4DC3nCXtnT9pe02z5CLNWo=","revision":"310ca1881b22af3522e3a8638c0b426629886196","revisionTime":"2018-01-19T21:58:41Z"}, {"path":"github.com/hashicorp/go-envparse","checksumSHA1":"FKmqR4DC3nCXtnT9pe02z5CLNWo=","revision":"310ca1881b22af3522e3a8638c0b426629886196","revisionTime":"2018-01-19T21:58:41Z"},
{"path":"github.com/hashicorp/go-getter","checksumSHA1":"uGH6AI982csQJoRPsSooK7FoWqo=","revision":"3f60ec5cfbb2a39731571b9ddae54b303bb0a969","revisionTime":"2018-04-25T22:41:30Z"}, {"path":"github.com/hashicorp/go-getter","checksumSHA1":"uGH6AI982csQJoRPsSooK7FoWqo=","revision":"3f60ec5cfbb2a39731571b9ddae54b303bb0a969","revisionTime":"2018-04-25T22:41:30Z"},
{"path":"github.com/hashicorp/go-getter/helper/url","checksumSHA1":"9J+kDr29yDrwsdu2ULzewmqGjpA=","revision":"b345bfcec894fb7ff3fdf9b21baf2f56ea423d98","revisionTime":"2018-04-10T17:49:45Z"}, {"path":"github.com/hashicorp/go-getter/helper/url","checksumSHA1":"9J+kDr29yDrwsdu2ULzewmqGjpA=","revision":"b345bfcec894fb7ff3fdf9b21baf2f56ea423d98","revisionTime":"2018-04-10T17:49:45Z"},
{"path":"github.com/hashicorp/go-hclog","checksumSHA1":"miVF4/7JP0lRwZvFJGKwZWk7aAQ=","revision":"b4e5765d1e5f00a0550911084f45f8214b5b83b9","revisionTime":"2017-07-16T17:45:23Z"}, {"path":"github.com/hashicorp/go-hclog","checksumSHA1":"dOP7kCX3dACHc9mU79826N411QA=","revision":"ff2cf002a8dd750586d91dddd4470c341f981fe1","revisionTime":"2018-07-09T16:53:50Z"},
{"path":"github.com/hashicorp/go-immutable-radix","checksumSHA1":"Cas2nprG6pWzf05A2F/OlnjUu2Y=","revision":"8aac2701530899b64bdea735a1de8da899815220","revisionTime":"2017-07-25T22:12:15Z"}, {"path":"github.com/hashicorp/go-immutable-radix","checksumSHA1":"Cas2nprG6pWzf05A2F/OlnjUu2Y=","revision":"8aac2701530899b64bdea735a1de8da899815220","revisionTime":"2017-07-25T22:12:15Z"},
{"path":"github.com/hashicorp/go-memdb","checksumSHA1":"FMAvwDar2bQyYAW4XMFhAt0J5xA=","revision":"20ff6434c1cc49b80963d45bf5c6aa89c78d8d57","revisionTime":"2017-08-31T20:15:40Z"}, {"path":"github.com/hashicorp/go-memdb","checksumSHA1":"FMAvwDar2bQyYAW4XMFhAt0J5xA=","revision":"20ff6434c1cc49b80963d45bf5c6aa89c78d8d57","revisionTime":"2017-08-31T20:15:40Z"},
{"path":"github.com/hashicorp/go-msgpack/codec","revision":"fa3f63826f7c23912c15263591e65d54d080b458"}, {"path":"github.com/hashicorp/go-msgpack/codec","revision":"fa3f63826f7c23912c15263591e65d54d080b458"},