add vendor
This commit is contained in:
1
vendor/github.com/hashicorp/go-hclog/.gitignore
generated
vendored
Normal file
1
vendor/github.com/hashicorp/go-hclog/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
.idea*
|
21
vendor/github.com/hashicorp/go-hclog/LICENSE
generated
vendored
Normal file
21
vendor/github.com/hashicorp/go-hclog/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 HashiCorp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
148
vendor/github.com/hashicorp/go-hclog/README.md
generated
vendored
Normal file
148
vendor/github.com/hashicorp/go-hclog/README.md
generated
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
# go-hclog
|
||||
|
||||
[][godocs]
|
||||
|
||||
[godocs]: https://godoc.org/github.com/hashicorp/go-hclog
|
||||
|
||||
`go-hclog` is a package for Go that provides a simple key/value logging
|
||||
interface for use in development and production environments.
|
||||
|
||||
It provides logging levels that provide decreased output based upon the
|
||||
desired amount of output, unlike the standard library `log` package.
|
||||
|
||||
It provides `Printf` style logging of values via `hclog.Fmt()`.
|
||||
|
||||
It provides a human readable output mode for use in development as well as
|
||||
JSON output mode for production.
|
||||
|
||||
## Stability Note
|
||||
|
||||
While this library is fully open source and HashiCorp will be maintaining it
|
||||
(since we are and will be making extensive use of it), the API and output
|
||||
format is subject to minor changes as we fully bake and vet it in our projects.
|
||||
This notice will be removed once it's fully integrated into our major projects
|
||||
and no further changes are anticipated.
|
||||
|
||||
## Installation and Docs
|
||||
|
||||
Install using `go get github.com/hashicorp/go-hclog`.
|
||||
|
||||
Full documentation is available at
|
||||
http://godoc.org/github.com/hashicorp/go-hclog
|
||||
|
||||
## Usage
|
||||
|
||||
### Use the global logger
|
||||
|
||||
```go
|
||||
hclog.Default().Info("hello world")
|
||||
```
|
||||
|
||||
```text
|
||||
2017-07-05T16:15:55.167-0700 [INFO ] hello world
|
||||
```
|
||||
|
||||
(Note timestamps are removed in future examples for brevity.)
|
||||
|
||||
### Create a new logger
|
||||
|
||||
```go
|
||||
appLogger := hclog.New(&hclog.LoggerOptions{
|
||||
Name: "my-app",
|
||||
Level: hclog.LevelFromString("DEBUG"),
|
||||
})
|
||||
```
|
||||
|
||||
### Emit an Info level message with 2 key/value pairs
|
||||
|
||||
```go
|
||||
input := "5.5"
|
||||
_, err := strconv.ParseInt(input, 10, 32)
|
||||
if err != nil {
|
||||
appLogger.Info("Invalid input for ParseInt", "input", input, "error", err)
|
||||
}
|
||||
```
|
||||
|
||||
```text
|
||||
... [INFO ] my-app: Invalid input for ParseInt: input=5.5 error="strconv.ParseInt: parsing "5.5": invalid syntax"
|
||||
```
|
||||
|
||||
### Create a new Logger for a major subsystem
|
||||
|
||||
```go
|
||||
subsystemLogger := appLogger.Named("transport")
|
||||
subsystemLogger.Info("we are transporting something")
|
||||
```
|
||||
|
||||
```text
|
||||
... [INFO ] my-app.transport: we are transporting something
|
||||
```
|
||||
|
||||
Notice that logs emitted by `subsystemLogger` contain `my-app.transport`,
|
||||
reflecting both the application and subsystem names.
|
||||
|
||||
### Create a new Logger with fixed key/value pairs
|
||||
|
||||
Using `With()` will include a specific key-value pair in all messages emitted
|
||||
by that logger.
|
||||
|
||||
```go
|
||||
requestID := "5fb446b6-6eba-821d-df1b-cd7501b6a363"
|
||||
requestLogger := subsystemLogger.With("request", requestID)
|
||||
requestLogger.Info("we are transporting a request")
|
||||
```
|
||||
|
||||
```text
|
||||
... [INFO ] my-app.transport: we are transporting a request: request=5fb446b6-6eba-821d-df1b-cd7501b6a363
|
||||
```
|
||||
|
||||
This allows sub Loggers to be context specific without having to thread that
|
||||
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
|
||||
|
||||
If you want to use the standard library's `log.Logger` interface you can wrap
|
||||
`hclog.Logger` by calling the `StandardLogger()` method. This allows you to use
|
||||
it with the familiar `Println()`, `Printf()`, etc. For example:
|
||||
|
||||
```go
|
||||
stdLogger := appLogger.StandardLogger(&hclog.StandardLoggerOptions{
|
||||
InferLevels: true,
|
||||
})
|
||||
// Printf() is provided by stdlib log.Logger interface, not hclog.Logger
|
||||
stdLogger.Printf("[DEBUG] %+v", stdLogger)
|
||||
```
|
||||
|
||||
```text
|
||||
... [DEBUG] my-app: &{mu:{state:0 sema:0} prefix: flag:0 out:0xc42000a0a0 buf:[]}
|
||||
```
|
||||
|
||||
Alternatively, you may configure the system-wide logger:
|
||||
|
||||
```go
|
||||
// log the standard logger from 'import "log"'
|
||||
log.SetOutput(appLogger.Writer(&hclog.StandardLoggerOptions{InferLevels: true}))
|
||||
log.SetPrefix("")
|
||||
log.SetFlags(0)
|
||||
|
||||
log.Printf("[DEBUG] %d", 42)
|
||||
```
|
||||
|
||||
```text
|
||||
... [DEBUG] my-app: 42
|
||||
```
|
||||
|
||||
Notice that if `appLogger` is initialized with the `INFO` log level _and_ you
|
||||
specify `InferLevels: true`, you will not see any output here. You must change
|
||||
`appLogger` to `DEBUG` to see output. See the docs for more information.
|
38
vendor/github.com/hashicorp/go-hclog/context.go
generated
vendored
Normal file
38
vendor/github.com/hashicorp/go-hclog/context.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
package hclog
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// WithContext inserts a logger into the context and is retrievable
|
||||
// with FromContext. The optional args can be set with the same syntax as
|
||||
// Logger.With to set fields on the inserted logger. This will not modify
|
||||
// the logger argument in-place.
|
||||
func WithContext(ctx context.Context, logger Logger, args ...interface{}) context.Context {
|
||||
// While we could call logger.With even with zero args, we have this
|
||||
// check to avoid unnecessary allocations around creating a copy of a
|
||||
// logger.
|
||||
if len(args) > 0 {
|
||||
logger = logger.With(args...)
|
||||
}
|
||||
|
||||
return context.WithValue(ctx, contextKey, logger)
|
||||
}
|
||||
|
||||
// FromContext returns a logger from the context. This will return L()
|
||||
// (the default logger) if no logger is found in the context. Therefore,
|
||||
// this will never return a nil value.
|
||||
func FromContext(ctx context.Context) Logger {
|
||||
logger, _ := ctx.Value(contextKey).(Logger)
|
||||
if logger == nil {
|
||||
return L()
|
||||
}
|
||||
|
||||
return logger
|
||||
}
|
||||
|
||||
// Unexported new type so that our context key never collides with another.
|
||||
type contextKeyType struct{}
|
||||
|
||||
// contextKey is the key used for the context to store the logger.
|
||||
var contextKey = contextKeyType{}
|
48
vendor/github.com/hashicorp/go-hclog/global.go
generated
vendored
Normal file
48
vendor/github.com/hashicorp/go-hclog/global.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
package hclog
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
protect sync.Once
|
||||
def Logger
|
||||
|
||||
// DefaultOptions is used to create the Default logger. These are read
|
||||
// only when the Default logger is created, so set them as soon as the
|
||||
// process starts.
|
||||
DefaultOptions = &LoggerOptions{
|
||||
Level: DefaultLevel,
|
||||
Output: DefaultOutput,
|
||||
}
|
||||
)
|
||||
|
||||
// Default returns a globally held logger. This can be a good starting
|
||||
// place, and then you can use .With() and .Name() to create sub-loggers
|
||||
// to be used in more specific contexts.
|
||||
func Default() Logger {
|
||||
protect.Do(func() {
|
||||
// If SetDefault was used before Default() was called, we need to
|
||||
// detect that here.
|
||||
if def == nil {
|
||||
def = New(DefaultOptions)
|
||||
}
|
||||
})
|
||||
|
||||
return def
|
||||
}
|
||||
|
||||
// L is a short alias for Default().
|
||||
func L() Logger {
|
||||
return Default()
|
||||
}
|
||||
|
||||
// SetDefault changes the logger to be returned by Default()and L()
|
||||
// to the one given. This allows packages to use the default logger
|
||||
// and have higher level packages change it to match the execution
|
||||
// environment. It returns any old default if there is one.
|
||||
func SetDefault(log Logger) Logger {
|
||||
old := def
|
||||
def = log
|
||||
return old
|
||||
}
|
527
vendor/github.com/hashicorp/go-hclog/intlogger.go
generated
vendored
Normal file
527
vendor/github.com/hashicorp/go-hclog/intlogger.go
generated
vendored
Normal file
@ -0,0 +1,527 @@
|
||||
package hclog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TimeFormat to use for logging. This is a version of RFC3339 that contains
|
||||
// contains millisecond precision
|
||||
const TimeFormat = "2006-01-02T15:04:05.000Z0700"
|
||||
|
||||
// errJsonUnsupportedTypeMsg is included in log json entries, if an arg cannot be serialized to json
|
||||
const errJsonUnsupportedTypeMsg = "logging contained values that don't serialize to json"
|
||||
|
||||
var (
|
||||
_levelToBracket = map[Level]string{
|
||||
Debug: "[DEBUG]",
|
||||
Trace: "[TRACE]",
|
||||
Info: "[INFO] ",
|
||||
Warn: "[WARN] ",
|
||||
Error: "[ERROR]",
|
||||
}
|
||||
)
|
||||
|
||||
// Make sure that intLogger is a Logger
|
||||
var _ Logger = &intLogger{}
|
||||
|
||||
// intLogger is an internal logger implementation. Internal in that it is
|
||||
// defined entirely by this package.
|
||||
type intLogger struct {
|
||||
json bool
|
||||
caller bool
|
||||
name string
|
||||
timeFormat string
|
||||
|
||||
// This is a pointer so that it's shared by any derived loggers, since
|
||||
// those derived loggers share the bufio.Writer as well.
|
||||
mutex *sync.Mutex
|
||||
writer *writer
|
||||
level *int32
|
||||
|
||||
implied []interface{}
|
||||
}
|
||||
|
||||
// New returns a configured logger.
|
||||
func New(opts *LoggerOptions) Logger {
|
||||
if opts == nil {
|
||||
opts = &LoggerOptions{}
|
||||
}
|
||||
|
||||
output := opts.Output
|
||||
if output == nil {
|
||||
output = DefaultOutput
|
||||
}
|
||||
|
||||
level := opts.Level
|
||||
if level == NoLevel {
|
||||
level = DefaultLevel
|
||||
}
|
||||
|
||||
mutex := opts.Mutex
|
||||
if mutex == nil {
|
||||
mutex = new(sync.Mutex)
|
||||
}
|
||||
|
||||
l := &intLogger{
|
||||
json: opts.JSONFormat,
|
||||
caller: opts.IncludeLocation,
|
||||
name: opts.Name,
|
||||
timeFormat: TimeFormat,
|
||||
mutex: mutex,
|
||||
writer: newWriter(output),
|
||||
level: new(int32),
|
||||
}
|
||||
|
||||
if opts.TimeFormat != "" {
|
||||
l.timeFormat = opts.TimeFormat
|
||||
}
|
||||
|
||||
atomic.StoreInt32(l.level, int32(level))
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (l *intLogger) Log(level Level, msg string, args ...interface{}) {
|
||||
if level < Level(atomic.LoadInt32(l.level)) {
|
||||
return
|
||||
}
|
||||
|
||||
t := time.Now()
|
||||
|
||||
l.mutex.Lock()
|
||||
defer l.mutex.Unlock()
|
||||
|
||||
if l.json {
|
||||
l.logJSON(t, level, msg, args...)
|
||||
} else {
|
||||
l.log(t, level, msg, args...)
|
||||
}
|
||||
|
||||
l.writer.Flush(level)
|
||||
}
|
||||
|
||||
// Cleanup a path by returning the last 2 segments of the path only.
|
||||
func trimCallerPath(path string) string {
|
||||
// lovely borrowed from zap
|
||||
// nb. To make sure we trim the path correctly on Windows too, we
|
||||
// counter-intuitively need to use '/' and *not* os.PathSeparator here,
|
||||
// because the path given originates from Go stdlib, specifically
|
||||
// runtime.Caller() which (as of Mar/17) returns forward slashes even on
|
||||
// Windows.
|
||||
//
|
||||
// See https://github.com/golang/go/issues/3335
|
||||
// and https://github.com/golang/go/issues/18151
|
||||
//
|
||||
// for discussion on the issue on Go side.
|
||||
|
||||
// Find the last separator.
|
||||
idx := strings.LastIndexByte(path, '/')
|
||||
if idx == -1 {
|
||||
return path
|
||||
}
|
||||
|
||||
// Find the penultimate separator.
|
||||
idx = strings.LastIndexByte(path[:idx], '/')
|
||||
if idx == -1 {
|
||||
return path
|
||||
}
|
||||
|
||||
return path[idx+1:]
|
||||
}
|
||||
|
||||
// Non-JSON logging format function
|
||||
func (l *intLogger) log(t time.Time, level Level, msg string, args ...interface{}) {
|
||||
l.writer.WriteString(t.Format(l.timeFormat))
|
||||
l.writer.WriteByte(' ')
|
||||
|
||||
s, ok := _levelToBracket[level]
|
||||
if ok {
|
||||
l.writer.WriteString(s)
|
||||
} else {
|
||||
l.writer.WriteString("[?????]")
|
||||
}
|
||||
|
||||
if l.caller {
|
||||
if _, file, line, ok := runtime.Caller(3); ok {
|
||||
l.writer.WriteByte(' ')
|
||||
l.writer.WriteString(trimCallerPath(file))
|
||||
l.writer.WriteByte(':')
|
||||
l.writer.WriteString(strconv.Itoa(line))
|
||||
l.writer.WriteByte(':')
|
||||
}
|
||||
}
|
||||
|
||||
l.writer.WriteByte(' ')
|
||||
|
||||
if l.name != "" {
|
||||
l.writer.WriteString(l.name)
|
||||
l.writer.WriteString(": ")
|
||||
}
|
||||
|
||||
l.writer.WriteString(msg)
|
||||
|
||||
args = append(l.implied, args...)
|
||||
|
||||
var stacktrace CapturedStacktrace
|
||||
|
||||
if args != nil && len(args) > 0 {
|
||||
if len(args)%2 != 0 {
|
||||
cs, ok := args[len(args)-1].(CapturedStacktrace)
|
||||
if ok {
|
||||
args = args[:len(args)-1]
|
||||
stacktrace = cs
|
||||
} else {
|
||||
args = append(args, "<unknown>")
|
||||
}
|
||||
}
|
||||
|
||||
l.writer.WriteByte(':')
|
||||
|
||||
FOR:
|
||||
for i := 0; i < len(args); i = i + 2 {
|
||||
var (
|
||||
val string
|
||||
raw bool
|
||||
)
|
||||
|
||||
switch st := args[i+1].(type) {
|
||||
case string:
|
||||
val = st
|
||||
case int:
|
||||
val = strconv.FormatInt(int64(st), 10)
|
||||
case int64:
|
||||
val = strconv.FormatInt(int64(st), 10)
|
||||
case int32:
|
||||
val = strconv.FormatInt(int64(st), 10)
|
||||
case int16:
|
||||
val = strconv.FormatInt(int64(st), 10)
|
||||
case int8:
|
||||
val = strconv.FormatInt(int64(st), 10)
|
||||
case uint:
|
||||
val = strconv.FormatUint(uint64(st), 10)
|
||||
case uint64:
|
||||
val = strconv.FormatUint(uint64(st), 10)
|
||||
case uint32:
|
||||
val = strconv.FormatUint(uint64(st), 10)
|
||||
case uint16:
|
||||
val = strconv.FormatUint(uint64(st), 10)
|
||||
case uint8:
|
||||
val = strconv.FormatUint(uint64(st), 10)
|
||||
case CapturedStacktrace:
|
||||
stacktrace = st
|
||||
continue FOR
|
||||
case Format:
|
||||
val = fmt.Sprintf(st[0].(string), st[1:]...)
|
||||
default:
|
||||
v := reflect.ValueOf(st)
|
||||
if v.Kind() == reflect.Slice {
|
||||
val = l.renderSlice(v)
|
||||
raw = true
|
||||
} else {
|
||||
val = fmt.Sprintf("%v", st)
|
||||
}
|
||||
}
|
||||
|
||||
l.writer.WriteByte(' ')
|
||||
l.writer.WriteString(args[i].(string))
|
||||
l.writer.WriteByte('=')
|
||||
|
||||
if !raw && strings.ContainsAny(val, " \t\n\r") {
|
||||
l.writer.WriteByte('"')
|
||||
l.writer.WriteString(val)
|
||||
l.writer.WriteByte('"')
|
||||
} else {
|
||||
l.writer.WriteString(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
l.writer.WriteString("\n")
|
||||
|
||||
if stacktrace != "" {
|
||||
l.writer.WriteString(string(stacktrace))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *intLogger) renderSlice(v reflect.Value) string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
buf.WriteRune('[')
|
||||
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
|
||||
sv := v.Index(i)
|
||||
|
||||
var val string
|
||||
|
||||
switch sv.Kind() {
|
||||
case reflect.String:
|
||||
val = sv.String()
|
||||
case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
val = strconv.FormatInt(sv.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
val = strconv.FormatUint(sv.Uint(), 10)
|
||||
default:
|
||||
val = fmt.Sprintf("%v", sv.Interface())
|
||||
}
|
||||
|
||||
if strings.ContainsAny(val, " \t\n\r") {
|
||||
buf.WriteByte('"')
|
||||
buf.WriteString(val)
|
||||
buf.WriteByte('"')
|
||||
} else {
|
||||
buf.WriteString(val)
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteRune(']')
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// JSON logging function
|
||||
func (l *intLogger) logJSON(t time.Time, level Level, msg string, args ...interface{}) {
|
||||
vals := l.jsonMapEntry(t, level, msg)
|
||||
args = append(l.implied, args...)
|
||||
|
||||
if args != nil && len(args) > 0 {
|
||||
if len(args)%2 != 0 {
|
||||
cs, ok := args[len(args)-1].(CapturedStacktrace)
|
||||
if ok {
|
||||
args = args[:len(args)-1]
|
||||
vals["stacktrace"] = cs
|
||||
} else {
|
||||
args = append(args, "<unknown>")
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(args); i = i + 2 {
|
||||
if _, ok := args[i].(string); !ok {
|
||||
// As this is the logging function not much we can do here
|
||||
// without injecting into logs...
|
||||
continue
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
err := json.NewEncoder(l.writer).Encode(vals)
|
||||
if err != nil {
|
||||
if _, ok := err.(*json.UnsupportedTypeError); ok {
|
||||
plainVal := l.jsonMapEntry(t, level, msg)
|
||||
plainVal["@warn"] = errJsonUnsupportedTypeMsg
|
||||
|
||||
json.NewEncoder(l.writer).Encode(plainVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l intLogger) jsonMapEntry(t time.Time, level Level, msg string) map[string]interface{} {
|
||||
vals := map[string]interface{}{
|
||||
"@message": msg,
|
||||
"@timestamp": t.Format("2006-01-02T15:04:05.000000Z07:00"),
|
||||
}
|
||||
|
||||
var levelStr string
|
||||
switch level {
|
||||
case Error:
|
||||
levelStr = "error"
|
||||
case Warn:
|
||||
levelStr = "warn"
|
||||
case Info:
|
||||
levelStr = "info"
|
||||
case Debug:
|
||||
levelStr = "debug"
|
||||
case Trace:
|
||||
levelStr = "trace"
|
||||
default:
|
||||
levelStr = "all"
|
||||
}
|
||||
|
||||
vals["@level"] = levelStr
|
||||
|
||||
if l.name != "" {
|
||||
vals["@module"] = l.name
|
||||
}
|
||||
|
||||
if l.caller {
|
||||
if _, file, line, ok := runtime.Caller(4); ok {
|
||||
vals["@caller"] = fmt.Sprintf("%s:%d", file, line)
|
||||
}
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
// Emit the message and args at DEBUG level
|
||||
func (l *intLogger) Debug(msg string, args ...interface{}) {
|
||||
l.Log(Debug, msg, args...)
|
||||
}
|
||||
|
||||
// Emit the message and args at TRACE level
|
||||
func (l *intLogger) Trace(msg string, args ...interface{}) {
|
||||
l.Log(Trace, msg, args...)
|
||||
}
|
||||
|
||||
// Emit the message and args at INFO level
|
||||
func (l *intLogger) Info(msg string, args ...interface{}) {
|
||||
l.Log(Info, msg, args...)
|
||||
}
|
||||
|
||||
// Emit the message and args at WARN level
|
||||
func (l *intLogger) Warn(msg string, args ...interface{}) {
|
||||
l.Log(Warn, msg, args...)
|
||||
}
|
||||
|
||||
// Emit the message and args at ERROR level
|
||||
func (l *intLogger) Error(msg string, args ...interface{}) {
|
||||
l.Log(Error, msg, args...)
|
||||
}
|
||||
|
||||
// Indicate that the logger would emit TRACE level logs
|
||||
func (l *intLogger) IsTrace() bool {
|
||||
return Level(atomic.LoadInt32(l.level)) == Trace
|
||||
}
|
||||
|
||||
// Indicate that the logger would emit DEBUG level logs
|
||||
func (l *intLogger) IsDebug() bool {
|
||||
return Level(atomic.LoadInt32(l.level)) <= Debug
|
||||
}
|
||||
|
||||
// Indicate that the logger would emit INFO level logs
|
||||
func (l *intLogger) IsInfo() bool {
|
||||
return Level(atomic.LoadInt32(l.level)) <= Info
|
||||
}
|
||||
|
||||
// Indicate that the logger would emit WARN level logs
|
||||
func (l *intLogger) IsWarn() bool {
|
||||
return Level(atomic.LoadInt32(l.level)) <= Warn
|
||||
}
|
||||
|
||||
// Indicate that the logger would emit ERROR level logs
|
||||
func (l *intLogger) IsError() bool {
|
||||
return Level(atomic.LoadInt32(l.level)) <= Error
|
||||
}
|
||||
|
||||
// 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
|
||||
// Logger.
|
||||
func (l *intLogger) With(args ...interface{}) Logger {
|
||||
if len(args)%2 != 0 {
|
||||
panic("With() call requires paired arguments")
|
||||
}
|
||||
|
||||
sl := *l
|
||||
|
||||
result := make(map[string]interface{}, len(l.implied)+len(args))
|
||||
keys := make([]string, 0, len(l.implied)+len(args))
|
||||
|
||||
// Read existing args, store map and key for consistent sorting
|
||||
for i := 0; i < len(l.implied); i += 2 {
|
||||
key := l.implied[i].(string)
|
||||
keys = append(keys, key)
|
||||
result[key] = l.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)
|
||||
|
||||
sl.implied = make([]interface{}, 0, len(l.implied)+len(args))
|
||||
for _, k := range keys {
|
||||
sl.implied = append(sl.implied, k)
|
||||
sl.implied = append(sl.implied, result[k])
|
||||
}
|
||||
|
||||
return &sl
|
||||
}
|
||||
|
||||
// Create a new sub-Logger that a name decending from the current name.
|
||||
// This is used to create a subsystem specific Logger.
|
||||
func (l *intLogger) Named(name string) Logger {
|
||||
sl := *l
|
||||
|
||||
if sl.name != "" {
|
||||
sl.name = sl.name + "." + name
|
||||
} else {
|
||||
sl.name = name
|
||||
}
|
||||
|
||||
return &sl
|
||||
}
|
||||
|
||||
// Create a new sub-Logger with an explicit name. This ignores the current
|
||||
// name. This is used to create a standalone logger that doesn't fall
|
||||
// within the normal hierarchy.
|
||||
func (l *intLogger) ResetNamed(name string) Logger {
|
||||
sl := *l
|
||||
|
||||
sl.name = name
|
||||
|
||||
return &sl
|
||||
}
|
||||
|
||||
// Update the logging level on-the-fly. This will affect all subloggers as
|
||||
// well.
|
||||
func (l *intLogger) SetLevel(level Level) {
|
||||
atomic.StoreInt32(l.level, int32(level))
|
||||
}
|
||||
|
||||
// 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
|
||||
// use this logger.
|
||||
func (l *intLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger {
|
||||
if opts == nil {
|
||||
opts = &StandardLoggerOptions{}
|
||||
}
|
||||
|
||||
return log.New(l.StandardWriter(opts), "", 0)
|
||||
}
|
||||
|
||||
func (l *intLogger) StandardWriter(opts *StandardLoggerOptions) io.Writer {
|
||||
return &stdlogAdapter{
|
||||
log: l,
|
||||
inferLevels: opts.InferLevels,
|
||||
forceLevel: opts.ForceLevel,
|
||||
}
|
||||
}
|
176
vendor/github.com/hashicorp/go-hclog/logger.go
generated
vendored
Normal file
176
vendor/github.com/hashicorp/go-hclog/logger.go
generated
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
package hclog
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
//DefaultOutput is used as the default log output.
|
||||
DefaultOutput io.Writer = os.Stderr
|
||||
|
||||
// DefaultLevel is used as the default log level.
|
||||
DefaultLevel = Info
|
||||
)
|
||||
|
||||
// Level represents a log level.
|
||||
type Level int32
|
||||
|
||||
const (
|
||||
// NoLevel is a special level used to indicate that no level has been
|
||||
// set and allow for a default to be used.
|
||||
NoLevel Level = 0
|
||||
|
||||
// Trace is the most verbose level. Intended to be used for the tracing
|
||||
// of actions in code, such as function enters/exits, etc.
|
||||
Trace Level = 1
|
||||
|
||||
// Debug information for programmer lowlevel analysis.
|
||||
Debug Level = 2
|
||||
|
||||
// Info information about steady state operations.
|
||||
Info Level = 3
|
||||
|
||||
// Warn information about rare but handled events.
|
||||
Warn Level = 4
|
||||
|
||||
// Error information about unrecoverable events.
|
||||
Error Level = 5
|
||||
)
|
||||
|
||||
// Format is a simple convience type for when formatting is required. 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}).
|
||||
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
|
||||
// the level string is invalid. This facilitates setting the log level via
|
||||
// config or environment variable by name in a predictable way.
|
||||
func LevelFromString(levelStr string) Level {
|
||||
// We don't care about case. Accept both "INFO" and "info".
|
||||
levelStr = strings.ToLower(strings.TrimSpace(levelStr))
|
||||
switch levelStr {
|
||||
case "trace":
|
||||
return Trace
|
||||
case "debug":
|
||||
return Debug
|
||||
case "info":
|
||||
return Info
|
||||
case "warn":
|
||||
return Warn
|
||||
case "error":
|
||||
return Error
|
||||
default:
|
||||
return NoLevel
|
||||
}
|
||||
}
|
||||
|
||||
// Logger describes the interface that must be implemeted by all loggers.
|
||||
type Logger interface {
|
||||
// Args are alternating key, val pairs
|
||||
// keys must be strings
|
||||
// vals can be any type, but display is implementation specific
|
||||
// Emit a message and key/value pairs at the TRACE level
|
||||
Trace(msg string, args ...interface{})
|
||||
|
||||
// Emit a message and key/value pairs at the DEBUG level
|
||||
Debug(msg string, args ...interface{})
|
||||
|
||||
// Emit a message and key/value pairs at the INFO level
|
||||
Info(msg string, args ...interface{})
|
||||
|
||||
// Emit a message and key/value pairs at the WARN level
|
||||
Warn(msg string, args ...interface{})
|
||||
|
||||
// Emit a message and key/value pairs at the ERROR level
|
||||
Error(msg string, args ...interface{})
|
||||
|
||||
// Indicate if TRACE logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
IsTrace() bool
|
||||
|
||||
// Indicate if DEBUG logs would be emitted. This and the other Is* guards
|
||||
IsDebug() bool
|
||||
|
||||
// Indicate if INFO logs would be emitted. This and the other Is* guards
|
||||
IsInfo() bool
|
||||
|
||||
// Indicate if WARN logs would be emitted. This and the other Is* guards
|
||||
IsWarn() bool
|
||||
|
||||
// Indicate if ERROR logs would be emitted. This and the other Is* guards
|
||||
IsError() bool
|
||||
|
||||
// Creates a sublogger that will always have the given key/value pairs
|
||||
With(args ...interface{}) Logger
|
||||
|
||||
// Create a logger that will prepend the name string on the front of all messages.
|
||||
// If the logger already has a name, the new value will be appended to the current
|
||||
// name. That way, a major subsystem can use this to decorate all it's own logs
|
||||
// without losing context.
|
||||
Named(name string) Logger
|
||||
|
||||
// Create a logger that will prepend the name string on the front of all messages.
|
||||
// This sets the name of the logger to the value directly, unlike Named which honor
|
||||
// the current name as well.
|
||||
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
|
||||
StandardLogger(opts *StandardLoggerOptions) *log.Logger
|
||||
|
||||
// Return a value that conforms to io.Writer, which can be passed into log.SetOutput()
|
||||
StandardWriter(opts *StandardLoggerOptions) io.Writer
|
||||
}
|
||||
|
||||
// StandardLoggerOptions can be used to configure a new standard logger.
|
||||
type StandardLoggerOptions struct {
|
||||
// Indicate that some minimal parsing should be done on strings to try
|
||||
// and detect their level and re-emit them.
|
||||
// This supports the strings like [ERROR], [ERR] [TRACE], [WARN], [INFO],
|
||||
// [DEBUG] and strip it off before reapplying it.
|
||||
InferLevels bool
|
||||
|
||||
// ForceLevel is used to force all output from the standard logger to be at
|
||||
// the specified level. Similar to InferLevels, this will strip any level
|
||||
// prefix contained in the logged string before applying the forced level.
|
||||
// If set, this override InferLevels.
|
||||
ForceLevel Level
|
||||
}
|
||||
|
||||
// LoggerOptions can be used to configure a new logger.
|
||||
type LoggerOptions struct {
|
||||
// Name of the subsystem to prefix logs with
|
||||
Name string
|
||||
|
||||
// The threshold for the logger. Anything less severe is supressed
|
||||
Level Level
|
||||
|
||||
// Where to write the logs to. Defaults to os.Stderr if nil
|
||||
Output io.Writer
|
||||
|
||||
// An optional mutex pointer in case Output is shared
|
||||
Mutex *sync.Mutex
|
||||
|
||||
// Control if the output should be in JSON.
|
||||
JSONFormat bool
|
||||
|
||||
// Include file and line information in each log line
|
||||
IncludeLocation bool
|
||||
|
||||
// The time format to use instead of the default
|
||||
TimeFormat string
|
||||
}
|
52
vendor/github.com/hashicorp/go-hclog/nulllogger.go
generated
vendored
Normal file
52
vendor/github.com/hashicorp/go-hclog/nulllogger.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
package hclog
|
||||
|
||||
import (
|
||||
"io"
|
||||
"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(l.StandardWriter(opts), "", log.LstdFlags)
|
||||
}
|
||||
|
||||
func (l *nullLogger) StandardWriter(opts *StandardLoggerOptions) io.Writer {
|
||||
return ioutil.Discard
|
||||
}
|
109
vendor/github.com/hashicorp/go-hclog/stacktrace.go
generated
vendored
Normal file
109
vendor/github.com/hashicorp/go-hclog/stacktrace.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2016 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package hclog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
_stacktraceIgnorePrefixes = []string{
|
||||
"runtime.goexit",
|
||||
"runtime.main",
|
||||
}
|
||||
_stacktracePool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return newProgramCounters(64)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// CapturedStacktrace represents a stacktrace captured by a previous call
|
||||
// to log.Stacktrace. If passed to a logging function, the stacktrace
|
||||
// will be appended.
|
||||
type CapturedStacktrace string
|
||||
|
||||
// Stacktrace captures a stacktrace of the current goroutine and returns
|
||||
// it to be passed to a logging function.
|
||||
func Stacktrace() CapturedStacktrace {
|
||||
return CapturedStacktrace(takeStacktrace())
|
||||
}
|
||||
|
||||
func takeStacktrace() string {
|
||||
programCounters := _stacktracePool.Get().(*programCounters)
|
||||
defer _stacktracePool.Put(programCounters)
|
||||
|
||||
var buffer bytes.Buffer
|
||||
|
||||
for {
|
||||
// Skip the call to runtime.Counters and takeStacktrace so that the
|
||||
// program counters start at the caller of takeStacktrace.
|
||||
n := runtime.Callers(2, programCounters.pcs)
|
||||
if n < cap(programCounters.pcs) {
|
||||
programCounters.pcs = programCounters.pcs[:n]
|
||||
break
|
||||
}
|
||||
// Don't put the too-short counter slice back into the pool; this lets
|
||||
// the pool adjust if we consistently take deep stacktraces.
|
||||
programCounters = newProgramCounters(len(programCounters.pcs) * 2)
|
||||
}
|
||||
|
||||
i := 0
|
||||
frames := runtime.CallersFrames(programCounters.pcs)
|
||||
for frame, more := frames.Next(); more; frame, more = frames.Next() {
|
||||
if shouldIgnoreStacktraceFunction(frame.Function) {
|
||||
continue
|
||||
}
|
||||
if i != 0 {
|
||||
buffer.WriteByte('\n')
|
||||
}
|
||||
i++
|
||||
buffer.WriteString(frame.Function)
|
||||
buffer.WriteByte('\n')
|
||||
buffer.WriteByte('\t')
|
||||
buffer.WriteString(frame.File)
|
||||
buffer.WriteByte(':')
|
||||
buffer.WriteString(strconv.Itoa(int(frame.Line)))
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func shouldIgnoreStacktraceFunction(function string) bool {
|
||||
for _, prefix := range _stacktraceIgnorePrefixes {
|
||||
if strings.HasPrefix(function, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type programCounters struct {
|
||||
pcs []uintptr
|
||||
}
|
||||
|
||||
func newProgramCounters(size int) *programCounters {
|
||||
return &programCounters{make([]uintptr, size)}
|
||||
}
|
83
vendor/github.com/hashicorp/go-hclog/stdlog.go
generated
vendored
Normal file
83
vendor/github.com/hashicorp/go-hclog/stdlog.go
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
package hclog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Provides a io.Writer to shim the data out of *log.Logger
|
||||
// and back into our Logger. This is basically the only way to
|
||||
// build upon *log.Logger.
|
||||
type stdlogAdapter struct {
|
||||
log Logger
|
||||
inferLevels bool
|
||||
forceLevel Level
|
||||
}
|
||||
|
||||
// Take the data, infer the levels if configured, and send it through
|
||||
// a regular Logger.
|
||||
func (s *stdlogAdapter) Write(data []byte) (int, error) {
|
||||
str := string(bytes.TrimRight(data, " \t\n"))
|
||||
|
||||
if s.forceLevel != NoLevel {
|
||||
// Use pickLevel to strip log levels included in the line since we are
|
||||
// forcing the level
|
||||
_, str := s.pickLevel(str)
|
||||
|
||||
// Log at the forced level
|
||||
switch s.forceLevel {
|
||||
case Trace:
|
||||
s.log.Trace(str)
|
||||
case Debug:
|
||||
s.log.Debug(str)
|
||||
case Info:
|
||||
s.log.Info(str)
|
||||
case Warn:
|
||||
s.log.Warn(str)
|
||||
case Error:
|
||||
s.log.Error(str)
|
||||
default:
|
||||
s.log.Info(str)
|
||||
}
|
||||
} else if s.inferLevels {
|
||||
level, str := s.pickLevel(str)
|
||||
switch level {
|
||||
case Trace:
|
||||
s.log.Trace(str)
|
||||
case Debug:
|
||||
s.log.Debug(str)
|
||||
case Info:
|
||||
s.log.Info(str)
|
||||
case Warn:
|
||||
s.log.Warn(str)
|
||||
case Error:
|
||||
s.log.Error(str)
|
||||
default:
|
||||
s.log.Info(str)
|
||||
}
|
||||
} else {
|
||||
s.log.Info(str)
|
||||
}
|
||||
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// Detect, based on conventions, what log level this is.
|
||||
func (s *stdlogAdapter) pickLevel(str string) (Level, string) {
|
||||
switch {
|
||||
case strings.HasPrefix(str, "[DEBUG]"):
|
||||
return Debug, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[TRACE]"):
|
||||
return Trace, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[INFO]"):
|
||||
return Info, strings.TrimSpace(str[6:])
|
||||
case strings.HasPrefix(str, "[WARN]"):
|
||||
return Warn, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[ERROR]"):
|
||||
return Error, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[ERR]"):
|
||||
return Error, strings.TrimSpace(str[5:])
|
||||
default:
|
||||
return Info, str
|
||||
}
|
||||
}
|
74
vendor/github.com/hashicorp/go-hclog/writer.go
generated
vendored
Normal file
74
vendor/github.com/hashicorp/go-hclog/writer.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
package hclog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
type writer struct {
|
||||
b bytes.Buffer
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func newWriter(w io.Writer) *writer {
|
||||
return &writer{w: w}
|
||||
}
|
||||
|
||||
func (w *writer) Flush(level Level) (err error) {
|
||||
if lw, ok := w.w.(LevelWriter); ok {
|
||||
_, err = lw.LevelWrite(level, w.b.Bytes())
|
||||
} else {
|
||||
_, err = w.w.Write(w.b.Bytes())
|
||||
}
|
||||
w.b.Reset()
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *writer) Write(p []byte) (int, error) {
|
||||
return w.b.Write(p)
|
||||
}
|
||||
|
||||
func (w *writer) WriteByte(c byte) error {
|
||||
return w.b.WriteByte(c)
|
||||
}
|
||||
|
||||
func (w *writer) WriteString(s string) (int, error) {
|
||||
return w.b.WriteString(s)
|
||||
}
|
||||
|
||||
// LevelWriter is the interface that wraps the LevelWrite method.
|
||||
type LevelWriter interface {
|
||||
LevelWrite(level Level, p []byte) (n int, err error)
|
||||
}
|
||||
|
||||
// LeveledWriter writes all log messages to the standard writer,
|
||||
// except for log levels that are defined in the overrides map.
|
||||
type LeveledWriter struct {
|
||||
standard io.Writer
|
||||
overrides map[Level]io.Writer
|
||||
}
|
||||
|
||||
// NewLeveledWriter returns an initialized LeveledWriter.
|
||||
//
|
||||
// standard will be used as the default writer for all log levels,
|
||||
// except for log levels that are defined in the overrides map.
|
||||
func NewLeveledWriter(standard io.Writer, overrides map[Level]io.Writer) *LeveledWriter {
|
||||
return &LeveledWriter{
|
||||
standard: standard,
|
||||
overrides: overrides,
|
||||
}
|
||||
}
|
||||
|
||||
// Write implements io.Writer.
|
||||
func (lw *LeveledWriter) Write(p []byte) (int, error) {
|
||||
return lw.standard.Write(p)
|
||||
}
|
||||
|
||||
// LevelWrite implements LevelWriter.
|
||||
func (lw *LeveledWriter) LevelWrite(level Level, p []byte) (int, error) {
|
||||
w, ok := lw.overrides[level]
|
||||
if !ok {
|
||||
w = lw.standard
|
||||
}
|
||||
return w.Write(p)
|
||||
}
|
Reference in New Issue
Block a user