Refactor mlog
- simplify mlog by removing redundant code
- remove Zap dependency
- update unit test helpers
- update logging config
- update auditing
Этот коммит содержится в:
Doug Lauder
2021-08-17 16:08:04 -04:00
коммит произвёл GitHub
родитель 04b27ce93c
Коммит a4507327a7
216 изменённых файлов: 4940 добавлений и 14674 удалений

11
vendor/github.com/mattermost/logr/config.go сгенерированный поставляемый
Просмотреть файл

@@ -1,11 +0,0 @@
package logr
import (
"fmt"
"github.com/wiggin77/cfg"
)
func ConfigLogger(config *cfg.Config) error {
return fmt.Errorf("Not implemented yet")
}

26
vendor/github.com/mattermost/logr/filter.go сгенерированный поставляемый
Просмотреть файл

@@ -1,26 +0,0 @@
package logr
// LevelID is the unique id of each level.
type LevelID uint
// Level provides a mechanism to enable/disable specific log lines.
type Level struct {
ID LevelID
Name string
Stacktrace bool
}
// String returns the name of this level.
func (level Level) String() string {
return level.Name
}
// Filter allows targets to determine which Level(s) are active
// for logging and which Level(s) require a stack trace to be output.
// A default implementation using "panic, fatal..." is provided, and
// a more flexible alternative implementation is also provided that
// allows any number of custom levels.
type Filter interface {
IsEnabled(Level) bool
IsStacktraceEnabled(Level) bool
}

273
vendor/github.com/mattermost/logr/format/json.go сгенерированный поставляемый
Просмотреть файл

@@ -1,273 +0,0 @@
package format
import (
"bytes"
"fmt"
"runtime"
"sort"
"sync"
"time"
"github.com/francoispqt/gojay"
"github.com/mattermost/logr"
)
// ContextField is a name/value pair within the context fields.
type ContextField struct {
Key string
Val interface{}
}
// JSON formats log records as JSON.
type JSON struct {
// DisableTimestamp disables output of timestamp field.
DisableTimestamp bool
// DisableLevel disables output of level field.
DisableLevel bool
// DisableMsg disables output of msg field.
DisableMsg bool
// DisableContext disables output of all context fields.
DisableContext bool
// DisableStacktrace disables output of stack trace.
DisableStacktrace bool
// TimestampFormat is an optional format for timestamps. If empty
// then DefTimestampFormat is used.
TimestampFormat string
// Deprecated: this has no effect.
Indent string
// EscapeHTML determines if certain characters (e.g. `<`, `>`, `&`)
// are escaped.
EscapeHTML bool
// KeyTimestamp overrides the timestamp field key name.
KeyTimestamp string
// KeyLevel overrides the level field key name.
KeyLevel string
// KeyMsg overrides the msg field key name.
KeyMsg string
// KeyContextFields when not empty will group all context fields
// under this key.
KeyContextFields string
// KeyStacktrace overrides the stacktrace field key name.
KeyStacktrace string
// ContextSorter allows custom sorting for the context fields.
ContextSorter func(fields logr.Fields) []ContextField
once sync.Once
}
// Format converts a log record to bytes in JSON format.
func (j *JSON) Format(rec *logr.LogRec, stacktrace bool, buf *bytes.Buffer) (*bytes.Buffer, error) {
j.once.Do(j.applyDefaultKeyNames)
if buf == nil {
buf = &bytes.Buffer{}
}
enc := gojay.BorrowEncoder(buf)
defer func() {
enc.Release()
}()
sorter := j.ContextSorter
if sorter == nil {
sorter = j.defaultContextSorter
}
jlr := JSONLogRec{
LogRec: rec,
JSON: j,
stacktrace: stacktrace,
sorter: sorter,
}
err := enc.EncodeObject(jlr)
if err != nil {
return nil, err
}
buf.WriteByte('\n')
return buf, nil
}
func (j *JSON) applyDefaultKeyNames() {
if j.KeyTimestamp == "" {
j.KeyTimestamp = "timestamp"
}
if j.KeyLevel == "" {
j.KeyLevel = "level"
}
if j.KeyMsg == "" {
j.KeyMsg = "msg"
}
if j.KeyStacktrace == "" {
j.KeyStacktrace = "stacktrace"
}
}
// defaultContextSorter sorts the context fields alphabetically by key.
func (j *JSON) defaultContextSorter(fields logr.Fields) []ContextField {
keys := make([]string, 0, len(fields))
for k := range fields {
keys = append(keys, k)
}
sort.Strings(keys)
cf := make([]ContextField, 0, len(keys))
for _, k := range keys {
cf = append(cf, ContextField{Key: k, Val: fields[k]})
}
return cf
}
// JSONLogRec decorates a LogRec adding JSON encoding.
type JSONLogRec struct {
*logr.LogRec
*JSON
stacktrace bool
sorter func(fields logr.Fields) []ContextField
}
// MarshalJSONObject encodes the LogRec as JSON.
func (rec JSONLogRec) MarshalJSONObject(enc *gojay.Encoder) {
if !rec.DisableTimestamp {
timestampFmt := rec.TimestampFormat
if timestampFmt == "" {
timestampFmt = logr.DefTimestampFormat
}
time := rec.Time()
enc.AddTimeKey(rec.KeyTimestamp, &time, timestampFmt)
}
if !rec.DisableLevel {
enc.AddStringKey(rec.KeyLevel, rec.Level().Name)
}
if !rec.DisableMsg {
enc.AddStringKey(rec.KeyMsg, rec.Msg())
}
if !rec.DisableContext {
ctxFields := rec.sorter(rec.Fields())
if rec.KeyContextFields != "" {
enc.AddObjectKey(rec.KeyContextFields, jsonFields(ctxFields))
} else {
if len(ctxFields) > 0 {
for _, cf := range ctxFields {
key := rec.prefixCollision(cf.Key)
encodeField(enc, key, cf.Val)
}
}
}
}
if rec.stacktrace && !rec.DisableStacktrace {
frames := rec.StackFrames()
if len(frames) > 0 {
enc.AddArrayKey(rec.KeyStacktrace, stackFrames(frames))
}
}
}
// IsNil returns true if the LogRec pointer is nil.
func (rec JSONLogRec) IsNil() bool {
return rec.LogRec == nil
}
func (rec JSONLogRec) prefixCollision(key string) string {
switch key {
case rec.KeyTimestamp, rec.KeyLevel, rec.KeyMsg, rec.KeyStacktrace:
return rec.prefixCollision("_" + key)
}
return key
}
type stackFrames []runtime.Frame
// MarshalJSONArray encodes stackFrames slice as JSON.
func (s stackFrames) MarshalJSONArray(enc *gojay.Encoder) {
for _, frame := range s {
enc.AddObject(stackFrame(frame))
}
}
// IsNil returns true if stackFrames is empty slice.
func (s stackFrames) IsNil() bool {
return len(s) == 0
}
type stackFrame runtime.Frame
// MarshalJSONArray encodes stackFrame as JSON.
func (f stackFrame) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddStringKey("Function", f.Function)
enc.AddStringKey("File", f.File)
enc.AddIntKey("Line", f.Line)
}
func (f stackFrame) IsNil() bool {
return false
}
type jsonFields []ContextField
// MarshalJSONObject encodes Fields map to JSON.
func (f jsonFields) MarshalJSONObject(enc *gojay.Encoder) {
for _, ctxField := range f {
encodeField(enc, ctxField.Key, ctxField.Val)
}
}
// IsNil returns true if map is nil.
func (f jsonFields) IsNil() bool {
return f == nil
}
func encodeField(enc *gojay.Encoder, key string, val interface{}) {
switch vt := val.(type) {
case gojay.MarshalerJSONObject:
enc.AddObjectKey(key, vt)
case gojay.MarshalerJSONArray:
enc.AddArrayKey(key, vt)
case string:
enc.AddStringKey(key, vt)
case error:
enc.AddStringKey(key, vt.Error())
case bool:
enc.AddBoolKey(key, vt)
case int:
enc.AddIntKey(key, vt)
case int64:
enc.AddInt64Key(key, vt)
case int32:
enc.AddIntKey(key, int(vt))
case int16:
enc.AddIntKey(key, int(vt))
case int8:
enc.AddIntKey(key, int(vt))
case uint64:
enc.AddIntKey(key, int(vt))
case uint32:
enc.AddIntKey(key, int(vt))
case uint16:
enc.AddIntKey(key, int(vt))
case uint8:
enc.AddIntKey(key, int(vt))
case float64:
enc.AddFloatKey(key, vt)
case float32:
enc.AddFloat32Key(key, vt)
case *gojay.EmbeddedJSON:
enc.AddEmbeddedJSONKey(key, vt)
case time.Time:
enc.AddTimeKey(key, &vt, logr.DefTimestampFormat)
case *time.Time:
enc.AddTimeKey(key, vt, logr.DefTimestampFormat)
default:
s := fmt.Sprintf("%v", vt)
enc.AddStringKey(key, s)
}
}

75
vendor/github.com/mattermost/logr/format/plain.go сгенерированный поставляемый
Просмотреть файл

@@ -1,75 +0,0 @@
package format
import (
"bytes"
"fmt"
"github.com/mattermost/logr"
)
// Plain is the simplest formatter, outputting only text with
// no colors.
type Plain struct {
// DisableTimestamp disables output of timestamp field.
DisableTimestamp bool
// DisableLevel disables output of level field.
DisableLevel bool
// DisableMsg disables output of msg field.
DisableMsg bool
// DisableContext disables output of all context fields.
DisableContext bool
// DisableStacktrace disables output of stack trace.
DisableStacktrace bool
// Delim is an optional delimiter output between each log field.
// Defaults to a single space.
Delim string
// TimestampFormat is an optional format for timestamps. If empty
// then DefTimestampFormat is used.
TimestampFormat string
}
// Format converts a log record to bytes.
func (p *Plain) Format(rec *logr.LogRec, stacktrace bool, buf *bytes.Buffer) (*bytes.Buffer, error) {
delim := p.Delim
if delim == "" {
delim = " "
}
if buf == nil {
buf = &bytes.Buffer{}
}
timestampFmt := p.TimestampFormat
if timestampFmt == "" {
timestampFmt = logr.DefTimestampFormat
}
if !p.DisableTimestamp {
var arr [128]byte
tbuf := rec.Time().AppendFormat(arr[:0], timestampFmt)
buf.Write(tbuf)
buf.WriteString(delim)
}
if !p.DisableLevel {
fmt.Fprintf(buf, "%v%s", rec.Level().Name, delim)
}
if !p.DisableMsg {
fmt.Fprint(buf, rec.Msg(), delim)
}
if !p.DisableContext {
ctx := rec.Fields()
if len(ctx) > 0 {
logr.WriteFields(buf, ctx, " ")
}
}
if stacktrace && !p.DisableStacktrace {
frames := rec.StackFrames()
if len(frames) > 0 {
buf.WriteString("\n")
logr.WriteStacktrace(buf, rec.StackFrames())
}
}
buf.WriteString("\n")
return buf, nil
}

119
vendor/github.com/mattermost/logr/formatter.go сгенерированный поставляемый
Просмотреть файл

@@ -1,119 +0,0 @@
package logr
import (
"bytes"
"fmt"
"io"
"runtime"
"sort"
)
// Formatter turns a LogRec into a formatted string.
type Formatter interface {
// Format converts a log record to bytes. If buf is not nil then it will be
// be filled with the formatted results, otherwise a new buffer will be allocated.
Format(rec *LogRec, stacktrace bool, buf *bytes.Buffer) (*bytes.Buffer, error)
}
const (
// DefTimestampFormat is the default time stamp format used by
// Plain formatter and others.
DefTimestampFormat = "2006-01-02 15:04:05.000 Z07:00"
)
// DefaultFormatter is the default formatter, outputting only text with
// no colors and a space delimiter. Use `format.Plain` instead.
type DefaultFormatter struct {
}
// Format converts a log record to bytes.
func (p *DefaultFormatter) Format(rec *LogRec, stacktrace bool, buf *bytes.Buffer) (*bytes.Buffer, error) {
if buf == nil {
buf = &bytes.Buffer{}
}
delim := " "
timestampFmt := DefTimestampFormat
fmt.Fprintf(buf, "%s%s", rec.Time().Format(timestampFmt), delim)
fmt.Fprintf(buf, "%v%s", rec.Level(), delim)
fmt.Fprint(buf, rec.Msg(), delim)
ctx := rec.Fields()
if len(ctx) > 0 {
WriteFields(buf, ctx, " ")
}
if stacktrace {
frames := rec.StackFrames()
if len(frames) > 0 {
buf.WriteString("\n")
WriteStacktrace(buf, rec.StackFrames())
}
}
buf.WriteString("\n")
return buf, nil
}
// WriteFields writes zero or more name value pairs to the io.Writer.
// The pairs are sorted by key name and output in key=value format
// with optional separator between fields.
func WriteFields(w io.Writer, flds Fields, separator string) {
keys := make([]string, 0, len(flds))
for k := range flds {
keys = append(keys, k)
}
sort.Strings(keys)
sep := ""
for _, key := range keys {
writeField(w, key, flds[key], sep)
sep = separator
}
}
func writeField(w io.Writer, key string, val interface{}, sep string) {
var template string
switch v := val.(type) {
case error:
val := v.Error()
if shouldQuote(val) {
template = "%s%s=%q"
} else {
template = "%s%s=%s"
}
case string:
if shouldQuote(v) {
template = "%s%s=%q"
} else {
template = "%s%s=%s"
}
default:
template = "%s%s=%v"
}
fmt.Fprintf(w, template, sep, key, val)
}
// shouldQuote returns true if val contains any characters that might be unsafe
// when injecting log output into an aggregator, viewer or report.
func shouldQuote(val string) bool {
for _, c := range val {
if !((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z')) {
return true
}
}
return false
}
// WriteStacktrace formats and outputs a stack trace to an io.Writer.
func WriteStacktrace(w io.Writer, frames []runtime.Frame) {
for _, frame := range frames {
if frame.Function != "" {
fmt.Fprintf(w, " %s\n", frame.Function)
}
if frame.File != "" {
fmt.Fprintf(w, " %s:%d\n", frame.File, frame.Line)
}
}
}

45
vendor/github.com/mattermost/logr/levelcustom.go сгенерированный поставляемый
Просмотреть файл

@@ -1,45 +0,0 @@
package logr
import (
"sync"
)
// CustomFilter allows targets to enable logging via a list of levels.
type CustomFilter struct {
mux sync.RWMutex
levels map[LevelID]Level
}
// IsEnabled returns true if the specified Level exists in this list.
func (st *CustomFilter) IsEnabled(level Level) bool {
st.mux.RLock()
defer st.mux.RUnlock()
_, ok := st.levels[level.ID]
return ok
}
// IsStacktraceEnabled returns true if the specified Level requires a stack trace.
func (st *CustomFilter) IsStacktraceEnabled(level Level) bool {
st.mux.RLock()
defer st.mux.RUnlock()
lvl, ok := st.levels[level.ID]
if ok {
return lvl.Stacktrace
}
return false
}
// Add adds one or more levels to the list. Adding a level enables logging for
// that level on any targets using this CustomFilter.
func (st *CustomFilter) Add(levels ...Level) {
st.mux.Lock()
defer st.mux.Unlock()
if st.levels == nil {
st.levels = make(map[LevelID]Level)
}
for _, s := range levels {
st.levels[s.ID] = s
}
}

37
vendor/github.com/mattermost/logr/levelstd.go сгенерированный поставляемый
Просмотреть файл

@@ -1,37 +0,0 @@
package logr
// StdFilter allows targets to filter via classic log levels where any level
// beyond a certain verbosity/severity is enabled.
type StdFilter struct {
Lvl Level
Stacktrace Level
}
// IsEnabled returns true if the specified Level is at or above this verbosity. Also
// determines if a stack trace is required.
func (lt StdFilter) IsEnabled(level Level) bool {
return level.ID <= lt.Lvl.ID
}
// IsStacktraceEnabled returns true if the specified Level requires a stack trace.
func (lt StdFilter) IsStacktraceEnabled(level Level) bool {
return level.ID <= lt.Stacktrace.ID
}
var (
// Panic is the highest level of severity. Logs the message and then panics.
Panic = Level{ID: 0, Name: "panic"}
// Fatal designates a catastrophic error. Logs the message and then calls
// `logr.Exit(1)`.
Fatal = Level{ID: 1, Name: "fatal"}
// Error designates a serious but possibly recoverable error.
Error = Level{ID: 2, Name: "error"}
// Warn designates non-critical error.
Warn = Level{ID: 3, Name: "warn"}
// Info designates information regarding application events.
Info = Level{ID: 4, Name: "info"}
// Debug designates verbose information typically used for debugging.
Debug = Level{ID: 5, Name: "debug"}
// Trace designates the highest verbosity of log output.
Trace = Level{ID: 6, Name: "trace"}
)

218
vendor/github.com/mattermost/logr/logger.go сгенерированный поставляемый
Просмотреть файл

@@ -1,218 +0,0 @@
package logr
import (
"fmt"
)
// Fields type, used to pass to `WithFields`.
type Fields map[string]interface{}
// Logger provides context for logging via fields.
type Logger struct {
logr *Logr
fields Fields
}
// Logr returns the `Logr` instance that created this `Logger`.
func (logger Logger) Logr() *Logr {
return logger.logr
}
// WithField creates a new `Logger` with any existing fields
// plus the new one.
func (logger Logger) WithField(key string, value interface{}) Logger {
return logger.WithFields(Fields{key: value})
}
// WithFields creates a new `Logger` with any existing fields
// plus the new ones.
func (logger Logger) WithFields(fields Fields) Logger {
l := Logger{logr: logger.logr}
// if parent has no fields then avoid creating a new map.
oldLen := len(logger.fields)
if oldLen == 0 {
l.fields = fields
return l
}
l.fields = make(Fields, len(fields)+oldLen)
for k, v := range logger.fields {
l.fields[k] = v
}
for k, v := range fields {
l.fields[k] = v
}
return l
}
// Log checks that the level matches one or more targets, and
// if so, generates a log record that is added to the Logr queue.
// Arguments are handled in the manner of fmt.Print.
func (logger Logger) Log(lvl Level, args ...interface{}) {
status := logger.logr.IsLevelEnabled(lvl)
if status.Enabled {
rec := NewLogRec(lvl, logger, "", args, status.Stacktrace)
logger.logr.enqueue(rec)
}
}
// Trace is a convenience method equivalent to `Log(TraceLevel, args...)`.
func (logger Logger) Trace(args ...interface{}) {
logger.Log(Trace, args...)
}
// Debug is a convenience method equivalent to `Log(DebugLevel, args...)`.
func (logger Logger) Debug(args ...interface{}) {
logger.Log(Debug, args...)
}
// Print ensures compatibility with std lib logger.
func (logger Logger) Print(args ...interface{}) {
logger.Info(args...)
}
// Info is a convenience method equivalent to `Log(InfoLevel, args...)`.
func (logger Logger) Info(args ...interface{}) {
logger.Log(Info, args...)
}
// Warn is a convenience method equivalent to `Log(WarnLevel, args...)`.
func (logger Logger) Warn(args ...interface{}) {
logger.Log(Warn, args...)
}
// Error is a convenience method equivalent to `Log(ErrorLevel, args...)`.
func (logger Logger) Error(args ...interface{}) {
logger.Log(Error, args...)
}
// Fatal is a convenience method equivalent to `Log(FatalLevel, args...)`
// followed by a call to os.Exit(1).
func (logger Logger) Fatal(args ...interface{}) {
logger.Log(Fatal, args...)
logger.logr.exit(1)
}
// Panic is a convenience method equivalent to `Log(PanicLevel, args...)`
// followed by a call to panic().
func (logger Logger) Panic(args ...interface{}) {
logger.Log(Panic, args...)
panic(fmt.Sprint(args...))
}
//
// Printf style
//
// Logf checks that the level matches one or more targets, and
// if so, generates a log record that is added to the main
// queue (channel). Arguments are handled in the manner of fmt.Printf.
func (logger Logger) Logf(lvl Level, format string, args ...interface{}) {
status := logger.logr.IsLevelEnabled(lvl)
if status.Enabled {
rec := NewLogRec(lvl, logger, format, args, status.Stacktrace)
logger.logr.enqueue(rec)
}
}
// Tracef is a convenience method equivalent to `Logf(TraceLevel, args...)`.
func (logger Logger) Tracef(format string, args ...interface{}) {
logger.Logf(Trace, format, args...)
}
// Debugf is a convenience method equivalent to `Logf(DebugLevel, args...)`.
func (logger Logger) Debugf(format string, args ...interface{}) {
logger.Logf(Debug, format, args...)
}
// Infof is a convenience method equivalent to `Logf(InfoLevel, args...)`.
func (logger Logger) Infof(format string, args ...interface{}) {
logger.Logf(Info, format, args...)
}
// Printf ensures compatibility with std lib logger.
func (logger Logger) Printf(format string, args ...interface{}) {
logger.Infof(format, args...)
}
// Warnf is a convenience method equivalent to `Logf(WarnLevel, args...)`.
func (logger Logger) Warnf(format string, args ...interface{}) {
logger.Logf(Warn, format, args...)
}
// Errorf is a convenience method equivalent to `Logf(ErrorLevel, args...)`.
func (logger Logger) Errorf(format string, args ...interface{}) {
logger.Logf(Error, format, args...)
}
// Fatalf is a convenience method equivalent to `Logf(FatalLevel, args...)`
// followed by a call to os.Exit(1).
func (logger Logger) Fatalf(format string, args ...interface{}) {
logger.Logf(Fatal, format, args...)
logger.logr.exit(1)
}
// Panicf is a convenience method equivalent to `Logf(PanicLevel, args...)`
// followed by a call to panic().
func (logger Logger) Panicf(format string, args ...interface{}) {
logger.Logf(Panic, format, args...)
}
//
// Println style
//
// Logln checks that the level matches one or more targets, and
// if so, generates a log record that is added to the main
// queue (channel). Arguments are handled in the manner of fmt.Println.
func (logger Logger) Logln(lvl Level, args ...interface{}) {
status := logger.logr.IsLevelEnabled(lvl)
if status.Enabled {
rec := NewLogRec(lvl, logger, "", args, status.Stacktrace)
rec.newline = true
logger.logr.enqueue(rec)
}
}
// Traceln is a convenience method equivalent to `Logln(TraceLevel, args...)`.
func (logger Logger) Traceln(args ...interface{}) {
logger.Logln(Trace, args...)
}
// Debugln is a convenience method equivalent to `Logln(DebugLevel, args...)`.
func (logger Logger) Debugln(args ...interface{}) {
logger.Logln(Debug, args...)
}
// Infoln is a convenience method equivalent to `Logln(InfoLevel, args...)`.
func (logger Logger) Infoln(args ...interface{}) {
logger.Logln(Info, args...)
}
// Println ensures compatibility with std lib logger.
func (logger Logger) Println(args ...interface{}) {
logger.Infoln(args...)
}
// Warnln is a convenience method equivalent to `Logln(WarnLevel, args...)`.
func (logger Logger) Warnln(args ...interface{}) {
logger.Logln(Warn, args...)
}
// Errorln is a convenience method equivalent to `Logln(ErrorLevel, args...)`.
func (logger Logger) Errorln(args ...interface{}) {
logger.Logln(Error, args...)
}
// Fatalln is a convenience method equivalent to `Logln(FatalLevel, args...)`
// followed by a call to os.Exit(1).
func (logger Logger) Fatalln(args ...interface{}) {
logger.Logln(Fatal, args...)
logger.logr.exit(1)
}
// Panicln is a convenience method equivalent to `Logln(PanicLevel, args...)`
// followed by a call to panic().
func (logger Logger) Panicln(args ...interface{}) {
logger.Logln(Panic, args...)
}

664
vendor/github.com/mattermost/logr/logr.go сгенерированный поставляемый
Просмотреть файл

@@ -1,664 +0,0 @@
package logr
import (
"bytes"
"context"
"errors"
"fmt"
"os"
"sync"
"time"
"github.com/wiggin77/cfg"
"github.com/wiggin77/merror"
)
// Logr maintains a list of log targets and accepts incoming
// log records.
type Logr struct {
tmux sync.RWMutex // target mutex
targets []Target
mux sync.RWMutex
maxQueueSizeActual int
in chan *LogRec
done chan struct{}
once sync.Once
shutdown bool
lvlCache levelCache
metricsInitOnce sync.Once
metricsCloseOnce sync.Once
metricsDone chan struct{}
metrics MetricsCollector
queueSizeGauge Gauge
loggedCounter Counter
errorCounter Counter
bufferPool sync.Pool
// MaxQueueSize is the maximum number of log records that can be queued.
// If exceeded, `OnQueueFull` is called which determines if the log
// record will be dropped or block until add is successful.
// If this is modified, it must be done before `Configure` or
// `AddTarget`. Defaults to DefaultMaxQueueSize.
MaxQueueSize int
// OnLoggerError, when not nil, is called any time an internal
// logging error occurs. For example, this can happen when a
// target cannot connect to its data sink.
OnLoggerError func(error)
// OnQueueFull, when not nil, is called on an attempt to add
// a log record to a full Logr queue.
// `MaxQueueSize` can be used to modify the maximum queue size.
// This function should return quickly, with a bool indicating whether
// the log record should be dropped (true) or block until the log record
// is successfully added (false). If nil then blocking (false) is assumed.
OnQueueFull func(rec *LogRec, maxQueueSize int) bool
// OnTargetQueueFull, when not nil, is called on an attempt to add
// a log record to a full target queue provided the target supports reporting
// this condition.
// This function should return quickly, with a bool indicating whether
// the log record should be dropped (true) or block until the log record
// is successfully added (false). If nil then blocking (false) is assumed.
OnTargetQueueFull func(target Target, rec *LogRec, maxQueueSize int) bool
// OnExit, when not nil, is called when a FatalXXX style log API is called.
// When nil, then the default behavior is to cleanly shut down this Logr and
// call `os.Exit(code)`.
OnExit func(code int)
// OnPanic, when not nil, is called when a PanicXXX style log API is called.
// When nil, then the default behavior is to cleanly shut down this Logr and
// call `panic(err)`.
OnPanic func(err interface{})
// EnqueueTimeout is the amount of time a log record can take to be queued.
// This only applies to blocking enqueue which happen after `logr.OnQueueFull`
// is called and returns false.
EnqueueTimeout time.Duration
// ShutdownTimeout is the amount of time `logr.Shutdown` can execute before
// timing out.
ShutdownTimeout time.Duration
// FlushTimeout is the amount of time `logr.Flush` can execute before
// timing out.
FlushTimeout time.Duration
// UseSyncMapLevelCache can be set to true before the first target is added
// when high concurrency (e.g. >32 cores) is expected. This may improve
// performance with large numbers of cores - benchmark for your use case.
UseSyncMapLevelCache bool
// MaxPooledFormatBuffer determines the maximum size of a buffer that can be
// pooled. To reduce allocations, the buffers needed during formatting (etc)
// are pooled. A very large log item will grow a buffer that could stay in
// memory indefinitely. This settings lets you control how big a pooled buffer
// can be - anything larger will be garbage collected after use.
// Defaults to 1MB.
MaxPooledBuffer int
// DisableBufferPool when true disables the buffer pool. See MaxPooledBuffer.
DisableBufferPool bool
// MetricsUpdateFreqMillis determines how often polled metrics are updated
// when metrics are enabled.
MetricsUpdateFreqMillis int64
}
// Configure adds/removes targets via the supplied `Config`.
func (logr *Logr) Configure(config *cfg.Config) error {
// TODO
return fmt.Errorf("not implemented yet")
}
func (logr *Logr) ensureInit() {
logr.once.Do(func() {
defer func() {
go logr.start()
}()
logr.mux.Lock()
defer logr.mux.Unlock()
logr.maxQueueSizeActual = logr.MaxQueueSize
if logr.maxQueueSizeActual == 0 {
logr.maxQueueSizeActual = DefaultMaxQueueSize
}
if logr.maxQueueSizeActual < 0 {
logr.maxQueueSizeActual = 0
}
logr.in = make(chan *LogRec, logr.maxQueueSizeActual)
logr.done = make(chan struct{})
if logr.UseSyncMapLevelCache {
logr.lvlCache = &syncMapLevelCache{}
} else {
logr.lvlCache = &arrayLevelCache{}
}
if logr.MaxPooledBuffer == 0 {
logr.MaxPooledBuffer = DefaultMaxPooledBuffer
}
logr.bufferPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
logr.lvlCache.setup()
})
}
// AddTarget adds one or more targets to the logger which will receive
// log records for outputting.
func (logr *Logr) AddTarget(targets ...Target) error {
if logr.IsShutdown() {
return fmt.Errorf("AddTarget called after Logr shut down")
}
logr.ensureInit()
metrics := logr.getMetricsCollector()
defer logr.ResetLevelCache() // call this after tmux is released
logr.tmux.Lock()
defer logr.tmux.Unlock()
errs := merror.New()
for _, t := range targets {
if t == nil {
continue
}
logr.targets = append(logr.targets, t)
if metrics != nil {
if tm, ok := t.(TargetWithMetrics); ok {
if err := tm.EnableMetrics(metrics, logr.MetricsUpdateFreqMillis); err != nil {
errs.Append(err)
}
}
}
}
return errs.ErrorOrNil()
}
// NewLogger creates a Logger using defaults. A `Logger` is light-weight
// enough to create on-demand, but typically one or more Loggers are
// created and re-used.
func (logr *Logr) NewLogger() Logger {
logger := Logger{logr: logr}
return logger
}
var levelStatusDisabled = LevelStatus{}
// IsLevelEnabled returns true if at least one target has the specified
// level enabled. The result is cached so that subsequent checks are fast.
func (logr *Logr) IsLevelEnabled(lvl Level) LevelStatus {
status, ok := logr.isLevelEnabledFromCache(lvl)
if ok {
return status
}
// Check each target.
logr.tmux.RLock()
for _, t := range logr.targets {
e, s := t.IsLevelEnabled(lvl)
if e {
status.Enabled = true
if s {
status.Stacktrace = true
break // if both enabled then no sense checking more targets
}
}
}
logr.tmux.RUnlock()
// Cache and return the result.
if err := logr.updateLevelCache(lvl.ID, status); err != nil {
logr.ReportError(err)
return LevelStatus{}
}
return status
}
func (logr *Logr) isLevelEnabledFromCache(lvl Level) (LevelStatus, bool) {
logr.mux.RLock()
defer logr.mux.RUnlock()
// Don't accept new log records after shutdown.
if logr.shutdown {
return levelStatusDisabled, true
}
// Check cache. lvlCache may still be nil if no targets added.
if logr.lvlCache == nil {
return levelStatusDisabled, true
}
status, ok := logr.lvlCache.get(lvl.ID)
if ok {
return status, true
}
return LevelStatus{}, false
}
func (logr *Logr) updateLevelCache(id LevelID, status LevelStatus) error {
logr.mux.RLock()
defer logr.mux.RUnlock()
if logr.lvlCache != nil {
return logr.lvlCache.put(id, status)
}
return nil
}
// HasTargets returns true only if at least one target exists within the Logr.
func (logr *Logr) HasTargets() bool {
logr.tmux.RLock()
defer logr.tmux.RUnlock()
return len(logr.targets) > 0
}
// TargetInfo provides name and type for a Target.
type TargetInfo struct {
Name string
Type string
}
// TargetInfos enumerates all the targets added to this Logr.
// The resulting slice represents a snapshot at time of calling.
func (logr *Logr) TargetInfos() []TargetInfo {
logr.tmux.RLock()
defer logr.tmux.RUnlock()
infos := make([]TargetInfo, 0)
for _, t := range logr.targets {
inf := TargetInfo{
Name: fmt.Sprintf("%v", t),
Type: fmt.Sprintf("%T", t),
}
infos = append(infos, inf)
}
return infos
}
// RemoveTargets safely removes one or more targets based on the filtering method.
// f should return true to delete the target, false to keep it.
// When removing a target, best effort is made to write any queued log records before
// closing, with cxt determining how much time can be spent in total.
// Note, keep the timeout short since this method blocks certain logging operations.
func (logr *Logr) RemoveTargets(cxt context.Context, f func(ti TargetInfo) bool) error {
var removed bool
defer func() {
if removed {
// call this after tmux is released since
// it will lock mux and we don't want to
// introduce possible deadlock.
logr.ResetLevelCache()
}
}()
errs := merror.New()
logr.tmux.Lock()
defer logr.tmux.Unlock()
cp := make([]Target, 0)
for _, t := range logr.targets {
inf := TargetInfo{
Name: fmt.Sprintf("%v", t),
Type: fmt.Sprintf("%T", t),
}
if f(inf) {
if err := t.Shutdown(cxt); err != nil {
errs.Append(err)
}
removed = true
} else {
cp = append(cp, t)
}
}
logr.targets = cp
return errs.ErrorOrNil()
}
// ResetLevelCache resets the cached results of `IsLevelEnabled`. This is
// called any time a Target is added or a target's level is changed.
func (logr *Logr) ResetLevelCache() {
// Write lock so that new cache entries cannot be stored while we
// clear the cache.
logr.mux.Lock()
defer logr.mux.Unlock()
logr.resetLevelCache()
}
// resetLevelCache empties the level cache without locking.
// mux.Lock must be held before calling this function.
func (logr *Logr) resetLevelCache() {
// lvlCache may still be nil if no targets added.
if logr.lvlCache != nil {
logr.lvlCache.clear()
}
}
// enqueue adds a log record to the logr queue. If the queue is full then
// this function either blocks or the log record is dropped, depending on
// the result of calling `OnQueueFull`.
func (logr *Logr) enqueue(rec *LogRec) {
if logr.in == nil {
logr.ReportError(fmt.Errorf("AddTarget or Configure must be called before enqueue"))
}
select {
case logr.in <- rec:
default:
if logr.OnQueueFull != nil && logr.OnQueueFull(rec, logr.maxQueueSizeActual) {
return // drop the record
}
select {
case <-time.After(logr.enqueueTimeout()):
logr.ReportError(fmt.Errorf("enqueue timed out for log rec [%v]", rec))
case logr.in <- rec: // block until success or timeout
}
}
}
// exit is called by one of the FatalXXX style APIS. If `logr.OnExit` is not nil
// then that method is called, otherwise the default behavior is to shut down this
// Logr cleanly then call `os.Exit(code)`.
func (logr *Logr) exit(code int) {
if logr.OnExit != nil {
logr.OnExit(code)
return
}
if err := logr.Shutdown(); err != nil {
logr.ReportError(err)
}
os.Exit(code)
}
// panic is called by one of the PanicXXX style APIS. If `logr.OnPanic` is not nil
// then that method is called, otherwise the default behavior is to shut down this
// Logr cleanly then call `panic(err)`.
func (logr *Logr) panic(err interface{}) {
if logr.OnPanic != nil {
logr.OnPanic(err)
return
}
if err := logr.Shutdown(); err != nil {
logr.ReportError(err)
}
panic(err)
}
// Flush blocks while flushing the logr queue and all target queues, by
// writing existing log records to valid targets.
// Any attempts to add new log records will block until flush is complete.
// `logr.FlushTimeout` determines how long flush can execute before
// timing out. Use `IsTimeoutError` to determine if the returned error is
// due to a timeout.
func (logr *Logr) Flush() error {
ctx, cancel := context.WithTimeout(context.Background(), logr.flushTimeout())
defer cancel()
return logr.FlushWithTimeout(ctx)
}
// Flush blocks while flushing the logr queue and all target queues, by
// writing existing log records to valid targets.
// Any attempts to add new log records will block until flush is complete.
// Use `IsTimeoutError` to determine if the returned error is
// due to a timeout.
func (logr *Logr) FlushWithTimeout(ctx context.Context) error {
if !logr.HasTargets() {
return nil
}
if logr.IsShutdown() {
return errors.New("Flush called on shut down Logr")
}
rec := newFlushLogRec(logr.NewLogger())
logr.enqueue(rec)
select {
case <-ctx.Done():
return newTimeoutError("logr queue shutdown timeout")
case <-rec.flush:
}
return nil
}
// IsShutdown returns true if this Logr instance has been shut down.
// No further log records can be enqueued and no targets added after
// shutdown.
func (logr *Logr) IsShutdown() bool {
logr.mux.Lock()
defer logr.mux.Unlock()
return logr.shutdown
}
// Shutdown cleanly stops the logging engine after making best efforts
// to flush all targets. Call this function right before application
// exit - logr cannot be restarted once shut down.
// `logr.ShutdownTimeout` determines how long shutdown can execute before
// timing out. Use `IsTimeoutError` to determine if the returned error is
// due to a timeout.
func (logr *Logr) Shutdown() error {
ctx, cancel := context.WithTimeout(context.Background(), logr.shutdownTimeout())
defer cancel()
return logr.ShutdownWithTimeout(ctx)
}
// Shutdown cleanly stops the logging engine after making best efforts
// to flush all targets. Call this function right before application
// exit - logr cannot be restarted once shut down.
// Use `IsTimeoutError` to determine if the returned error is due to a
// timeout.
func (logr *Logr) ShutdownWithTimeout(ctx context.Context) error {
logr.mux.Lock()
if logr.shutdown {
logr.mux.Unlock()
return errors.New("Shutdown called again after shut down")
}
logr.shutdown = true
logr.resetLevelCache()
logr.mux.Unlock()
logr.metricsCloseOnce.Do(func() {
if logr.metricsDone != nil {
close(logr.metricsDone)
}
})
errs := merror.New()
// close the incoming channel and wait for read loop to exit.
if logr.in != nil {
close(logr.in)
select {
case <-ctx.Done():
errs.Append(newTimeoutError("logr queue shutdown timeout"))
case <-logr.done:
}
}
// logr.in channel should now be drained to targets and no more log records
// can be added.
logr.tmux.RLock()
defer logr.tmux.RUnlock()
for _, t := range logr.targets {
err := t.Shutdown(ctx)
if err != nil {
errs.Append(err)
}
}
return errs.ErrorOrNil()
}
// ReportError is used to notify the host application of any internal logging errors.
// If `OnLoggerError` is not nil, it is called with the error, otherwise the error is
// output to `os.Stderr`.
func (logr *Logr) ReportError(err interface{}) {
logr.incErrorCounter()
if logr.OnLoggerError == nil {
fmt.Fprintln(os.Stderr, err)
return
}
logr.OnLoggerError(fmt.Errorf("%v", err))
}
// BorrowBuffer borrows a buffer from the pool. Release the buffer to reduce garbage collection.
func (logr *Logr) BorrowBuffer() *bytes.Buffer {
if logr.DisableBufferPool {
return &bytes.Buffer{}
}
return logr.bufferPool.Get().(*bytes.Buffer)
}
// ReleaseBuffer returns a buffer to the pool to reduce garbage collection. The buffer is only
// retained if less than MaxPooledBuffer.
func (logr *Logr) ReleaseBuffer(buf *bytes.Buffer) {
if !logr.DisableBufferPool && buf.Cap() < logr.MaxPooledBuffer {
buf.Reset()
logr.bufferPool.Put(buf)
}
}
// enqueueTimeout returns amount of time a log record can take to be queued.
// This only applies to blocking enqueue which happen after `logr.OnQueueFull` is called
// and returns false.
func (logr *Logr) enqueueTimeout() time.Duration {
if logr.EnqueueTimeout == 0 {
return DefaultEnqueueTimeout
}
return logr.EnqueueTimeout
}
// shutdownTimeout returns the timeout duration for `logr.Shutdown`.
func (logr *Logr) shutdownTimeout() time.Duration {
if logr.ShutdownTimeout == 0 {
return DefaultShutdownTimeout
}
return logr.ShutdownTimeout
}
// flushTimeout returns the timeout duration for `logr.Flush`.
func (logr *Logr) flushTimeout() time.Duration {
if logr.FlushTimeout == 0 {
return DefaultFlushTimeout
}
return logr.FlushTimeout
}
// start selects on incoming log records until done channel signals.
// Incoming log records are fanned out to all log targets.
func (logr *Logr) start() {
defer func() {
if r := recover(); r != nil {
logr.ReportError(r)
go logr.start()
}
}()
for rec := range logr.in {
if rec.flush != nil {
logr.flush(rec.flush)
} else {
rec.prep()
logr.fanout(rec)
}
}
close(logr.done)
}
// startMetricsUpdater updates the metrics for any polled values every `MetricsUpdateFreqSecs` seconds until
// logr is closed.
func (logr *Logr) startMetricsUpdater() {
for {
updateFreq := logr.getMetricsUpdateFreqMillis()
if updateFreq == 0 {
updateFreq = DefMetricsUpdateFreqMillis
}
if updateFreq < 250 {
updateFreq = 250 // don't peg the CPU
}
select {
case <-logr.metricsDone:
return
case <-time.After(time.Duration(updateFreq) * time.Millisecond):
logr.setQueueSizeGauge(float64(len(logr.in)))
}
}
}
func (logr *Logr) getMetricsUpdateFreqMillis() int64 {
logr.mux.RLock()
defer logr.mux.RUnlock()
return logr.MetricsUpdateFreqMillis
}
// fanout pushes a LogRec to all targets.
func (logr *Logr) fanout(rec *LogRec) {
var target Target
defer func() {
if r := recover(); r != nil {
logr.ReportError(fmt.Errorf("fanout failed for target %s, %v", target, r))
}
}()
var logged bool
defer func() {
if logged {
logr.incLoggedCounter() // call this after tmux is released
}
}()
logr.tmux.RLock()
defer logr.tmux.RUnlock()
for _, target = range logr.targets {
if enabled, _ := target.IsLevelEnabled(rec.Level()); enabled {
target.Log(rec)
logged = true
}
}
}
// flush drains the queue and notifies when done.
func (logr *Logr) flush(done chan<- struct{}) {
// first drain the logr queue.
loop:
for {
var rec *LogRec
select {
case rec = <-logr.in:
if rec.flush == nil {
rec.prep()
logr.fanout(rec)
}
default:
break loop
}
}
logger := logr.NewLogger()
// drain all the targets; block until finished.
logr.tmux.RLock()
defer logr.tmux.RUnlock()
for _, target := range logr.targets {
rec := newFlushLogRec(logger)
target.Log(rec)
<-rec.flush
}
done <- struct{}{}
}

299
vendor/github.com/mattermost/logr/target.go сгенерированный поставляемый
Просмотреть файл

@@ -1,299 +0,0 @@
package logr
import (
"context"
"fmt"
"os"
"sync"
"time"
)
// Target represents a destination for log records such as file,
// database, TCP socket, etc.
type Target interface {
// SetName provides an optional name for the target.
SetName(name string)
// IsLevelEnabled returns true if this target should emit
// logs for the specified level. Also determines if
// a stack trace is required.
IsLevelEnabled(Level) (enabled bool, stacktrace bool)
// Formatter returns the Formatter associated with this Target.
Formatter() Formatter
// Log outputs the log record to this target's destination.
Log(rec *LogRec)
// Shutdown makes best effort to flush target queue and
// frees/closes all resources.
Shutdown(ctx context.Context) error
}
// RecordWriter can convert a LogRecord to bytes and output to some data sink.
type RecordWriter interface {
Write(rec *LogRec) error
}
// Basic provides the basic functionality of a Target that can be used
// to more easily compose your own Targets. To use, just embed Basic
// in your target type, implement `RecordWriter`, and call `(*Basic).Start`.
type Basic struct {
target Target
filter Filter
formatter Formatter
in chan *LogRec
done chan struct{}
w RecordWriter
mux sync.RWMutex
name string
metrics bool
queueSizeGauge Gauge
loggedCounter Counter
errorCounter Counter
droppedCounter Counter
blockedCounter Counter
metricsUpdateFreqMillis int64
}
// Start initializes this target helper and starts accepting log records for processing.
func (b *Basic) Start(target Target, rw RecordWriter, filter Filter, formatter Formatter, maxQueued int) {
if filter == nil {
filter = &StdFilter{Lvl: Fatal}
}
if formatter == nil {
formatter = &DefaultFormatter{}
}
b.target = target
b.filter = filter
b.formatter = formatter
b.in = make(chan *LogRec, maxQueued)
b.done = make(chan struct{}, 1)
b.w = rw
go b.start()
if b.hasMetrics() {
go b.startMetricsUpdater()
}
}
func (b *Basic) SetName(name string) {
b.mux.Lock()
defer b.mux.Unlock()
b.name = name
}
// IsLevelEnabled returns true if this target should emit
// logs for the specified level. Also determines if
// a stack trace is required.
func (b *Basic) IsLevelEnabled(lvl Level) (enabled bool, stacktrace bool) {
return b.filter.IsEnabled(lvl), b.filter.IsStacktraceEnabled(lvl)
}
// Formatter returns the Formatter associated with this Target.
func (b *Basic) Formatter() Formatter {
return b.formatter
}
// Shutdown stops processing log records after making best
// effort to flush queue.
func (b *Basic) Shutdown(ctx context.Context) error {
// close the incoming channel and wait for read loop to exit.
close(b.in)
select {
case <-ctx.Done():
case <-b.done:
}
// b.in channel should now be drained.
return nil
}
// Log outputs the log record to this targets destination.
func (b *Basic) Log(rec *LogRec) {
lgr := rec.Logger().Logr()
select {
case b.in <- rec:
default:
handler := lgr.OnTargetQueueFull
if handler != nil && handler(b.target, rec, cap(b.in)) {
b.incDroppedCounter()
return // drop the record
}
b.incBlockedCounter()
select {
case <-time.After(lgr.enqueueTimeout()):
lgr.ReportError(fmt.Errorf("target enqueue timeout for log rec [%v]", rec))
case b.in <- rec: // block until success or timeout
}
}
}
// Metrics enables metrics collection using the provided MetricsCollector.
func (b *Basic) EnableMetrics(collector MetricsCollector, updateFreqMillis int64) error {
name := fmt.Sprintf("%v", b)
b.mux.Lock()
defer b.mux.Unlock()
b.metrics = true
b.metricsUpdateFreqMillis = updateFreqMillis
var err error
if b.queueSizeGauge, err = collector.QueueSizeGauge(name); err != nil {
return err
}
if b.loggedCounter, err = collector.LoggedCounter(name); err != nil {
return err
}
if b.errorCounter, err = collector.ErrorCounter(name); err != nil {
return err
}
if b.droppedCounter, err = collector.DroppedCounter(name); err != nil {
return err
}
if b.blockedCounter, err = collector.BlockedCounter(name); err != nil {
return err
}
return nil
}
func (b *Basic) hasMetrics() bool {
b.mux.RLock()
defer b.mux.RUnlock()
return b.metrics
}
func (b *Basic) setQueueSizeGauge(val float64) {
b.mux.RLock()
defer b.mux.RUnlock()
if b.queueSizeGauge != nil {
b.queueSizeGauge.Set(val)
}
}
func (b *Basic) incLoggedCounter() {
b.mux.RLock()
defer b.mux.RUnlock()
if b.loggedCounter != nil {
b.loggedCounter.Inc()
}
}
func (b *Basic) incErrorCounter() {
b.mux.RLock()
defer b.mux.RUnlock()
if b.errorCounter != nil {
b.errorCounter.Inc()
}
}
func (b *Basic) incDroppedCounter() {
b.mux.RLock()
defer b.mux.RUnlock()
if b.droppedCounter != nil {
b.droppedCounter.Inc()
}
}
func (b *Basic) incBlockedCounter() {
b.mux.RLock()
defer b.mux.RUnlock()
if b.blockedCounter != nil {
b.blockedCounter.Inc()
}
}
// String returns a name for this target. Use `SetName` to specify a name.
func (b *Basic) String() string {
b.mux.RLock()
defer b.mux.RUnlock()
if b.name != "" {
return b.name
}
return fmt.Sprintf("%T", b.target)
}
// Start accepts log records via In channel and writes to the
// supplied writer, until Done channel signaled.
func (b *Basic) start() {
defer func() {
if r := recover(); r != nil {
fmt.Fprintln(os.Stderr, "Basic.start -- ", r)
go b.start()
}
}()
for rec := range b.in {
if rec.flush != nil {
b.flush(rec.flush)
} else {
err := b.w.Write(rec)
if err != nil {
b.incErrorCounter()
rec.Logger().Logr().ReportError(err)
} else {
b.incLoggedCounter()
}
}
}
close(b.done)
}
// startMetricsUpdater updates the metrics for any polled values every `MetricsUpdateFreqSecs` seconds until
// target is closed.
func (b *Basic) startMetricsUpdater() {
for {
updateFreq := b.getMetricsUpdateFreqMillis()
if updateFreq == 0 {
updateFreq = DefMetricsUpdateFreqMillis
}
if updateFreq < 250 {
updateFreq = 250 // don't peg the CPU
}
select {
case <-b.done:
return
case <-time.After(time.Duration(updateFreq) * time.Millisecond):
b.setQueueSizeGauge(float64(len(b.in)))
}
}
}
func (b *Basic) getMetricsUpdateFreqMillis() int64 {
b.mux.RLock()
defer b.mux.RUnlock()
return b.metricsUpdateFreqMillis
}
// flush drains the queue and notifies when done.
func (b *Basic) flush(done chan<- struct{}) {
for {
var rec *LogRec
var err error
select {
case rec = <-b.in:
// ignore any redundant flush records.
if rec.flush == nil {
err = b.w.Write(rec)
if err != nil {
b.incErrorCounter()
rec.Logger().Logr().ReportError(err)
}
}
default:
done <- struct{}{}
return
}
}
}

89
vendor/github.com/mattermost/logr/target/syslog.go сгенерированный поставляемый
Просмотреть файл

@@ -1,89 +0,0 @@
// +build !windows,!nacl,!plan9
package target
import (
"context"
"fmt"
"log/syslog"
"github.com/mattermost/logr"
"github.com/wiggin77/merror"
)
// Syslog outputs log records to local or remote syslog.
type Syslog struct {
logr.Basic
w *syslog.Writer
}
// SyslogParams provides parameters for dialing a syslog daemon.
type SyslogParams struct {
Network string
Raddr string
Priority syslog.Priority
Tag string
}
// NewSyslogTarget creates a target capable of outputting log records to remote or local syslog.
func NewSyslogTarget(filter logr.Filter, formatter logr.Formatter, params *SyslogParams, maxQueue int) (*Syslog, error) {
writer, err := syslog.Dial(params.Network, params.Raddr, params.Priority, params.Tag)
if err != nil {
return nil, err
}
s := &Syslog{w: writer}
s.Basic.Start(s, s, filter, formatter, maxQueue)
return s, nil
}
// Shutdown stops processing log records after making best
// effort to flush queue.
func (s *Syslog) Shutdown(ctx context.Context) error {
errs := merror.New()
err := s.Basic.Shutdown(ctx)
errs.Append(err)
err = s.w.Close()
errs.Append(err)
return errs.ErrorOrNil()
}
// Write converts the log record to bytes, via the Formatter,
// and outputs to syslog.
func (s *Syslog) Write(rec *logr.LogRec) error {
_, stacktrace := s.IsLevelEnabled(rec.Level())
buf := rec.Logger().Logr().BorrowBuffer()
defer rec.Logger().Logr().ReleaseBuffer(buf)
buf, err := s.Formatter().Format(rec, stacktrace, buf)
if err != nil {
return err
}
txt := buf.String()
switch rec.Level() {
case logr.Panic, logr.Fatal:
err = s.w.Crit(txt)
case logr.Error:
err = s.w.Err(txt)
case logr.Warn:
err = s.w.Warning(txt)
case logr.Debug, logr.Trace:
err = s.w.Debug(txt)
default:
// logr.Info plus all custom levels.
err = s.w.Info(txt)
}
if err != nil {
reporter := rec.Logger().Logr().ReportError
reporter(fmt.Errorf("syslog write fail: %w", err))
// syslog writer will try to reconnect.
}
return err
}

40
vendor/github.com/mattermost/logr/target/writer.go сгенерированный поставляемый
Просмотреть файл

@@ -1,40 +0,0 @@
package target
import (
"io"
"io/ioutil"
"github.com/mattermost/logr"
)
// Writer outputs log records to any `io.Writer`.
type Writer struct {
logr.Basic
out io.Writer
}
// NewWriterTarget creates a target capable of outputting log records to an io.Writer.
func NewWriterTarget(filter logr.Filter, formatter logr.Formatter, out io.Writer, maxQueue int) *Writer {
if out == nil {
out = ioutil.Discard
}
w := &Writer{out: out}
w.Basic.Start(w, w, filter, formatter, maxQueue)
return w
}
// Write converts the log record to bytes, via the Formatter,
// and outputs to the io.Writer.
func (w *Writer) Write(rec *logr.LogRec) error {
_, stacktrace := w.IsLevelEnabled(rec.Level())
buf := rec.Logger().Logr().BorrowBuffer()
defer rec.Logger().Logr().ReleaseBuffer(buf)
buf, err := w.Formatter().Format(rec, stacktrace, buf)
if err != nil {
return err
}
_, err = w.out.Write(buf.Bytes())
return err
}

Просмотреть файл

@@ -34,3 +34,4 @@ logs
# test apps
test/cmd/testapp1/testapp1
test/cmd/simple/simple
test/cmd/gelf/gelf

Просмотреть файл

0
vendor/github.com/mattermost/logr/LICENSE → vendor/github.com/mattermost/logr/v2/LICENSE сгенерированный поставляемый
Просмотреть файл

Просмотреть файл

@@ -16,9 +16,9 @@ It is very much inspired by [Logrus](https://github.com/sirupsen/logrus) but add
<!-- markdownlint-disable MD033 -->
| entity | description |
| ------ | ----------- |
| Logr | Engine instance typically instantiated once; used to configure logging.<br>```lgr := &Logr{}```|
| Logr | Engine instance typically instantiated once; used to configure logging.<br>```lgr,_ := logr.New()```|
| Logger | Provides contextual logging via fields; lightweight, can be created once and accessed globally or create on demand.<br>```logger := lgr.NewLogger()```<br>```logger2 := logger.WithField("user", "Sam")```|
| Target | A destination for log items such as console, file, database or just about anything that can be written to. Each target has its own filter/level and formatter, and any number of targets can be added to a Logr. Targets for syslog and any io.Writer are built-in and it is easy to create your own. You can also use any [Logrus hooks](https://github.com/sirupsen/logrus/wiki/Hooks) via a simple [adapter](https://github.com/wiggin77/logrus4logr).|
| Target | A destination for log items such as console, file, database or just about anything that can be written to. Each target has its own filter/level and formatter, and any number of targets can be added to a Logr. Targets for file, syslog and any io.Writer are built-in and it is easy to create your own. You can also use any [Logrus hooks](https://github.com/sirupsen/logrus/wiki/Hooks) via a simple [adapter](https://github.com/wiggin77/logrus4logr).|
| Filter | Determines which logging calls get written versus filtered out. Also determines which logging calls generate a stack trace.<br>```filter := &logr.StdFilter{Lvl: logr.Warn, Stacktrace: logr.Fatal}```|
| Formatter | Formats the output. Logr includes built-in formatters for JSON and plain text with delimiters. It is easy to create your own formatters or you can also use any [Logrus formatters](https://github.com/sirupsen/logrus#formatters) via a simple [adapter](https://github.com/wiggin77/logrus4logr).<br>```formatter := &format.Plain{Delim: " \| "}```|
@@ -26,15 +26,15 @@ It is very much inspired by [Logrus](https://github.com/sirupsen/logrus) but add
```go
// Create Logr instance.
lgr := &logr.Logr{}
lgr,_ := logr.New()
// Create a filter and formatter. Both can be shared by multiple
// targets.
filter := &logr.StdFilter{Lvl: logr.Warn, Stacktrace: logr.Error}
formatter := &format.Plain{Delim: " | "}
formatter := &formatters.Plain{Delim: " | "}
// WriterTarget outputs to any io.Writer
t := target.NewWriterTarget(filter, formatter, os.StdOut, 1000)
t := targets.NewWriterTarget(filter, formatter, os.StdOut, 1000)
lgr.AddTarget(t)
// One or more Loggers can be created, shared, used concurrently,
@@ -56,7 +56,7 @@ Fields allow for contextual logging, meaning information can be added to log sta
Fields are added via Loggers:
```go
lgr := &Logr{}
lgr,_ := logr.New()
// ... add targets ...
logger := lgr.NewLogger().WithFields(logr.Fields{
"user": user,
@@ -88,14 +88,14 @@ Logr also supports custom filters (logr.CustomFilter) which allow fine grained i
LoginLevel := logr.Level{ID: 100, Name: "login ", Stacktrace: false}
LogoutLevel := logr.Level{ID: 101, Name: "logout", Stacktrace: false}
lgr := &logr.Logr{}
lgr,_ := logr.New()
// create a custom filter with custom levels.
filter := &logr.CustomFilter{}
filter.Add(LoginLevel, LogoutLevel)
formatter := &format.Plain{Delim: " | "}
tgr := target.NewWriterTarget(filter, formatter, os.StdOut, 1000)
formatter := &formatters.Plain{Delim: " | "}
tgr := targets.NewWriterTarget(filter, formatter, os.StdOut, 1000)
lgr.AddTarget(tgr)
logger := lgr.NewLogger().WithFields(logr.Fields{"user": "Bob", "role": "admin"})
@@ -113,36 +113,31 @@ You can use any [Logrus hooks](https://github.com/sirupsen/logrus/wiki/Hooks) vi
You can create your own target by implementing the [Target](./target.go) interface.
An easier method is to use the [logr.Basic](./target.go) type target and build your functionality on that. Basic handles all the queuing and other plumbing so you only need to implement two methods. Example target that outputs to `io.Writer`:
Example target that outputs to `io.Writer`:
```go
type Writer struct {
logr.Basic
out io.Writer
}
func NewWriterTarget(filter logr.Filter, formatter logr.Formatter, out io.Writer, maxQueue int) *Writer {
func NewWriterTarget(out io.Writer) *Writer {
w := &Writer{out: out}
w.Basic.Start(w, w, filter, formatter, maxQueue)
return w
}
// Called once to initialize target.
func (w *Writer) Init() error {
return nil
}
// Write will always be called by a single goroutine, so no locking needed.
// Just convert a log record to a []byte using the formatter and output the
// bytes to your sink.
func (w *Writer) Write(rec *logr.LogRec) error {
_, stacktrace := w.IsLevelEnabled(rec.Level())
func (w *Writer) Write(p []byte, rec *logr.LogRec) (int, error) {
return w.out.Write(buf.Bytes())
}
// take a buffer from the pool to avoid allocations or just allocate a new one.
buf := rec.Logger().Logr().BorrowBuffer()
defer rec.Logger().Logr().ReleaseBuffer(buf)
buf, err := w.Formatter().Format(rec, stacktrace, buf)
if err != nil {
return err
}
_, err = w.out.Write(buf.Bytes())
return err
// Called once to cleanup/free resources for target.
func (w *Writer) Shutdown() error {
return nil
}
```

209
vendor/github.com/mattermost/logr/v2/config/config.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,209 @@
package config
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"strings"
"github.com/mattermost/logr/v2"
"github.com/mattermost/logr/v2/formatters"
"github.com/mattermost/logr/v2/targets"
)
type TargetCfg struct {
Type string `json:"type"` // one of "console", "file", "tcp", "syslog", "none".
Options json.RawMessage `json:"options,omitempty"`
Format string `json:"format"` // one of "json", "plain", "gelf"
FormatOptions json.RawMessage `json:"format_options,omitempty"`
Levels []logr.Level `json:"levels"`
MaxQueueSize int `json:"maxqueuesize,omitempty"`
}
type ConsoleOptions struct {
Out string `json:"out"` // one of "stdout", "stderr"
}
type TargetFactory func(targetType string, options json.RawMessage) (logr.Target, error)
type FormatterFactory func(format string, options json.RawMessage) (logr.Formatter, error)
type Factories struct {
targetFactory TargetFactory // can be nil
formatterFactory FormatterFactory // can be nil
}
var removeAll = func(ti logr.TargetInfo) bool { return true }
// ConfigureTargets replaces the current list of log targets with a new one based on a map
// of name->TargetCfg. The map of TargetCfg's would typically be serialized from a JSON
// source or can be programmatically created.
//
// An optional set of factories can be provided which will be called to create any target
// types or formatters not built-in.
//
// To append log targets to an existing config, use `(*Logr).AddTarget` or
// `(*Logr).AddTargetFromConfig` instead.
func ConfigureTargets(lgr *logr.Logr, config map[string]TargetCfg, factories *Factories) error {
if err := lgr.RemoveTargets(context.Background(), removeAll); err != nil {
return fmt.Errorf("error removing existing log targets: %w", err)
}
if factories == nil {
factories = &Factories{nil, nil}
}
for name, tcfg := range config {
target, err := newTarget(tcfg.Type, tcfg.Options, factories.targetFactory)
if err != nil {
return fmt.Errorf("error creating log target %s: %w", name, err)
}
if target == nil {
continue
}
formatter, err := newFormatter(tcfg.Format, tcfg.FormatOptions, factories.formatterFactory)
if err != nil {
return fmt.Errorf("error creating formatter for log target %s: %w", name, err)
}
filter := newFilter(tcfg.Levels)
qSize := tcfg.MaxQueueSize
if qSize == 0 {
qSize = logr.DefaultMaxQueueSize
}
if err = lgr.AddTarget(target, name, filter, formatter, qSize); err != nil {
return fmt.Errorf("error adding log target %s: %w", name, err)
}
}
return nil
}
func newFilter(levels []logr.Level) logr.Filter {
filter := &logr.CustomFilter{}
for _, lvl := range levels {
filter.Add(lvl)
}
return filter
}
func newTarget(targetType string, options json.RawMessage, factory TargetFactory) (logr.Target, error) {
switch strings.ToLower(targetType) {
case "console":
c := ConsoleOptions{}
if len(options) != 0 {
if err := json.Unmarshal(options, &c); err != nil {
return nil, fmt.Errorf("error decoding console target options: %w", err)
}
}
var w io.Writer
switch c.Out {
case "stderr":
w = os.Stderr
case "stdout", "":
w = os.Stdout
default:
return nil, fmt.Errorf("invalid console target option '%s'", c.Out)
}
return targets.NewWriterTarget(w), nil
case "file":
fo := targets.FileOptions{}
if len(options) == 0 {
return nil, errors.New("missing file target options")
}
if err := json.Unmarshal(options, &fo); err != nil {
return nil, fmt.Errorf("error decoding file target options: %w", err)
}
if err := fo.CheckValid(); err != nil {
return nil, fmt.Errorf("invalid file target options: %w", err)
}
return targets.NewFileTarget(fo), nil
case "tcp":
to := targets.TcpOptions{}
if len(options) == 0 {
return nil, errors.New("missing TCP target options")
}
if err := json.Unmarshal(options, &to); err != nil {
return nil, fmt.Errorf("error decoding TCP target options: %w", err)
}
if err := to.CheckValid(); err != nil {
return nil, fmt.Errorf("invalid TCP target options: %w", err)
}
return targets.NewTcpTarget(&to), nil
case "syslog":
so := targets.SyslogOptions{}
if len(options) == 0 {
return nil, errors.New("missing SysLog target options")
}
if err := json.Unmarshal(options, &so); err != nil {
return nil, fmt.Errorf("error decoding Syslog target options: %w", err)
}
if err := so.CheckValid(); err != nil {
return nil, fmt.Errorf("invalid SysLog target options: %w", err)
}
return targets.NewSyslogTarget(&so)
case "none":
return nil, nil
default:
if factory != nil {
t, err := factory(targetType, options)
if err != nil || t == nil {
return nil, fmt.Errorf("error from target factory: %w", err)
}
return t, nil
}
}
return nil, fmt.Errorf("target type '%s' is unrecogized", targetType)
}
func newFormatter(format string, options json.RawMessage, factory FormatterFactory) (logr.Formatter, error) {
switch strings.ToLower(format) {
case "json":
j := formatters.JSON{}
if len(options) != 0 {
if err := json.Unmarshal(options, &j); err != nil {
return nil, fmt.Errorf("error decoding JSON formatter options: %w", err)
}
if err := j.CheckValid(); err != nil {
return nil, fmt.Errorf("invalid JSON formatter options: %w", err)
}
}
return &j, nil
case "plain":
p := formatters.Plain{}
if len(options) != 0 {
if err := json.Unmarshal(options, &p); err != nil {
return nil, fmt.Errorf("error decoding Plain formatter options: %w", err)
}
if err := p.CheckValid(); err != nil {
return nil, fmt.Errorf("invalid plain formatter options: %w", err)
}
}
return &p, nil
case "gelf":
g := formatters.Gelf{}
if len(options) != 0 {
if err := json.Unmarshal(options, &g); err != nil {
return nil, fmt.Errorf("error decoding Gelf formatter options: %w", err)
}
if err := g.CheckValid(); err != nil {
return nil, fmt.Errorf("invalid GELF formatter options: %w", err)
}
}
return &g, nil
default:
if factory != nil {
f, err := factory(format, options)
if err != nil || f == nil {
return nil, fmt.Errorf("error from formatter factory: %w", err)
}
return f, nil
}
}
return nil, fmt.Errorf("format '%s' is unrecogized", format)
}

90
vendor/github.com/mattermost/logr/v2/config/sample-config.json сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,90 @@
{
"sample-console": {
"type": "console",
"options": {
"out": "stdout"
},
"format": "plain",
"format_options": {
"delim": " | "
},
"levels": [
{"id": 5, "name": "debug"},
{"id": 4, "name": "info"},
{"id": 3, "name": "warn"},
{"id": 2, "name": "error", "stacktrace": true},
{"id": 1, "name": "fatal", "stacktrace": true},
{"id": 0, "name": "panic", "stacktrace": true}
],
"maxqueuesize": 1000
},
"sample-file": {
"type": "file",
"options": {
"filename": "test.log",
"max_size": 1000000,
"max_age": 1,
"max_backups": 10,
"compress": true
},
"format": "json",
"format_options": {
},
"levels": [
{"id": 5, "name": "debug"},
{"id": 4, "name": "info"},
{"id": 3, "name": "warn"},
{"id": 2, "name": "error", "stacktrace": true},
{"id": 1, "name": "fatal", "stacktrace": true},
{"id": 0, "name": "panic", "stacktrace": true}
],
"maxqueuesize": 1000
},
"sample-tcp": {
"type": "tcp",
"options": {
"host": "localhost",
"port": 18066,
"tls": false,
"cert": "",
"insecure": false
},
"format": "gelf",
"format_options": {
"hostname": "server01"
},
"levels": [
{"id": 5, "name": "debug"},
{"id": 4, "name": "info"},
{"id": 3, "name": "warn"},
{"id": 2, "name": "error", "stacktrace": true},
{"id": 1, "name": "fatal", "stacktrace": true},
{"id": 0, "name": "panic", "stacktrace": true}
],
"maxqueuesize": 1000
},
"sample-syslog": {
"type": "syslog",
"options": {
"host": "localhost",
"port": 18066,
"tls": false,
"cert": "",
"insecure": false,
"tag": "testapp"
},
"format": "plain",
"format_options": {
"delim": " "
},
"levels": [
{"id": 5, "name": "debug"},
{"id": 4, "name": "info"},
{"id": 3, "name": "warn"},
{"id": 2, "name": "error", "stacktrace": true},
{"id": 1, "name": "fatal", "stacktrace": true},
{"id": 0, "name": "panic", "stacktrace": true}
],
"maxqueuesize": 1000
}
}

Просмотреть файл

@@ -13,7 +13,7 @@ const (
// MaxLevelID is the maximum value of a level ID. Some level cache implementations will
// allocate a cache of this size. Cannot exceed uint.
MaxLevelID = 256
MaxLevelID = 65535
// DefaultEnqueueTimeout is the default amount of time a log record can take to be queued.
// This only applies to blocking enqueue which happen after `logr.OnQueueFull` is called

403
vendor/github.com/mattermost/logr/v2/field.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,403 @@
package logr
import (
"errors"
"fmt"
"io"
"reflect"
"strconv"
"time"
)
var (
Comma = []byte{','}
Equals = []byte{'='}
Space = []byte{' '}
Newline = []byte{'\n'}
Quote = []byte{'"'}
Colon = []byte{'"'}
)
// LogCloner is implemented by `Any` types that require a clone to be provided
// to the logger because the original may mutate.
type LogCloner interface {
LogClone() interface{}
}
// LogWriter is implemented by `Any` types that provide custom formatting for
// log output. A string representation of the type should be written directly to
// the `io.Writer`.
type LogWriter interface {
LogWrite(w io.Writer) error
}
type FieldType uint8
const (
UnknownType FieldType = iota
StringType
StringerType
StructType
ErrorType
BoolType
TimestampMillisType
TimeType
DurationType
Int64Type
Int32Type
IntType
Uint64Type
Uint32Type
UintType
Float64Type
Float32Type
BinaryType
ArrayType
MapType
)
type Field struct {
Key string
Type FieldType
Integer int64
Float float64
String string
Interface interface{}
}
func quoteString(w io.Writer, s string, shouldQuote func(s string) bool) error {
b := shouldQuote(s)
if b {
if _, err := w.Write(Quote); err != nil {
return err
}
}
if _, err := w.Write([]byte(s)); err != nil {
return err
}
if b {
if _, err := w.Write(Quote); err != nil {
return err
}
}
return nil
}
// ValueString converts a known type to a string using default formatting.
// This is called lazily by a formatter.
// Formatters can provide custom formatting or types passed via `Any` can implement
// the `LogString` interface to generate output for logging.
// If the optional shouldQuote callback is provided, then it will be called for any
// string output that could potentially need to be quoted.
func (f Field) ValueString(w io.Writer, shouldQuote func(s string) bool) error {
if shouldQuote == nil {
shouldQuote = func(s string) bool { return false }
}
var err error
switch f.Type {
case StringType:
err = quoteString(w, f.String, shouldQuote)
case StringerType:
s, ok := f.Interface.(fmt.Stringer)
if ok {
err = quoteString(w, s.String(), shouldQuote)
} else if f.Interface == nil {
err = quoteString(w, "", shouldQuote)
} else {
err = fmt.Errorf("invalid fmt.Stringer for key %s", f.Key)
}
case StructType:
s, ok := f.Interface.(LogWriter)
if ok {
err = s.LogWrite(w)
break
}
// structs that do not implement LogWriter fall back to reflection via Printf.
// TODO: create custom reflection-based encoder.
_, err = fmt.Fprintf(w, "%v", f.Interface)
case ErrorType:
// TODO: create custom error encoder.
err = quoteString(w, fmt.Sprintf("%v", f.Interface), shouldQuote)
case BoolType:
var b bool
if f.Integer != 0 {
b = true
}
_, err = io.WriteString(w, strconv.FormatBool(b))
case TimestampMillisType:
ts := time.Unix(f.Integer/1000, (f.Integer%1000)*int64(time.Millisecond))
err = quoteString(w, ts.UTC().Format(TimestampMillisFormat), shouldQuote)
case TimeType:
t, ok := f.Interface.(time.Time)
if !ok {
err = errors.New("invalid time")
break
}
err = quoteString(w, t.Format(DefTimestampFormat), shouldQuote)
case DurationType:
_, err = fmt.Fprintf(w, "%s", time.Duration(f.Integer))
case Int64Type, Int32Type, IntType:
_, err = io.WriteString(w, strconv.FormatInt(f.Integer, 10))
case Uint64Type, Uint32Type, UintType:
_, err = io.WriteString(w, strconv.FormatUint(uint64(f.Integer), 10))
case Float64Type, Float32Type:
size := 64
if f.Type == Float32Type {
size = 32
}
err = quoteString(w, strconv.FormatFloat(f.Float, 'f', -1, size), shouldQuote)
case BinaryType:
b, ok := f.Interface.([]byte)
if ok {
_, err = fmt.Fprintf(w, "[%X]", b)
break
}
_, err = fmt.Fprintf(w, "[%v]", f.Interface)
case ArrayType:
a := reflect.ValueOf(f.Interface)
arr:
for i := 0; i < a.Len(); i++ {
item := a.Index(i)
switch v := item.Interface().(type) {
case LogWriter:
if err = v.LogWrite(w); err != nil {
break arr
}
case fmt.Stringer:
if err = quoteString(w, v.String(), shouldQuote); err != nil {
break arr
}
default:
s := fmt.Sprintf("%v", v)
if err = quoteString(w, s, shouldQuote); err != nil {
break arr
}
}
if _, err = w.Write(Comma); err != nil {
break arr
}
}
case MapType:
a := reflect.ValueOf(f.Interface)
iter := a.MapRange()
it:
for iter.Next() {
if _, err = io.WriteString(w, iter.Key().String()); err != nil {
break it
}
if _, err = w.Write(Equals); err != nil {
break it
}
val := iter.Value().Interface()
switch v := val.(type) {
case LogWriter:
if err = v.LogWrite(w); err != nil {
break it
}
case fmt.Stringer:
if err = quoteString(w, v.String(), shouldQuote); err != nil {
break it
}
default:
s := fmt.Sprintf("%v", v)
if err = quoteString(w, s, shouldQuote); err != nil {
break it
}
}
if _, err = w.Write(Comma); err != nil {
break it
}
}
case UnknownType:
_, err = fmt.Fprintf(w, "%v", f.Interface)
default:
err = fmt.Errorf("invalid type %d", f.Type)
}
return err
}
func nilField(key string) Field {
return String(key, "")
}
func fieldForAny(key string, val interface{}) Field {
switch v := val.(type) {
case LogCloner:
if v == nil {
return nilField(key)
}
c := v.LogClone()
return Field{Key: key, Type: StructType, Interface: c}
case *LogCloner:
if v == nil {
return nilField(key)
}
c := (*v).LogClone()
return Field{Key: key, Type: StructType, Interface: c}
case LogWriter:
if v == nil {
return nilField(key)
}
return Field{Key: key, Type: StructType, Interface: v}
case *LogWriter:
if v == nil {
return nilField(key)
}
return Field{Key: key, Type: StructType, Interface: *v}
case bool:
return Bool(key, v)
case *bool:
if v == nil {
return nilField(key)
}
return Bool(key, *v)
case float64:
return Float64(key, v)
case *float64:
if v == nil {
return nilField(key)
}
return Float64(key, *v)
case float32:
return Float32(key, v)
case *float32:
if v == nil {
return nilField(key)
}
return Float32(key, *v)
case int:
return Int(key, v)
case *int:
if v == nil {
return nilField(key)
}
return Int(key, *v)
case int64:
return Int64(key, v)
case *int64:
if v == nil {
return nilField(key)
}
return Int64(key, *v)
case int32:
return Int32(key, v)
case *int32:
if v == nil {
return nilField(key)
}
return Int32(key, *v)
case int16:
return Int32(key, int32(v))
case *int16:
if v == nil {
return nilField(key)
}
return Int32(key, int32(*v))
case int8:
return Int32(key, int32(v))
case *int8:
if v == nil {
return nilField(key)
}
return Int32(key, int32(*v))
case string:
return String(key, v)
case *string:
if v == nil {
return nilField(key)
}
return String(key, *v)
case uint:
return Uint(key, v)
case *uint:
if v == nil {
return nilField(key)
}
return Uint(key, *v)
case uint64:
return Uint64(key, v)
case *uint64:
if v == nil {
return nilField(key)
}
return Uint64(key, *v)
case uint32:
return Uint32(key, v)
case *uint32:
if v == nil {
return nilField(key)
}
return Uint32(key, *v)
case uint16:
return Uint32(key, uint32(v))
case *uint16:
if v == nil {
return nilField(key)
}
return Uint32(key, uint32(*v))
case uint8:
return Uint32(key, uint32(v))
case *uint8:
if v == nil {
return nilField(key)
}
return Uint32(key, uint32(*v))
case []byte:
if v == nil {
return nilField(key)
}
return Field{Key: key, Type: BinaryType, Interface: v}
case time.Time:
return Time(key, v)
case *time.Time:
if v == nil {
return nilField(key)
}
return Time(key, *v)
case time.Duration:
return Duration(key, v)
case *time.Duration:
if v == nil {
return nilField(key)
}
return Duration(key, *v)
case error:
return NamedErr(key, v)
case fmt.Stringer:
if v == nil {
return nilField(key)
}
return Field{Key: key, Type: StringerType, Interface: v}
case *fmt.Stringer:
if v == nil {
return nilField(key)
}
return Field{Key: key, Type: StringerType, Interface: *v}
default:
return Field{Key: key, Type: UnknownType, Interface: val}
}
}
// FieldSorter provides sorting of an array of fields by key.
type FieldSorter []Field
func (fs FieldSorter) Len() int { return len(fs) }
func (fs FieldSorter) Less(i, j int) bool { return fs[i].Key < fs[j].Key }
func (fs FieldSorter) Swap(i, j int) { fs[i], fs[j] = fs[j], fs[i] }

110
vendor/github.com/mattermost/logr/v2/fieldapi.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,110 @@
package logr
import (
"fmt"
"time"
)
// Any picks the best supported field type based on type of val.
// For best performance when passing a struct (or struct pointer),
// implement `logr.LogWriter` on the struct, otherwise reflection
// will be used to generate a string representation.
func Any(key string, val interface{}) Field {
return fieldForAny(key, val)
}
// Int64 constructs a field containing a key and Int64 value.
func Int64(key string, val int64) Field {
return Field{Key: key, Type: Int64Type, Integer: val}
}
// Int32 constructs a field containing a key and Int32 value.
func Int32(key string, val int32) Field {
return Field{Key: key, Type: Int32Type, Integer: int64(val)}
}
// Int constructs a field containing a key and Int value.
func Int(key string, val int) Field {
return Field{Key: key, Type: IntType, Integer: int64(val)}
}
// Uint64 constructs a field containing a key and Uint64 value.
func Uint64(key string, val uint64) Field {
return Field{Key: key, Type: Uint64Type, Integer: int64(val)}
}
// Uint32 constructs a field containing a key and Uint32 value.
func Uint32(key string, val uint32) Field {
return Field{Key: key, Type: Uint32Type, Integer: int64(val)}
}
// Uint constructs a field containing a key and Uint value.
func Uint(key string, val uint) Field {
return Field{Key: key, Type: UintType, Integer: int64(val)}
}
// Float64 constructs a field containing a key and Float64 value.
func Float64(key string, val float64) Field {
return Field{Key: key, Type: Float64Type, Float: val}
}
// Float32 constructs a field containing a key and Float32 value.
func Float32(key string, val float32) Field {
return Field{Key: key, Type: Float32Type, Float: float64(val)}
}
// String constructs a field containing a key and String value.
func String(key string, val string) Field {
return Field{Key: key, Type: StringType, String: val}
}
// Stringer constructs a field containing a key and a `fmt.Stringer` value.
// The `String` method will be called in lazy fashion.
func Stringer(key string, val fmt.Stringer) Field {
return Field{Key: key, Type: StringerType, Interface: val}
}
// Err constructs a field containing a default key ("error") and error value.
func Err(err error) Field {
return NamedErr("error", err)
}
// NamedErr constructs a field containing a key and error value.
func NamedErr(key string, err error) Field {
return Field{Key: key, Type: ErrorType, Interface: err}
}
// Bool constructs a field containing a key and bool value.
func Bool(key string, val bool) Field {
var b int64
if val {
b = 1
}
return Field{Key: key, Type: BoolType, Integer: b}
}
// Time constructs a field containing a key and time.Time value.
func Time(key string, val time.Time) Field {
return Field{Key: key, Type: TimeType, Interface: val}
}
// Duration constructs a field containing a key and time.Duration value.
func Duration(key string, val time.Duration) Field {
return Field{Key: key, Type: DurationType, Integer: int64(val)}
}
// Millis constructs a field containing a key and timestamp value.
// The timestamp is expected to be milliseconds since Jan 1, 1970 UTC.
func Millis(key string, val int64) Field {
return Field{Key: key, Type: TimestampMillisType, Integer: val}
}
// Array constructs a field containing a key and array value.
func Array(key string, val interface{}) Field {
return Field{Key: key, Type: ArrayType, Interface: val}
}
// Map constructs a field containing a key and map value.
func Map(key string, val interface{}) Field {
return Field{Key: key, Type: MapType, Interface: val}
}

10
vendor/github.com/mattermost/logr/v2/filter.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,10 @@
package logr
// Filter allows targets to determine which Level(s) are active
// for logging and which Level(s) require a stack trace to be output.
// A default implementation using "panic, fatal..." is provided, and
// a more flexible alternative implementation is also provided that
// allows any number of custom levels.
type Filter interface {
GetEnabledLevel(level Level) (Level, bool)
}

47
vendor/github.com/mattermost/logr/v2/filtercustom.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,47 @@
package logr
import (
"sync"
)
// CustomFilter allows targets to enable logging via a list of discrete levels.
type CustomFilter struct {
mux sync.RWMutex
levels map[LevelID]Level
}
// NewCustomFilter creates a filter supporting discrete log levels.
func NewCustomFilter(levels ...Level) *CustomFilter {
filter := &CustomFilter{}
filter.Add(levels...)
return filter
}
// GetEnabledLevel returns the Level with the specified Level.ID and whether the level
// is enabled for this filter.
func (cf *CustomFilter) GetEnabledLevel(level Level) (Level, bool) {
cf.mux.RLock()
defer cf.mux.RUnlock()
levelEnabled, ok := cf.levels[level.ID]
if ok && levelEnabled.Name == "" {
levelEnabled.Name = level.Name
}
return levelEnabled, ok
}
// Add adds one or more levels to the list. Adding a level enables logging for
// that level on any targets using this CustomFilter.
func (cf *CustomFilter) Add(levels ...Level) {
cf.mux.Lock()
defer cf.mux.Unlock()
if cf.levels == nil {
cf.levels = make(map[LevelID]Level)
}
for _, s := range levels {
cf.levels[s.ID] = s
}
}

65
vendor/github.com/mattermost/logr/v2/filterstd.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,65 @@
package logr
// StdFilter allows targets to filter via classic log levels where any level
// beyond a certain verbosity/severity is enabled.
type StdFilter struct {
Lvl Level
Stacktrace Level
}
// GetEnabledLevel returns the Level with the specified Level.ID and whether the level
// is enabled for this filter.
func (lt StdFilter) GetEnabledLevel(level Level) (Level, bool) {
enabled := level.ID <= lt.Lvl.ID
var levelEnabled Level
if enabled {
switch level.ID {
case Panic.ID:
levelEnabled = Panic
case Fatal.ID:
levelEnabled = Fatal
case Error.ID:
levelEnabled = Error
case Warn.ID:
levelEnabled = Warn
case Info.ID:
levelEnabled = Info
case Debug.ID:
levelEnabled = Debug
case Trace.ID:
levelEnabled = Trace
default:
levelEnabled = level
}
}
return levelEnabled, enabled
}
// IsEnabled returns true if the specified Level is at or above this verbosity. Also
// determines if a stack trace is required.
func (lt StdFilter) IsEnabled(level Level) bool {
return level.ID <= lt.Lvl.ID
}
// IsStacktraceEnabled returns true if the specified Level requires a stack trace.
func (lt StdFilter) IsStacktraceEnabled(level Level) bool {
return level.ID <= lt.Stacktrace.ID
}
var (
// Panic is the highest level of severity.
Panic = Level{ID: 0, Name: "panic", Color: Red}
// Fatal designates a catastrophic error.
Fatal = Level{ID: 1, Name: "fatal", Color: Red}
// Error designates a serious but possibly recoverable error.
Error = Level{ID: 2, Name: "error", Color: Red}
// Warn designates non-critical error.
Warn = Level{ID: 3, Name: "warn", Color: Yellow}
// Info designates information regarding application events.
Info = Level{ID: 4, Name: "info", Color: Cyan}
// Debug designates verbose information typically used for debugging.
Debug = Level{ID: 5, Name: "debug", Color: NoColor}
// Trace designates the highest verbosity of log output.
Trace = Level{ID: 6, Name: "trace", Color: NoColor}
)

184
vendor/github.com/mattermost/logr/v2/formatter.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,184 @@
package logr
import (
"bytes"
"io"
"runtime"
"strconv"
)
// Formatter turns a LogRec into a formatted string.
type Formatter interface {
// IsStacktraceNeeded returns true if this formatter requires a stacktrace to be
// generated for each LogRecord. Enabling features such as `Caller` field require
// a stacktrace.
IsStacktraceNeeded() bool
// Format converts a log record to bytes. If buf is not nil then it will be
// be filled with the formatted results, otherwise a new buffer will be allocated.
Format(rec *LogRec, level Level, buf *bytes.Buffer) (*bytes.Buffer, error)
}
const (
// DefTimestampFormat is the default time stamp format used by Plain formatter and others.
DefTimestampFormat = "2006-01-02 15:04:05.000 Z07:00"
// TimestampMillisFormat is the format for logging milliseconds UTC
TimestampMillisFormat = "Jan _2 15:04:05.000"
)
type Writer struct {
io.Writer
}
func (w Writer) Writes(elems ...[]byte) (int, error) {
var count int
for _, e := range elems {
if c, err := w.Write(e); err != nil {
return count + c, err
} else {
count += c
}
}
return count, nil
}
// DefaultFormatter is the default formatter, outputting only text with
// no colors and a space delimiter. Use `format.Plain` instead.
type DefaultFormatter struct {
}
// IsStacktraceNeeded always returns false for default formatter since the
// `Caller` field is not supported.
func (p *DefaultFormatter) IsStacktraceNeeded() bool {
return false
}
// Format converts a log record to bytes.
func (p *DefaultFormatter) Format(rec *LogRec, level Level, buf *bytes.Buffer) (*bytes.Buffer, error) {
if buf == nil {
buf = &bytes.Buffer{}
}
timestampFmt := DefTimestampFormat
buf.WriteString(rec.Time().Format(timestampFmt))
buf.Write(Space)
buf.WriteString(level.Name)
buf.Write(Space)
buf.WriteString(rec.Msg())
buf.Write(Space)
fields := rec.Fields()
if len(fields) > 0 {
if err := WriteFields(buf, fields, Space, NoColor); err != nil {
return nil, err
}
}
if level.Stacktrace {
frames := rec.StackFrames()
if len(frames) > 0 {
buf.Write(Newline)
if err := WriteStacktrace(buf, rec.StackFrames()); err != nil {
return nil, err
}
}
}
buf.Write(Newline)
return buf, nil
}
// WriteFields writes zero or more name value pairs to the io.Writer.
// The pairs output in key=value format with optional separator between fields.
func WriteFields(w io.Writer, fields []Field, separator []byte, color Color) error {
ws := Writer{w}
sep := []byte{}
for _, field := range fields {
if err := writeField(ws, field, sep, color); err != nil {
return err
}
sep = separator
}
return nil
}
func writeField(ws Writer, field Field, sep []byte, color Color) error {
if len(sep) != 0 {
if _, err := ws.Write(sep); err != nil {
return err
}
}
if err := WriteWithColor(ws, field.Key, color); err != nil {
return err
}
if _, err := ws.Write(Equals); err != nil {
return err
}
return field.ValueString(ws, shouldQuote)
}
// shouldQuote returns true if val contains any characters that might be unsafe
// when injecting log output into an aggregator, viewer or report.
func shouldQuote(val string) bool {
for _, c := range val {
if !((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
c == '-' || c == '.' || c == '_' || c == '/' || c == '@' || c == '^' || c == '+') {
return true
}
}
return false
}
// WriteStacktrace formats and outputs a stack trace to an io.Writer.
func WriteStacktrace(w io.Writer, frames []runtime.Frame) error {
ws := Writer{w}
for _, frame := range frames {
if frame.Function != "" {
if _, err := ws.Writes(Space, Space, []byte(frame.Function), Newline); err != nil {
return err
}
}
if frame.File != "" {
s := strconv.FormatInt(int64(frame.Line), 10)
if _, err := ws.Writes([]byte{' ', ' ', ' ', ' ', ' ', ' '}, []byte(frame.File), Colon, []byte(s), Newline); err != nil {
return err
}
}
}
return nil
}
// WriteWithColor outputs a string with the specified ANSI color.
func WriteWithColor(w io.Writer, s string, color Color) error {
var err error
writer := func(buf []byte) {
if err != nil {
return
}
_, err = w.Write(buf)
}
if color != NoColor {
writer(AnsiColorPrefix)
writer([]byte(strconv.FormatInt(int64(color), 10)))
writer(AnsiColorSuffix)
}
if err == nil {
_, err = io.WriteString(w, s)
}
if color != NoColor {
writer(AnsiColorPrefix)
writer([]byte(strconv.FormatInt(int64(NoColor), 10)))
writer(AnsiColorSuffix)
}
return err
}

152
vendor/github.com/mattermost/logr/v2/formatters/gelf.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,152 @@
package formatters
import (
"bytes"
"fmt"
"net"
"os"
"strings"
"github.com/francoispqt/gojay"
"github.com/mattermost/logr/v2"
)
const (
GelfVersion = "1.1"
GelfVersionKey = "version"
GelfHostKey = "host"
GelfShortKey = "short_message"
GelfFullKey = "full_message"
GelfTimestampKey = "timestamp"
GelfLevelKey = "level"
)
// Gelf formats log records as GELF rcords (https://docs.graylog.org/en/4.0/pages/gelf.html).
type Gelf struct {
// Hostname allows a custom hostname, otherwise os.Hostname is used
Hostname string `json:"hostname"`
// EnableCaller enables output of the file and line number that emitted a log record.
EnableCaller bool `json:"enable_caller"`
// FieldSorter allows custom sorting for the context fields.
FieldSorter func(fields []logr.Field) []logr.Field `json:"-"`
}
func (g *Gelf) CheckValid() error {
return nil
}
// IsStacktraceNeeded returns true if a stacktrace is needed so we can output the `Caller` field.
func (g *Gelf) IsStacktraceNeeded() bool {
return g.EnableCaller
}
// Format converts a log record to bytes in GELF format.
func (g *Gelf) Format(rec *logr.LogRec, level logr.Level, buf *bytes.Buffer) (*bytes.Buffer, error) {
if buf == nil {
buf = &bytes.Buffer{}
}
enc := gojay.BorrowEncoder(buf)
defer func() {
enc.Release()
}()
gr := gelfRecord{
LogRec: rec,
Gelf: g,
level: level,
sorter: g.FieldSorter,
}
err := enc.EncodeObject(gr)
if err != nil {
return nil, err
}
buf.WriteByte(0)
return buf, nil
}
type gelfRecord struct {
*logr.LogRec
*Gelf
level logr.Level
sorter func(fields []logr.Field) []logr.Field
}
// MarshalJSONObject encodes the LogRec as JSON.
func (gr gelfRecord) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddStringKey(GelfVersionKey, GelfVersion)
enc.AddStringKey(GelfHostKey, gr.getHostname())
enc.AddStringKey(GelfShortKey, gr.Msg())
if gr.level.Stacktrace {
frames := gr.StackFrames()
if len(frames) != 0 {
var sbuf strings.Builder
for _, frame := range frames {
fmt.Fprintf(&sbuf, "%s\n %s:%d\n", frame.Function, frame.File, frame.Line)
}
enc.AddStringKey(GelfFullKey, sbuf.String())
}
}
secs := float64(gr.Time().UTC().Unix())
millis := float64(gr.Time().Nanosecond() / 1000000)
ts := secs + (millis / 1000)
enc.AddFloat64Key(GelfTimestampKey, ts)
enc.AddUint32Key(GelfLevelKey, uint32(gr.level.ID))
var fields []logr.Field
if gr.EnableCaller {
caller := logr.Field{
Key: "_caller",
Type: logr.StringType,
String: gr.LogRec.Caller(),
}
fields = append(fields, caller)
}
fields = append(fields, gr.Fields()...)
if gr.sorter != nil {
fields = gr.sorter(fields)
}
if len(fields) > 0 {
for _, field := range fields {
if !strings.HasPrefix("_", field.Key) {
field.Key = "_" + field.Key
}
if err := encodeField(enc, field); err != nil {
enc.AddStringKey(field.Key, fmt.Sprintf("<error encoding field: %v>", err))
}
}
}
}
// IsNil returns true if the gelf record pointer is nil.
func (gr gelfRecord) IsNil() bool {
return gr.LogRec == nil
}
func (g *Gelf) getHostname() string {
if g.Hostname != "" {
return g.Hostname
}
h, err := os.Hostname()
if err == nil {
return h
}
// get the egress IP by fake dialing any address. UDP ensures no dial.
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
return "unknown"
}
defer conn.Close()
local := conn.LocalAddr().(*net.UDPAddr)
return local.IP.String()
}

273
vendor/github.com/mattermost/logr/v2/formatters/json.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,273 @@
package formatters
import (
"bytes"
"encoding/json"
"fmt"
"runtime"
"strings"
"sync"
"github.com/francoispqt/gojay"
"github.com/mattermost/logr/v2"
)
// JSON formats log records as JSON.
type JSON struct {
// DisableTimestamp disables output of timestamp field.
DisableTimestamp bool `json:"disable_timestamp"`
// DisableLevel disables output of level field.
DisableLevel bool `json:"disable_level"`
// DisableMsg disables output of msg field.
DisableMsg bool `json:"disable_msg"`
// DisableFields disables output of all fields.
DisableFields bool `json:"disable_fields"`
// DisableStacktrace disables output of stack trace.
DisableStacktrace bool `json:"disable_stacktrace"`
// EnableCaller enables output of the file and line number that emitted a log record.
EnableCaller bool `json:"enable_caller"`
// TimestampFormat is an optional format for timestamps. If empty
// then DefTimestampFormat is used.
TimestampFormat string `json:"timestamp_format"`
// KeyTimestamp overrides the timestamp field key name.
KeyTimestamp string `json:"key_timestamp"`
// KeyLevel overrides the level field key name.
KeyLevel string `json:"key_level"`
// KeyMsg overrides the msg field key name.
KeyMsg string `json:"key_msg"`
// KeyGroupFields when not empty will group all context fields
// under this key.
KeyGroupFields string `json:"key_group_fields"`
// KeyStacktrace overrides the stacktrace field key name.
KeyStacktrace string `json:"key_stacktrace"`
// KeyCaller overrides the caller field key name.
KeyCaller string `json:"key_caller"`
// FieldSorter allows custom sorting of the fields. If nil then
// no sorting is done.
FieldSorter func(fields []logr.Field) []logr.Field `json:"-"`
once sync.Once
}
func (j *JSON) CheckValid() error {
return nil
}
// IsStacktraceNeeded returns true if a stacktrace is needed so we can output the `Caller` field.
func (j *JSON) IsStacktraceNeeded() bool {
return j.EnableCaller
}
// Format converts a log record to bytes in JSON format.
func (j *JSON) Format(rec *logr.LogRec, level logr.Level, buf *bytes.Buffer) (*bytes.Buffer, error) {
j.once.Do(j.applyDefaultKeyNames)
if buf == nil {
buf = &bytes.Buffer{}
}
enc := gojay.BorrowEncoder(buf)
defer func() {
enc.Release()
}()
jlr := JSONLogRec{
LogRec: rec,
JSON: j,
level: level,
sorter: j.FieldSorter,
}
err := enc.EncodeObject(jlr)
if err != nil {
return nil, err
}
buf.WriteByte('\n')
return buf, nil
}
func (j *JSON) applyDefaultKeyNames() {
if j.KeyTimestamp == "" {
j.KeyTimestamp = "timestamp"
}
if j.KeyLevel == "" {
j.KeyLevel = "level"
}
if j.KeyMsg == "" {
j.KeyMsg = "msg"
}
if j.KeyStacktrace == "" {
j.KeyStacktrace = "stacktrace"
}
if j.KeyCaller == "" {
j.KeyCaller = "caller"
}
}
// JSONLogRec decorates a LogRec adding JSON encoding.
type JSONLogRec struct {
*logr.LogRec
*JSON
level logr.Level
sorter func(fields []logr.Field) []logr.Field
}
// MarshalJSONObject encodes the LogRec as JSON.
func (jlr JSONLogRec) MarshalJSONObject(enc *gojay.Encoder) {
if !jlr.DisableTimestamp {
timestampFmt := jlr.TimestampFormat
if timestampFmt == "" {
timestampFmt = logr.DefTimestampFormat
}
time := jlr.Time()
enc.AddTimeKey(jlr.KeyTimestamp, &time, timestampFmt)
}
if !jlr.DisableLevel {
enc.AddStringKey(jlr.KeyLevel, jlr.level.Name)
}
if !jlr.DisableMsg {
enc.AddStringKey(jlr.KeyMsg, jlr.Msg())
}
if jlr.EnableCaller {
enc.AddStringKey(jlr.KeyCaller, jlr.Caller())
}
if !jlr.DisableFields {
fields := jlr.Fields()
if jlr.sorter != nil {
fields = jlr.sorter(fields)
}
if jlr.KeyGroupFields != "" {
enc.AddObjectKey(jlr.KeyGroupFields, FieldArray(fields))
} else {
if len(fields) > 0 {
for _, field := range fields {
field = jlr.prefixCollision(field)
if err := encodeField(enc, field); err != nil {
enc.AddStringKey(field.Key, "<error encoding field: "+err.Error()+">")
}
}
}
}
}
if jlr.level.Stacktrace && !jlr.DisableStacktrace {
frames := jlr.StackFrames()
if len(frames) > 0 {
enc.AddArrayKey(jlr.KeyStacktrace, stackFrames(frames))
}
}
}
// IsNil returns true if the LogRec pointer is nil.
func (rec JSONLogRec) IsNil() bool {
return rec.LogRec == nil
}
func (rec JSONLogRec) prefixCollision(field logr.Field) logr.Field {
switch field.Key {
case rec.KeyTimestamp, rec.KeyLevel, rec.KeyMsg, rec.KeyStacktrace:
f := field
f.Key = "_" + field.Key
return rec.prefixCollision(f)
}
return field
}
type stackFrames []runtime.Frame
// MarshalJSONArray encodes stackFrames slice as JSON.
func (s stackFrames) MarshalJSONArray(enc *gojay.Encoder) {
for _, frame := range s {
enc.AddObject(stackFrame(frame))
}
}
// IsNil returns true if stackFrames is empty slice.
func (s stackFrames) IsNil() bool {
return len(s) == 0
}
type stackFrame runtime.Frame
// MarshalJSONArray encodes stackFrame as JSON.
func (f stackFrame) MarshalJSONObject(enc *gojay.Encoder) {
enc.AddStringKey("Function", f.Function)
enc.AddStringKey("File", f.File)
enc.AddIntKey("Line", f.Line)
}
func (f stackFrame) IsNil() bool {
return false
}
type FieldArray []logr.Field
// MarshalJSONObject encodes Fields map to JSON.
func (fa FieldArray) MarshalJSONObject(enc *gojay.Encoder) {
for _, fld := range fa {
if err := encodeField(enc, fld); err != nil {
enc.AddStringKey(fld.Key, "<error encoding field: "+err.Error()+">")
}
}
}
// IsNil returns true if map is nil.
func (fa FieldArray) IsNil() bool {
return fa == nil
}
func encodeField(enc *gojay.Encoder, field logr.Field) error {
// first check if the value has a marshaller already.
switch vt := field.Interface.(type) {
case gojay.MarshalerJSONObject:
enc.AddObjectKey(field.Key, vt)
return nil
case gojay.MarshalerJSONArray:
enc.AddArrayKey(field.Key, vt)
return nil
}
switch field.Type {
case logr.StringType:
enc.AddStringKey(field.Key, field.String)
case logr.BoolType:
var b bool
if field.Integer != 0 {
b = true
}
enc.AddBoolKey(field.Key, b)
case logr.StructType, logr.ArrayType, logr.MapType, logr.UnknownType:
b, err := json.Marshal(field.Interface)
if err != nil {
return err
}
embed := gojay.EmbeddedJSON(b)
enc.AddEmbeddedJSONKey(field.Key, &embed)
case logr.StringerType, logr.ErrorType, logr.TimestampMillisType, logr.TimeType, logr.DurationType, logr.BinaryType:
var buf strings.Builder
_ = field.ValueString(&buf, nil)
enc.AddStringKey(field.Key, buf.String())
case logr.Int64Type, logr.Int32Type, logr.IntType:
enc.AddInt64Key(field.Key, field.Integer)
case logr.Uint64Type, logr.Uint32Type, logr.UintType:
enc.AddUint64Key(field.Key, uint64(field.Integer))
case logr.Float64Type, logr.Float32Type:
enc.AddFloat64Key(field.Key, field.Float)
default:
return fmt.Errorf("invalid field type: %d", field.Type)
}
return nil
}

146
vendor/github.com/mattermost/logr/v2/formatters/plain.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,146 @@
package formatters
import (
"bytes"
"fmt"
"strings"
"github.com/mattermost/logr/v2"
)
// Plain is the simplest formatter, outputting only text with
// no colors.
type Plain struct {
// DisableTimestamp disables output of timestamp field.
DisableTimestamp bool `json:"disable_timestamp"`
// DisableLevel disables output of level field.
DisableLevel bool `json:"disable_level"`
// DisableMsg disables output of msg field.
DisableMsg bool `json:"disable_msg"`
// DisableFields disables output of all fields.
DisableFields bool `json:"disable_fields"`
// DisableStacktrace disables output of stack trace.
DisableStacktrace bool `json:"disable_stacktrace"`
// EnableCaller enables output of the file and line number that emitted a log record.
EnableCaller bool `json:"enable_caller"`
// Delim is an optional delimiter output between each log field.
// Defaults to a single space.
Delim string `json:"delim"`
// MinLevelLen sets the minimum level name length. If the level name is less
// than the minimum it will be padded with spaces.
MinLevelLen int `json:"min_level_len"`
// MinMessageLen sets the minimum msg length. If the msg text is less
// than the minimum it will be padded with spaces.
MinMessageLen int `json:"min_msg_len"`
// TimestampFormat is an optional format for timestamps. If empty
// then DefTimestampFormat is used.
TimestampFormat string `json:"timestamp_format"`
// LineEnd sets the end of line character(s). Defaults to '\n'.
LineEnd string `json:"line_end"`
// EnableColor sets whether output should include color.
EnableColor bool `json:"enable_color"`
}
func (p *Plain) CheckValid() error {
if p.MinMessageLen < 0 || p.MinMessageLen > 1024 {
return fmt.Errorf("min_msg_len is invalid(%d)", p.MinMessageLen)
}
return nil
}
// IsStacktraceNeeded returns true if a stacktrace is needed so we can output the `Caller` field.
func (p *Plain) IsStacktraceNeeded() bool {
return p.EnableCaller
}
// Format converts a log record to bytes.
func (p *Plain) Format(rec *logr.LogRec, level logr.Level, buf *bytes.Buffer) (*bytes.Buffer, error) {
delim := p.Delim
if delim == "" {
delim = " "
}
if buf == nil {
buf = &bytes.Buffer{}
}
timestampFmt := p.TimestampFormat
if timestampFmt == "" {
timestampFmt = logr.DefTimestampFormat
}
color := logr.NoColor
if p.EnableColor {
color = level.Color
}
if !p.DisableLevel {
_ = logr.WriteWithColor(buf, level.Name, color)
count := len(level.Name)
if p.MinLevelLen > count {
_, _ = buf.WriteString(strings.Repeat(" ", p.MinLevelLen-count))
}
buf.WriteString(delim)
}
if !p.DisableTimestamp {
var arr [128]byte
tbuf := rec.Time().AppendFormat(arr[:0], timestampFmt)
buf.WriteByte('[')
buf.Write(tbuf)
buf.WriteByte(']')
buf.WriteString(delim)
}
if !p.DisableMsg {
count, _ := buf.WriteString(rec.Msg())
if p.MinMessageLen > count {
_, _ = buf.WriteString(strings.Repeat(" ", p.MinMessageLen-count))
}
_, _ = buf.WriteString(delim)
}
var fields []logr.Field
if p.EnableCaller {
fld := logr.Field{
Key: "caller",
Type: logr.StringType,
String: rec.Caller(),
}
fields = append(fields, fld)
}
if !p.DisableFields {
fields = append(fields, rec.Fields()...)
}
if len(fields) > 0 {
if err := logr.WriteFields(buf, fields, logr.Space, color); err != nil {
return nil, err
}
}
if level.Stacktrace && !p.DisableStacktrace {
frames := rec.StackFrames()
if len(frames) > 0 {
buf.WriteString("\n")
if err := logr.WriteStacktrace(buf, rec.StackFrames()); err != nil {
return nil, err
}
}
}
if p.LineEnd == "" {
buf.WriteString("\n")
} else {
buf.WriteString(p.LineEnd)
}
return buf, nil
}

6
vendor/github.com/mattermost/logr/go.mod → vendor/github.com/mattermost/logr/v2/go.mod сгенерированный поставляемый
Просмотреть файл

@@ -1,11 +1,11 @@
module github.com/mattermost/logr
module github.com/mattermost/logr/v2
go 1.12
require (
github.com/francoispqt/gojay v1.2.13
github.com/stretchr/testify v1.2.2
github.com/wiggin77/cfg v1.0.2
github.com/stretchr/testify v1.4.0
github.com/wiggin77/merror v1.0.2
github.com/wiggin77/srslog v1.0.1
gopkg.in/natefinch/lumberjack.v2 v2.0.0
)

8
vendor/github.com/mattermost/logr/go.sum → vendor/github.com/mattermost/logr/v2/go.sum сгенерированный поставляемый
Просмотреть файл

@@ -15,6 +15,7 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@@ -93,15 +94,18 @@ github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYED
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/wiggin77/cfg v1.0.2 h1:NBUX+iJRr+RTncTqTNvajHwzduqbhCQjEqxLHr6Fk7A=
github.com/wiggin77/cfg v1.0.2/go.mod h1:b3gotba2e5bXTqTW48DwIFoLc+4lWKP7WPi/CdvZ4aE=
github.com/wiggin77/merror v1.0.2 h1:V0nH9eFp64ASyaXC+pB5WpvBoCg7NUwvaCSKdzlcHqw=
github.com/wiggin77/merror v1.0.2/go.mod h1:uQTcIU0Z6jRK4OwqganPYerzQxSFJ4GSHM3aurxxQpg=
github.com/wiggin77/srslog v1.0.1 h1:gA2XjSMy3DrRdX9UqLuDtuVAAshb8bE1NhX1YK0Qe+8=
github.com/wiggin77/srslog v1.0.1/go.mod h1:fehkyYDq1QfuYn60TDPu9YdY2bB85VUW2mvN1WynEls=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=

34
vendor/github.com/mattermost/logr/v2/level.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,34 @@
package logr
var AnsiColorPrefix = []byte("\u001b[")
var AnsiColorSuffix = []byte("m")
// Color for formatters that support color output.
type Color uint8
const (
NoColor Color = 0
Red Color = 31
Green Color = 32
Yellow Color = 33
Blue Color = 34
Magenta Color = 35
Cyan Color = 36
White Color = 37
)
// LevelID is the unique id of each level.
type LevelID uint
// Level provides a mechanism to enable/disable specific log lines.
type Level struct {
ID LevelID `json:"id"`
Name string `json:"name"`
Stacktrace bool `json:"stacktrace,omitempty"`
Color Color `json:"color,omitempty"`
}
// String returns the name of this level.
func (level Level) String() string {
return level.Name
}

Просмотреть файл

99
vendor/github.com/mattermost/logr/v2/logger.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,99 @@
package logr
import "log"
// Logger provides context for logging via fields.
type Logger struct {
lgr *Logr
fields []Field
}
// Logr returns the `Logr` instance that created this `Logger`.
func (logger Logger) Logr() *Logr {
return logger.lgr
}
// With creates a new `Logger` with any existing fields plus the new ones.
func (logger Logger) With(fields ...Field) Logger {
l := Logger{lgr: logger.lgr}
size := len(logger.fields) + len(fields)
if size > 0 {
l.fields = make([]Field, 0, size)
l.fields = append(l.fields, logger.fields...)
l.fields = append(l.fields, fields...)
}
return l
}
// StdLogger creates a standard logger backed by this `Logr.Logger` instance.
// All log records are emitted with the specified log level.
func (logger Logger) StdLogger(level Level) *log.Logger {
return NewStdLogger(level, logger)
}
// IsLevelEnabled determines if the specified level is enabled for at least
// one log target.
func (logger Logger) IsLevelEnabled(level Level) bool {
status := logger.Logr().IsLevelEnabled(level)
return status.Enabled
}
// Sugar creates a new `Logger` with a less structured API. Any fields are preserved.
func (logger Logger) Sugar(fields ...Field) Sugar {
return Sugar{
logger: logger.With(fields...),
}
}
// Log checks that the level matches one or more targets, and
// if so, generates a log record that is added to the Logr queue.
// Arguments are handled in the manner of fmt.Print.
func (logger Logger) Log(lvl Level, msg string, fields ...Field) {
status := logger.lgr.IsLevelEnabled(lvl)
if status.Enabled {
rec := NewLogRec(lvl, logger, msg, fields, status.Stacktrace)
logger.lgr.enqueue(rec)
}
}
// LogM calls `Log` multiple times, one for each level provided.
func (logger Logger) LogM(levels []Level, msg string, fields ...Field) {
for _, lvl := range levels {
logger.Log(lvl, msg, fields...)
}
}
// Trace is a convenience method equivalent to `Log(TraceLevel, msg, fields...)`.
func (logger Logger) Trace(msg string, fields ...Field) {
logger.Log(Trace, msg, fields...)
}
// Debug is a convenience method equivalent to `Log(DebugLevel, msg, fields...)`.
func (logger Logger) Debug(msg string, fields ...Field) {
logger.Log(Debug, msg, fields...)
}
// Info is a convenience method equivalent to `Log(InfoLevel, msg, fields...)`.
func (logger Logger) Info(msg string, fields ...Field) {
logger.Log(Info, msg, fields...)
}
// Warn is a convenience method equivalent to `Log(WarnLevel, msg, fields...)`.
func (logger Logger) Warn(msg string, fields ...Field) {
logger.Log(Warn, msg, fields...)
}
// Error is a convenience method equivalent to `Log(ErrorLevel, msg, fields...)`.
func (logger Logger) Error(msg string, fields ...Field) {
logger.Log(Error, msg, fields...)
}
// Fatal is a convenience method equivalent to `Log(FatalLevel, msg, fields...)`
func (logger Logger) Fatal(msg string, fields ...Field) {
logger.Log(Fatal, msg, fields...)
}
// Panic is a convenience method equivalent to `Log(PanicLevel, msg, fields...)`
func (logger Logger) Panic(msg string, fields ...Field) {
logger.Log(Panic, msg, fields...)
}

471
vendor/github.com/mattermost/logr/v2/logr.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,471 @@
package logr
import (
"bytes"
"context"
"errors"
"fmt"
"os"
"sync"
"sync/atomic"
"time"
"github.com/wiggin77/merror"
)
// Logr maintains a list of log targets and accepts incoming
// log records. Use `New` to create instances.
type Logr struct {
tmux sync.RWMutex // targetHosts mutex
targetHosts []*TargetHost
in chan *LogRec
quit chan struct{} // closed by Shutdown to exit read loop
done chan struct{} // closed when read loop exited
lvlCache levelCache
bufferPool sync.Pool
options *options
metricsMux sync.RWMutex
metrics *metrics
shutdown int32
}
// New creates a new Logr instance with one or more options specified.
// Some options with invalid values can cause an error to be returned,
// however `logr.New()` using just defaults never errors.
func New(opts ...Option) (*Logr, error) {
options := &options{
maxQueueSize: DefaultMaxQueueSize,
enqueueTimeout: DefaultEnqueueTimeout,
shutdownTimeout: DefaultShutdownTimeout,
flushTimeout: DefaultFlushTimeout,
maxPooledBuffer: DefaultMaxPooledBuffer,
}
lgr := &Logr{options: options}
// apply the options
for _, opt := range opts {
if err := opt(lgr); err != nil {
return nil, err
}
}
pkgName := GetLogrPackageName()
if pkgName != "" {
opt := StackFilter(pkgName, pkgName+"/targets", pkgName+"/formatters")
_ = opt(lgr)
}
lgr.in = make(chan *LogRec, lgr.options.maxQueueSize)
lgr.quit = make(chan struct{})
lgr.done = make(chan struct{})
if lgr.options.useSyncMapLevelCache {
lgr.lvlCache = &syncMapLevelCache{}
} else {
lgr.lvlCache = &arrayLevelCache{}
}
lgr.lvlCache.setup()
lgr.bufferPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
lgr.initMetrics(lgr.options.metricsCollector, lgr.options.metricsUpdateFreqMillis)
go lgr.start()
return lgr, nil
}
// AddTarget adds a target to the logger which will receive
// log records for outputting.
func (lgr *Logr) AddTarget(target Target, name string, filter Filter, formatter Formatter, maxQueueSize int) error {
if lgr.IsShutdown() {
return fmt.Errorf("AddTarget called after Logr shut down")
}
lgr.metricsMux.RLock()
metrics := lgr.metrics
lgr.metricsMux.RUnlock()
hostOpts := targetHostOptions{
name: name,
filter: filter,
formatter: formatter,
maxQueueSize: maxQueueSize,
metrics: metrics,
}
host, err := newTargetHost(target, hostOpts)
if err != nil {
return err
}
lgr.tmux.Lock()
defer lgr.tmux.Unlock()
lgr.targetHosts = append(lgr.targetHosts, host)
lgr.ResetLevelCache()
return nil
}
// NewLogger creates a Logger using defaults. A `Logger` is light-weight
// enough to create on-demand, but typically one or more Loggers are
// created and re-used.
func (lgr *Logr) NewLogger() Logger {
logger := Logger{lgr: lgr}
return logger
}
var levelStatusDisabled = LevelStatus{}
// IsLevelEnabled returns true if at least one target has the specified
// level enabled. The result is cached so that subsequent checks are fast.
func (lgr *Logr) IsLevelEnabled(lvl Level) LevelStatus {
// No levels enabled after shutdown
if atomic.LoadInt32(&lgr.shutdown) != 0 {
return levelStatusDisabled
}
// Check cache.
status, ok := lgr.lvlCache.get(lvl.ID)
if ok {
return status
}
status = LevelStatus{}
// Cache miss; check each target.
lgr.tmux.RLock()
defer lgr.tmux.RUnlock()
for _, host := range lgr.targetHosts {
enabled, level := host.IsLevelEnabled(lvl)
if enabled {
status.Enabled = true
if level.Stacktrace || host.formatter.IsStacktraceNeeded() {
status.Stacktrace = true
break // if both level and stacktrace enabled then no sense checking more targets
}
}
}
// Cache and return the result.
if err := lgr.lvlCache.put(lvl.ID, status); err != nil {
lgr.ReportError(err)
return LevelStatus{}
}
return status
}
// HasTargets returns true only if at least one target exists within the lgr.
func (lgr *Logr) HasTargets() bool {
lgr.tmux.RLock()
defer lgr.tmux.RUnlock()
return len(lgr.targetHosts) > 0
}
// TargetInfo provides name and type for a Target.
type TargetInfo struct {
Name string
Type string
}
// TargetInfos enumerates all the targets added to this lgr.
// The resulting slice represents a snapshot at time of calling.
func (lgr *Logr) TargetInfos() []TargetInfo {
infos := make([]TargetInfo, 0)
lgr.tmux.RLock()
defer lgr.tmux.RUnlock()
for _, host := range lgr.targetHosts {
inf := TargetInfo{
Name: host.String(),
Type: fmt.Sprintf("%T", host.target),
}
infos = append(infos, inf)
}
return infos
}
// RemoveTargets safely removes one or more targets based on the filtering method.
// f should return true to delete the target, false to keep it.
// When removing a target, best effort is made to write any queued log records before
// closing, with cxt determining how much time can be spent in total.
// Note, keep the timeout short since this method blocks certain logging operations.
func (lgr *Logr) RemoveTargets(cxt context.Context, f func(ti TargetInfo) bool) error {
errs := merror.New()
hosts := make([]*TargetHost, 0)
lgr.tmux.Lock()
defer lgr.tmux.Unlock()
for _, host := range lgr.targetHosts {
inf := TargetInfo{
Name: host.String(),
Type: fmt.Sprintf("%T", host.target),
}
if f(inf) {
if err := host.Shutdown(cxt); err != nil {
errs.Append(err)
}
} else {
hosts = append(hosts, host)
}
}
lgr.targetHosts = hosts
lgr.ResetLevelCache()
return errs.ErrorOrNil()
}
// ResetLevelCache resets the cached results of `IsLevelEnabled`. This is
// called any time a Target is added or a target's level is changed.
func (lgr *Logr) ResetLevelCache() {
lgr.lvlCache.clear()
}
// SetMetricsCollector sets (or resets) the metrics collector to be used for gathering
// metrics for all targets. Only targets added after this call will use the collector.
//
// To ensure all targets use a collector, use the `SetMetricsCollector` option when
// creating the Logr instead, or configure/reconfigure the Logr after calling this method.
func (lgr *Logr) SetMetricsCollector(collector MetricsCollector, updateFreqMillis int64) {
lgr.initMetrics(collector, updateFreqMillis)
}
// enqueue adds a log record to the logr queue. If the queue is full then
// this function either blocks or the log record is dropped, depending on
// the result of calling `OnQueueFull`.
func (lgr *Logr) enqueue(rec *LogRec) {
select {
case lgr.in <- rec:
default:
if lgr.options.onQueueFull != nil && lgr.options.onQueueFull(rec, cap(lgr.in)) {
return // drop the record
}
select {
case <-time.After(lgr.options.enqueueTimeout):
lgr.ReportError(fmt.Errorf("enqueue timed out for log rec [%v]", rec))
case lgr.in <- rec: // block until success or timeout
}
}
}
// Flush blocks while flushing the logr queue and all target queues, by
// writing existing log records to valid targets.
// Any attempts to add new log records will block until flush is complete.
// `logr.FlushTimeout` determines how long flush can execute before
// timing out. Use `IsTimeoutError` to determine if the returned error is
// due to a timeout.
func (lgr *Logr) Flush() error {
ctx, cancel := context.WithTimeout(context.Background(), lgr.options.flushTimeout)
defer cancel()
return lgr.FlushWithTimeout(ctx)
}
// Flush blocks while flushing the logr queue and all target queues, by
// writing existing log records to valid targets.
// Any attempts to add new log records will block until flush is complete.
// Use `IsTimeoutError` to determine if the returned error is
// due to a timeout.
func (lgr *Logr) FlushWithTimeout(ctx context.Context) error {
if !lgr.HasTargets() {
return nil
}
if lgr.IsShutdown() {
return errors.New("Flush called on shut down Logr")
}
rec := newFlushLogRec(lgr.NewLogger())
lgr.enqueue(rec)
select {
case <-ctx.Done():
return newTimeoutError("logr queue flush timeout")
case <-rec.flush:
}
return nil
}
// IsShutdown returns true if this Logr instance has been shut down.
// No further log records can be enqueued and no targets added after
// shutdown.
func (lgr *Logr) IsShutdown() bool {
return atomic.LoadInt32(&lgr.shutdown) != 0
}
// Shutdown cleanly stops the logging engine after making best efforts
// to flush all targets. Call this function right before application
// exit - logr cannot be restarted once shut down.
// `logr.ShutdownTimeout` determines how long shutdown can execute before
// timing out. Use `IsTimeoutError` to determine if the returned error is
// due to a timeout.
func (lgr *Logr) Shutdown() error {
ctx, cancel := context.WithTimeout(context.Background(), lgr.options.shutdownTimeout)
defer cancel()
return lgr.ShutdownWithTimeout(ctx)
}
// Shutdown cleanly stops the logging engine after making best efforts
// to flush all targets. Call this function right before application
// exit - logr cannot be restarted once shut down.
// Use `IsTimeoutError` to determine if the returned error is due to a
// timeout.
func (lgr *Logr) ShutdownWithTimeout(ctx context.Context) error {
if err := lgr.FlushWithTimeout(ctx); err != nil {
return err
}
if atomic.SwapInt32(&lgr.shutdown, 1) != 0 {
return errors.New("Shutdown called again after shut down")
}
lgr.ResetLevelCache()
lgr.stopMetricsUpdater()
close(lgr.quit)
errs := merror.New()
// Wait for read loop to exit
select {
case <-ctx.Done():
errs.Append(newTimeoutError("logr queue shutdown timeout"))
case <-lgr.done:
}
// logr.in channel should now be drained to targets and no more log records
// can be added.
lgr.tmux.RLock()
defer lgr.tmux.RUnlock()
for _, host := range lgr.targetHosts {
err := host.Shutdown(ctx)
if err != nil {
errs.Append(err)
}
}
return errs.ErrorOrNil()
}
// ReportError is used to notify the host application of any internal logging errors.
// If `OnLoggerError` is not nil, it is called with the error, otherwise the error is
// output to `os.Stderr`.
func (lgr *Logr) ReportError(err interface{}) {
lgr.incErrorCounter()
if lgr.options.onLoggerError == nil {
fmt.Fprintln(os.Stderr, err)
return
}
lgr.options.onLoggerError(fmt.Errorf("%v", err))
}
// BorrowBuffer borrows a buffer from the pool. Release the buffer to reduce garbage collection.
func (lgr *Logr) BorrowBuffer() *bytes.Buffer {
if lgr.options.disableBufferPool {
return &bytes.Buffer{}
}
return lgr.bufferPool.Get().(*bytes.Buffer)
}
// ReleaseBuffer returns a buffer to the pool to reduce garbage collection. The buffer is only
// retained if less than MaxPooledBuffer.
func (lgr *Logr) ReleaseBuffer(buf *bytes.Buffer) {
if !lgr.options.disableBufferPool && buf.Cap() < lgr.options.maxPooledBuffer {
buf.Reset()
lgr.bufferPool.Put(buf)
}
}
// start selects on incoming log records until shutdown record is received.
// Incoming log records are fanned out to all log targets.
func (lgr *Logr) start() {
defer func() {
if r := recover(); r != nil {
lgr.ReportError(r)
go lgr.start()
} else {
close(lgr.done)
}
}()
for {
var rec *LogRec
select {
case rec = <-lgr.in:
if rec.flush != nil {
lgr.flush(rec.flush)
} else {
rec.prep()
lgr.fanout(rec)
}
case <-lgr.quit:
return
}
}
}
// fanout pushes a LogRec to all targets.
func (lgr *Logr) fanout(rec *LogRec) {
var host *TargetHost
defer func() {
if r := recover(); r != nil {
lgr.ReportError(fmt.Errorf("fanout failed for target %s, %v", host.String(), r))
}
}()
var logged bool
lgr.tmux.RLock()
defer lgr.tmux.RUnlock()
for _, host = range lgr.targetHosts {
if enabled, _ := host.IsLevelEnabled(rec.Level()); enabled {
host.Log(rec)
logged = true
}
}
if logged {
lgr.incLoggedCounter()
}
}
// flush drains the queue and notifies when done.
func (lgr *Logr) flush(done chan<- struct{}) {
// first drain the logr queue.
loop:
for {
var rec *LogRec
select {
case rec = <-lgr.in:
if rec.flush == nil {
rec.prep()
lgr.fanout(rec)
}
default:
break loop
}
}
logger := lgr.NewLogger()
// drain all the targets; block until finished.
lgr.tmux.RLock()
defer lgr.tmux.RUnlock()
for _, host := range lgr.targetHosts {
rec := newFlushLogRec(logger)
host.Log(rec)
<-rec.flush
}
done <- struct{}{}
}

Просмотреть файл

@@ -2,24 +2,13 @@ package logr
import (
"fmt"
"path/filepath"
"runtime"
"strings"
"sync"
"time"
)
var (
logrPkg string
)
func init() {
// Calc current package name
pcs := make([]uintptr, 2)
_ = runtime.Callers(0, pcs)
tmp := runtime.FuncForPC(pcs[1]).Name()
logrPkg = getPackageName(tmp)
}
// LogRec collects raw, unformatted data to be logged.
// TODO: pool these? how to reliably know when targets are done with them? Copy for each target?
type LogRec struct {
@@ -29,9 +18,9 @@ type LogRec struct {
level Level
logger Logger
template string
newline bool
args []interface{}
msg string
newline bool
fields []Field
stackPC []uintptr
stackCount int
@@ -40,13 +29,14 @@ type LogRec struct {
flush chan struct{}
// remaining fields calculated by `prep`
msg string
frames []runtime.Frame
frames []runtime.Frame
fieldsAll []Field
caller string
}
// NewLogRec creates a new LogRec with the current time and optional stack trace.
func NewLogRec(lvl Level, logger Logger, template string, args []interface{}, incStacktrace bool) *LogRec {
rec := &LogRec{time: time.Now(), logger: logger, level: lvl, template: template, args: args}
func NewLogRec(lvl Level, logger Logger, msg string, fields []Field, incStacktrace bool) *LogRec {
rec := &LogRec{time: time.Now(), logger: logger, level: lvl, msg: msg, fields: fields}
if incStacktrace {
rec.stackPC = make([]uintptr, DefaultMaxStackFrames)
rec.stackCount = runtime.Callers(2, rec.stackPC)
@@ -60,44 +50,40 @@ func newFlushLogRec(logger Logger) *LogRec {
return &LogRec{logger: logger, flush: make(chan struct{})}
}
// prep resolves all args and field values to strings, and
// resolves stack trace to frames.
// prep resolves stack trace to frames.
func (rec *LogRec) prep() {
rec.mux.Lock()
defer rec.mux.Unlock()
// resolve args
if rec.template == "" {
if rec.newline {
rec.msg = fmt.Sprintln(rec.args...)
} else {
rec.msg = fmt.Sprint(rec.args...)
}
} else {
rec.msg = fmt.Sprintf(rec.template, rec.args...)
}
// include log rec fields and logger fields added via "With"
rec.fieldsAll = make([]Field, 0, len(rec.fields)+len(rec.logger.fields))
rec.fieldsAll = append(rec.fieldsAll, rec.logger.fields...)
rec.fieldsAll = append(rec.fieldsAll, rec.fields...)
filter := rec.logger.lgr.options.stackFilter
// resolve stack trace
if rec.stackCount > 0 {
rec.frames = make([]runtime.Frame, 0, rec.stackCount)
frames := runtime.CallersFrames(rec.stackPC[:rec.stackCount])
for {
f, more := frames.Next()
rec.frames = append(rec.frames, f)
frame, more := frames.Next()
// remove all package entries that are in filter.
pkg := ResolvePackageName(frame.Function)
if _, ok := filter[pkg]; !ok && pkg != "" {
rec.frames = append(rec.frames, frame)
}
if !more {
break
}
}
}
// remove leading logr package entries.
var start int
for i, frame := range rec.frames {
pkg := getPackageName(frame.Function)
if pkg != "" && pkg != logrPkg {
start = i
break
}
}
rec.frames = rec.frames[start:]
// calc caller if stack trace provided
if len(rec.frames) > 0 {
rec.caller = calcCaller(rec.frames)
}
}
@@ -112,10 +98,9 @@ func (rec *LogRec) WithTime(time time.Time) *LogRec {
time: time,
level: rec.level,
logger: rec.logger,
template: rec.template,
newline: rec.newline,
args: rec.args,
msg: rec.msg,
newline: rec.newline,
fields: rec.fields,
stackPC: rec.stackPC,
stackCount: rec.stackCount,
frames: rec.frames,
@@ -140,9 +125,9 @@ func (rec *LogRec) Level() Level {
}
// Fields returns this log record's Fields.
func (rec *LogRec) Fields() Fields {
func (rec *LogRec) Fields() []Field {
// no locking needed as this field is not mutated.
return rec.logger.fields
return rec.fieldsAll
}
// Msg returns this log record's message text.
@@ -160,6 +145,15 @@ func (rec *LogRec) StackFrames() []runtime.Frame {
return rec.frames
}
// Caller returns this log record's caller info, meaning the file and line
// number where this log record was emitted. Returns empty string if no
// stack trace was provided.
func (rec *LogRec) Caller() string {
rec.mux.RLock()
defer rec.mux.RUnlock()
return rec.caller
}
// String returns a string representation of this log record.
func (rec *LogRec) String() string {
if rec.flush != nil {
@@ -167,23 +161,22 @@ func (rec *LogRec) String() string {
}
f := &DefaultFormatter{}
buf := rec.logger.logr.BorrowBuffer()
defer rec.logger.logr.ReleaseBuffer(buf)
buf, _ = f.Format(rec, true, buf)
buf := rec.logger.lgr.BorrowBuffer()
defer rec.logger.lgr.ReleaseBuffer(buf)
buf, _ = f.Format(rec, rec.Level(), buf)
return strings.TrimSpace(buf.String())
}
// getPackageName reduces a fully qualified function name to the package name
// By sirupsen: https://github.com/sirupsen/logrus/blob/master/entry.go
func getPackageName(f string) string {
for {
lastPeriod := strings.LastIndex(f, ".")
lastSlash := strings.LastIndex(f, "/")
if lastPeriod > lastSlash {
f = f[:lastPeriod]
} else {
break
func calcCaller(frames []runtime.Frame) string {
for _, frame := range frames {
if frame.File == "" {
continue
}
dir, file := filepath.Split(frame.File)
base := filepath.Base(dir)
return fmt.Sprintf("%s/%s:%d", base, file, frame.Line)
}
return f
return ""
}

Просмотреть файл

@@ -1,10 +1,6 @@
package logr
import (
"errors"
"github.com/wiggin77/merror"
)
import "time"
const (
DefMetricsUpdateFreqMillis = 15000 // 15 seconds
@@ -52,66 +48,93 @@ type TargetWithMetrics interface {
EnableMetrics(collector MetricsCollector, updateFreqMillis int64) error
}
func (logr *Logr) getMetricsCollector() MetricsCollector {
logr.mux.RLock()
defer logr.mux.RUnlock()
return logr.metrics
type metrics struct {
collector MetricsCollector
updateFreqMillis int64
queueSizeGauge Gauge
loggedCounter Counter
errorCounter Counter
done chan struct{}
}
// SetMetricsCollector enables metrics collection by supplying a MetricsCollector.
// The MetricsCollector provides counters and gauges that are updated by log targets.
func (logr *Logr) SetMetricsCollector(collector MetricsCollector) error {
// initMetrics initializes metrics collection.
func (lgr *Logr) initMetrics(collector MetricsCollector, updatefreq int64) {
lgr.stopMetricsUpdater()
if collector == nil {
return errors.New("collector cannot be nil")
lgr.metricsMux.Lock()
lgr.metrics = nil
lgr.metricsMux.Unlock()
return
}
logr.mux.Lock()
logr.metrics = collector
logr.queueSizeGauge, _ = collector.QueueSizeGauge("_logr")
logr.loggedCounter, _ = collector.LoggedCounter("_logr")
logr.errorCounter, _ = collector.ErrorCounter("_logr")
logr.mux.Unlock()
metrics := &metrics{
collector: collector,
updateFreqMillis: updatefreq,
done: make(chan struct{}),
}
metrics.queueSizeGauge, _ = collector.QueueSizeGauge("_logr")
metrics.loggedCounter, _ = collector.LoggedCounter("_logr")
metrics.errorCounter, _ = collector.ErrorCounter("_logr")
logr.metricsInitOnce.Do(func() {
logr.metricsDone = make(chan struct{})
go logr.startMetricsUpdater()
})
lgr.metricsMux.Lock()
lgr.metrics = metrics
lgr.metricsMux.Unlock()
merr := merror.New()
go lgr.startMetricsUpdater()
}
logr.tmux.RLock()
defer logr.tmux.RUnlock()
for _, target := range logr.targets {
if tm, ok := target.(TargetWithMetrics); ok {
if err := tm.EnableMetrics(collector, logr.MetricsUpdateFreqMillis); err != nil {
merr.Append(err)
}
func (lgr *Logr) setQueueSizeGauge(val float64) {
lgr.metricsMux.RLock()
defer lgr.metricsMux.RUnlock()
if lgr.metrics != nil {
lgr.metrics.queueSizeGauge.Set(val)
}
}
func (lgr *Logr) incLoggedCounter() {
lgr.metricsMux.RLock()
defer lgr.metricsMux.RUnlock()
if lgr.metrics != nil {
lgr.metrics.loggedCounter.Inc()
}
}
func (lgr *Logr) incErrorCounter() {
lgr.metricsMux.RLock()
defer lgr.metricsMux.RUnlock()
if lgr.metrics != nil {
lgr.metrics.errorCounter.Inc()
}
}
// startMetricsUpdater updates the metrics for any polled values every `metricsUpdateFreqSecs` seconds until
// logr is closed.
func (lgr *Logr) startMetricsUpdater() {
for {
lgr.metricsMux.RLock()
metrics := lgr.metrics
c := metrics.done
lgr.metricsMux.RUnlock()
select {
case <-c:
return
case <-time.After(time.Duration(metrics.updateFreqMillis) * time.Millisecond):
lgr.setQueueSizeGauge(float64(len(lgr.in)))
}
}
return merr.ErrorOrNil()
}
func (logr *Logr) setQueueSizeGauge(val float64) {
logr.mux.RLock()
defer logr.mux.RUnlock()
if logr.queueSizeGauge != nil {
logr.queueSizeGauge.Set(val)
}
}
func (logr *Logr) incLoggedCounter() {
logr.mux.RLock()
defer logr.mux.RUnlock()
if logr.loggedCounter != nil {
logr.loggedCounter.Inc()
}
}
func (lgr *Logr) stopMetricsUpdater() {
lgr.metricsMux.Lock()
defer lgr.metricsMux.Unlock()
func (logr *Logr) incErrorCounter() {
logr.mux.RLock()
defer logr.mux.RUnlock()
if logr.errorCounter != nil {
logr.errorCounter.Inc()
if lgr.metrics != nil && lgr.metrics.done != nil {
close(lgr.metrics.done)
lgr.metrics.done = nil
}
}

192
vendor/github.com/mattermost/logr/v2/options.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,192 @@
package logr
import (
"errors"
"time"
)
type Option func(*Logr) error
type options struct {
maxQueueSize int
onLoggerError func(error)
onQueueFull func(rec *LogRec, maxQueueSize int) bool
onTargetQueueFull func(target Target, rec *LogRec, maxQueueSize int) bool
onExit func(code int)
onPanic func(err interface{})
enqueueTimeout time.Duration
shutdownTimeout time.Duration
flushTimeout time.Duration
useSyncMapLevelCache bool
maxPooledBuffer int
disableBufferPool bool
metricsCollector MetricsCollector
metricsUpdateFreqMillis int64
stackFilter map[string]struct{}
}
// MaxQueueSize is the maximum number of log records that can be queued.
// If exceeded, `OnQueueFull` is called which determines if the log
// record will be dropped or block until add is successful.
// Defaults to DefaultMaxQueueSize.
func MaxQueueSize(size int) Option {
return func(l *Logr) error {
if size < 0 {
return errors.New("size cannot be less than zero")
}
l.options.maxQueueSize = size
return nil
}
}
// OnLoggerError, when not nil, is called any time an internal
// logging error occurs. For example, this can happen when a
// target cannot connect to its data sink.
func OnLoggerError(f func(error)) Option {
return func(l *Logr) error {
l.options.onLoggerError = f
return nil
}
}
// OnQueueFull, when not nil, is called on an attempt to add
// a log record to a full Logr queue.
// `MaxQueueSize` can be used to modify the maximum queue size.
// This function should return quickly, with a bool indicating whether
// the log record should be dropped (true) or block until the log record
// is successfully added (false). If nil then blocking (false) is assumed.
func OnQueueFull(f func(rec *LogRec, maxQueueSize int) bool) Option {
return func(l *Logr) error {
l.options.onQueueFull = f
return nil
}
}
// OnTargetQueueFull, when not nil, is called on an attempt to add
// a log record to a full target queue provided the target supports reporting
// this condition.
// This function should return quickly, with a bool indicating whether
// the log record should be dropped (true) or block until the log record
// is successfully added (false). If nil then blocking (false) is assumed.
func OnTargetQueueFull(f func(target Target, rec *LogRec, maxQueueSize int) bool) Option {
return func(l *Logr) error {
l.options.onTargetQueueFull = f
return nil
}
}
// OnExit, when not nil, is called when a FatalXXX style log API is called.
// When nil, then the default behavior is to cleanly shut down this Logr and
// call `os.Exit(code)`.
func OnExit(f func(code int)) Option {
return func(l *Logr) error {
l.options.onExit = f
return nil
}
}
// OnPanic, when not nil, is called when a PanicXXX style log API is called.
// When nil, then the default behavior is to cleanly shut down this Logr and
// call `panic(err)`.
func OnPanic(f func(err interface{})) Option {
return func(l *Logr) error {
l.options.onPanic = f
return nil
}
}
// EnqueueTimeout is the amount of time a log record can take to be queued.
// This only applies to blocking enqueue which happen after `logr.OnQueueFull`
// is called and returns false.
func EnqueueTimeout(dur time.Duration) Option {
return func(l *Logr) error {
l.options.enqueueTimeout = dur
return nil
}
}
// ShutdownTimeout is the amount of time `logr.Shutdown` can execute before
// timing out. An alternative is to use `logr.ShutdownWithContext` and supply
// a timeout.
func ShutdownTimeout(dur time.Duration) Option {
return func(l *Logr) error {
l.options.shutdownTimeout = dur
return nil
}
}
// FlushTimeout is the amount of time `logr.Flush` can execute before
// timing out. An alternative is to use `logr.FlushWithContext` and supply
// a timeout.
func FlushTimeout(dur time.Duration) Option {
return func(l *Logr) error {
l.options.flushTimeout = dur
return nil
}
}
// UseSyncMapLevelCache can be set to true when high concurrency (e.g. >32 cores)
// is expected. This may improve performance with large numbers of cores - benchmark
// for your use case.
func UseSyncMapLevelCache(use bool) Option {
return func(l *Logr) error {
l.options.useSyncMapLevelCache = use
return nil
}
}
// MaxPooledBufferSize determines the maximum size of a buffer that can be
// pooled. To reduce allocations, the buffers needed during formatting (etc)
// are pooled. A very large log item will grow a buffer that could stay in
// memory indefinitely. This setting lets you control how big a pooled buffer
// can be - anything larger will be garbage collected after use.
// Defaults to 1MB.
func MaxPooledBufferSize(size int) Option {
return func(l *Logr) error {
l.options.maxPooledBuffer = size
return nil
}
}
// DisableBufferPool when true disables the buffer pool. See MaxPooledBuffer.
func DisableBufferPool(disable bool) Option {
return func(l *Logr) error {
l.options.disableBufferPool = disable
return nil
}
}
// SetMetricsCollector enables metrics collection by supplying a MetricsCollector.
// The MetricsCollector provides counters and gauges that are updated by log targets.
// `updateFreqMillis` determines how often polled metrics are updated. Defaults to 15000 (15 seconds)
// and must be at least 250 so we don't peg the CPU.
func SetMetricsCollector(collector MetricsCollector, updateFreqMillis int64) Option {
return func(l *Logr) error {
if collector == nil {
return errors.New("collector cannot be nil")
}
if updateFreqMillis < 250 {
return errors.New("updateFreqMillis cannot be less than 250")
}
l.options.metricsCollector = collector
l.options.metricsUpdateFreqMillis = updateFreqMillis
return nil
}
}
// StackFilter provides a list of package names to exclude from the top of
// stack traces. The Logr packages are automatically filtered.
func StackFilter(pkg ...string) Option {
return func(l *Logr) error {
if l.options.stackFilter == nil {
l.options.stackFilter = make(map[string]struct{})
}
for _, p := range pkg {
if p != "" {
l.options.stackFilter[p] = struct{}{}
}
}
return nil
}
}

57
vendor/github.com/mattermost/logr/v2/pkg.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,57 @@
package logr
import (
"runtime"
"strings"
"sync"
)
const (
maximumStackDepth int = 30
)
var (
logrPkg string
pkgCalcOnce sync.Once
)
// GetPackageName returns the root package name of Logr.
func GetLogrPackageName() string {
pkgCalcOnce.Do(func() {
logrPkg = GetPackageName("GetLogrPackageName")
})
return logrPkg
}
// GetPackageName returns the package name of the caller.
// `callingFuncName` should be the name of the calling function and
// should be unique enough not to collide with any runtime methods.
func GetPackageName(callingFuncName string) string {
var pkgName string
pcs := make([]uintptr, maximumStackDepth)
_ = runtime.Callers(0, pcs)
for _, pc := range pcs {
funcName := runtime.FuncForPC(pc).Name()
if strings.Contains(funcName, callingFuncName) {
pkgName = ResolvePackageName(funcName)
break
}
}
return pkgName
}
// ResolvePackageName reduces a fully qualified function name to the package name
func ResolvePackageName(f string) string {
for {
lastPeriod := strings.LastIndex(f, ".")
lastSlash := strings.LastIndex(f, "/")
if lastPeriod > lastSlash {
f = f[:lastPeriod]
} else {
break
}
}
return f
}

56
vendor/github.com/mattermost/logr/v2/stdlogger.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,56 @@
package logr
import (
"log"
"os"
"strings"
)
// NewStdLogger creates a standard logger backed by a Logr instance.
// All log records are emitted with the specified log level.
func NewStdLogger(level Level, logger Logger) *log.Logger {
adapter := newStdLogAdapter(logger, level)
return log.New(adapter, "", 0)
}
// RedirectStdLog redirects output from the standard library's package-global logger
// to this logger at the specified level and with zero or more Field's. Since Logr already
// handles caller annotations, timestamps, etc., it automatically disables the standard
// library's annotations and prefixing.
// A function is returned that restores the original prefix and flags and resets the standard
// library's output to os.Stderr.
func (lgr *Logr) RedirectStdLog(level Level, fields ...Field) func() {
flags := log.Flags()
prefix := log.Prefix()
log.SetFlags(0)
log.SetPrefix("")
logger := lgr.NewLogger().With(fields...)
adapter := newStdLogAdapter(logger, level)
log.SetOutput(adapter)
return func() {
log.SetFlags(flags)
log.SetPrefix(prefix)
log.SetOutput(os.Stderr)
}
}
type stdLogAdapter struct {
logger Logger
level Level
}
func newStdLogAdapter(logger Logger, level Level) *stdLogAdapter {
return &stdLogAdapter{
logger: logger,
level: level,
}
}
// Write implements io.Writer
func (a *stdLogAdapter) Write(p []byte) (int, error) {
s := strings.TrimSpace(string(p))
a.logger.Log(a.level, s)
return len(p), nil
}

119
vendor/github.com/mattermost/logr/v2/sugar.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,119 @@
package logr
import (
"fmt"
)
// Sugar provides a less structured API for logging.
type Sugar struct {
logger Logger
}
func (s Sugar) sugarLog(lvl Level, msg string, args ...interface{}) {
if s.logger.IsLevelEnabled(lvl) {
fields := make([]Field, 0, len(args))
for _, arg := range args {
fields = append(fields, Any("", arg))
}
s.logger.Log(lvl, msg, fields...)
}
}
// Trace is a convenience method equivalent to `Log(TraceLevel, msg, args...)`.
func (s Sugar) Trace(msg string, args ...interface{}) {
s.sugarLog(Trace, msg, args...)
}
// Debug is a convenience method equivalent to `Log(DebugLevel, msg, args...)`.
func (s Sugar) Debug(msg string, args ...interface{}) {
s.sugarLog(Debug, msg, args...)
}
// Print ensures compatibility with std lib logger.
func (s Sugar) Print(msg string, args ...interface{}) {
s.Info(msg, args...)
}
// Info is a convenience method equivalent to `Log(InfoLevel, msg, args...)`.
func (s Sugar) Info(msg string, args ...interface{}) {
s.sugarLog(Info, msg, args...)
}
// Warn is a convenience method equivalent to `Log(WarnLevel, msg, args...)`.
func (s Sugar) Warn(msg string, args ...interface{}) {
s.sugarLog(Warn, msg, args...)
}
// Error is a convenience method equivalent to `Log(ErrorLevel, msg, args...)`.
func (s Sugar) Error(msg string, args ...interface{}) {
s.sugarLog(Error, msg, args...)
}
// Fatal is a convenience method equivalent to `Log(FatalLevel, msg, args...)`
func (s Sugar) Fatal(msg string, args ...interface{}) {
s.sugarLog(Fatal, msg, args...)
}
// Panic is a convenience method equivalent to `Log(PanicLevel, msg, args...)`
func (s Sugar) Panic(msg string, args ...interface{}) {
s.sugarLog(Panic, msg, args...)
}
//
// Printf style
//
// Logf checks that the level matches one or more targets, and
// if so, generates a log record that is added to the main
// queue (channel). Arguments are handled in the manner of fmt.Printf.
func (s Sugar) Logf(lvl Level, format string, args ...interface{}) {
if s.logger.IsLevelEnabled(lvl) {
var msg string
if format == "" {
msg = fmt.Sprint(args...)
} else {
msg = fmt.Sprintf(format, args...)
}
s.logger.Log(lvl, msg)
}
}
// Tracef is a convenience method equivalent to `Logf(TraceLevel, args...)`.
func (s Sugar) Tracef(format string, args ...interface{}) {
s.Logf(Trace, format, args...)
}
// Debugf is a convenience method equivalent to `Logf(DebugLevel, args...)`.
func (s Sugar) Debugf(format string, args ...interface{}) {
s.Logf(Debug, format, args...)
}
// Infof is a convenience method equivalent to `Logf(InfoLevel, args...)`.
func (s Sugar) Infof(format string, args ...interface{}) {
s.Logf(Info, format, args...)
}
// Printf ensures compatibility with std lib logger.
func (s Sugar) Printf(format string, args ...interface{}) {
s.Infof(format, args...)
}
// Warnf is a convenience method equivalent to `Logf(WarnLevel, args...)`.
func (s Sugar) Warnf(format string, args ...interface{}) {
s.Logf(Warn, format, args...)
}
// Errorf is a convenience method equivalent to `Logf(ErrorLevel, args...)`.
func (s Sugar) Errorf(format string, args ...interface{}) {
s.Logf(Error, format, args...)
}
// Fatalf is a convenience method equivalent to `Logf(FatalLevel, args...)`
func (s Sugar) Fatalf(format string, args ...interface{}) {
s.Logf(Fatal, format, args...)
}
// Panicf is a convenience method equivalent to `Logf(PanicLevel, args...)`
func (s Sugar) Panicf(format string, args ...interface{}) {
s.Logf(Panic, format, args...)
}

304
vendor/github.com/mattermost/logr/v2/target.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,304 @@
package logr
import (
"context"
"errors"
"fmt"
"os"
"sync/atomic"
"time"
)
// Target represents a destination for log records such as file,
// database, TCP socket, etc.
type Target interface {
// Init is called once to initialize the target.
Init() error
// Write outputs to this target's destination.
Write(p []byte, rec *LogRec) (int, error)
// Shutdown is called once to free/close any resources.
// Target queue is already drained when this is called.
Shutdown() error
}
type targetMetrics struct {
queueSizeGauge Gauge
loggedCounter Counter
errorCounter Counter
droppedCounter Counter
blockedCounter Counter
}
type targetHostOptions struct {
name string
filter Filter
formatter Formatter
maxQueueSize int
metrics *metrics
}
// TargetHost hosts and manages the lifecycle of a target.
// Incoming log records are queued and formatted before
// being passed to the target.
type TargetHost struct {
target Target
name string
filter Filter
formatter Formatter
in chan *LogRec
quit chan struct{} // closed by Shutdown to exit read loop
done chan struct{} // closed when read loop exited
targetMetrics *targetMetrics
shutdown int32
}
func newTargetHost(target Target, options targetHostOptions) (*TargetHost, error) {
host := &TargetHost{
target: target,
name: options.name,
filter: options.filter,
formatter: options.formatter,
in: make(chan *LogRec, options.maxQueueSize),
quit: make(chan struct{}),
done: make(chan struct{}),
}
if host.name == "" {
host.name = fmt.Sprintf("%T", target)
}
if host.filter == nil {
host.filter = &StdFilter{Lvl: Fatal}
}
if host.formatter == nil {
host.formatter = &DefaultFormatter{}
}
err := host.initMetrics(options.metrics)
if err != nil {
return nil, err
}
err = target.Init()
if err != nil {
return nil, err
}
go host.start()
return host, nil
}
func (h *TargetHost) initMetrics(metrics *metrics) error {
if metrics == nil {
return nil
}
var err error
tmetrics := &targetMetrics{}
if tmetrics.queueSizeGauge, err = metrics.collector.QueueSizeGauge(h.name); err != nil {
return err
}
if tmetrics.loggedCounter, err = metrics.collector.LoggedCounter(h.name); err != nil {
return err
}
if tmetrics.errorCounter, err = metrics.collector.ErrorCounter(h.name); err != nil {
return err
}
if tmetrics.droppedCounter, err = metrics.collector.DroppedCounter(h.name); err != nil {
return err
}
if tmetrics.blockedCounter, err = metrics.collector.BlockedCounter(h.name); err != nil {
return err
}
h.targetMetrics = tmetrics
updateFreqMillis := metrics.updateFreqMillis
if updateFreqMillis == 0 {
updateFreqMillis = DefMetricsUpdateFreqMillis
}
if updateFreqMillis < 250 {
updateFreqMillis = 250 // don't peg the CPU
}
go h.startMetricsUpdater(updateFreqMillis)
return nil
}
// IsLevelEnabled returns true if this target should emit logs for the specified level.
func (h *TargetHost) IsLevelEnabled(lvl Level) (enabled bool, level Level) {
level, enabled = h.filter.GetEnabledLevel(lvl)
return enabled, level
}
// Shutdown stops processing log records after making best
// effort to flush queue.
func (h *TargetHost) Shutdown(ctx context.Context) error {
if atomic.SwapInt32(&h.shutdown, 1) != 0 {
return errors.New("targetHost shutdown called more than once")
}
close(h.quit)
// No more records can be accepted; now wait for read loop to exit.
select {
case <-ctx.Done():
case <-h.done:
}
// b.in channel should now be drained.
return h.target.Shutdown()
}
// Log queues a log record to be output to this target's destination.
func (h *TargetHost) Log(rec *LogRec) {
if atomic.LoadInt32(&h.shutdown) != 0 {
return
}
lgr := rec.Logger().Logr()
select {
case h.in <- rec:
default:
handler := lgr.options.onTargetQueueFull
if handler != nil && handler(h.target, rec, cap(h.in)) {
h.incDroppedCounter()
return // drop the record
}
h.incBlockedCounter()
select {
case <-time.After(lgr.options.enqueueTimeout):
lgr.ReportError(fmt.Errorf("target enqueue timeout for log rec [%v]", rec))
case h.in <- rec: // block until success or timeout
}
}
}
func (h *TargetHost) setQueueSizeGauge(val float64) {
if h.targetMetrics != nil {
h.targetMetrics.queueSizeGauge.Set(val)
}
}
func (h *TargetHost) incLoggedCounter() {
if h.targetMetrics != nil {
h.targetMetrics.loggedCounter.Inc()
}
}
func (h *TargetHost) incErrorCounter() {
if h.targetMetrics != nil {
h.targetMetrics.errorCounter.Inc()
}
}
func (h *TargetHost) incDroppedCounter() {
if h.targetMetrics != nil {
h.targetMetrics.droppedCounter.Inc()
}
}
func (h *TargetHost) incBlockedCounter() {
if h.targetMetrics != nil {
h.targetMetrics.blockedCounter.Inc()
}
}
// String returns a name for this target.
func (h *TargetHost) String() string {
return h.name
}
// start accepts log records via In channel and writes to the
// supplied target, until Done channel signaled.
func (h *TargetHost) start() {
defer func() {
if r := recover(); r != nil {
fmt.Fprintln(os.Stderr, "TargetHost.start -- ", r)
go h.start()
} else {
close(h.done)
}
}()
for {
var rec *LogRec
select {
case rec = <-h.in:
if rec.flush != nil {
h.flush(rec.flush)
} else {
err := h.writeRec(rec)
if err != nil {
h.incErrorCounter()
rec.Logger().Logr().ReportError(err)
} else {
h.incLoggedCounter()
}
}
case <-h.quit:
return
}
}
}
func (h *TargetHost) writeRec(rec *LogRec) error {
level, enabled := h.filter.GetEnabledLevel(rec.Level())
if !enabled {
// how did we get here?
return fmt.Errorf("level %s not enabled for target %s", rec.Level().Name, h.name)
}
buf := rec.logger.lgr.BorrowBuffer()
defer rec.logger.lgr.ReleaseBuffer(buf)
buf, err := h.formatter.Format(rec, level, buf)
if err != nil {
return err
}
_, err = h.target.Write(buf.Bytes(), rec)
return err
}
// startMetricsUpdater updates the metrics for any polled values every `updateFreqMillis` seconds until
// target is shut down.
func (h *TargetHost) startMetricsUpdater(updateFreqMillis int64) {
for {
select {
case <-h.done:
return
case <-time.After(time.Duration(updateFreqMillis) * time.Millisecond):
h.setQueueSizeGauge(float64(len(h.in)))
}
}
}
// flush drains the queue and notifies when done.
func (h *TargetHost) flush(done chan<- struct{}) {
for {
var rec *LogRec
var err error
select {
case rec = <-h.in:
// ignore any redundant flush records.
if rec.flush == nil {
err = h.writeRec(rec)
if err != nil {
h.incErrorCounter()
rec.Logger().Logr().ReportError(err)
}
}
default:
done <- struct{}{}
return
}
}
}

Просмотреть файл

@@ -1,11 +1,10 @@
package target
package targets
import (
"context"
"errors"
"io"
"github.com/mattermost/logr"
"github.com/wiggin77/merror"
"github.com/mattermost/logr/v2"
"gopkg.in/natefinch/lumberjack.v2"
)
@@ -13,38 +12,44 @@ type FileOptions struct {
// Filename is the file to write logs to. Backup log files will be retained
// in the same directory. It uses <processname>-lumberjack.log in
// os.TempDir() if empty.
Filename string
Filename string `json:"filename"`
// MaxSize is the maximum size in megabytes of the log file before it gets
// rotated. It defaults to 100 megabytes.
MaxSize int
MaxSize int `json:"max_size"`
// MaxAge is the maximum number of days to retain old log files based on the
// timestamp encoded in their filename. Note that a day is defined as 24
// hours and may not exactly correspond to calendar days due to daylight
// savings, leap seconds, etc. The default is not to remove old log files
// based on age.
MaxAge int
MaxAge int `json:"max_age"`
// MaxBackups is the maximum number of old log files to retain. The default
// is to retain all old log files (though MaxAge may still cause them to get
// deleted.)
MaxBackups int
MaxBackups int `json:"max_backups"`
// Compress determines if the rotated log files should be compressed
// using gzip. The default is not to perform compression.
Compress bool
Compress bool `json:"compress"`
}
func (fo FileOptions) CheckValid() error {
if fo.Filename == "" {
return errors.New("filename cannot be empty")
}
return nil
}
// File outputs log records to a file which can be log rotated based on size or age.
// Uses `https://github.com/natefinch/lumberjack` for rotation.
type File struct {
logr.Basic
out io.WriteCloser
}
// NewFileTarget creates a target capable of outputting log records to a rotated file.
func NewFileTarget(filter logr.Filter, formatter logr.Formatter, opts FileOptions, maxQueue int) *File {
func NewFileTarget(opts FileOptions) *File {
lumber := &lumberjack.Logger{
Filename: opts.Filename,
MaxSize: opts.MaxSize,
@@ -53,35 +58,21 @@ func NewFileTarget(filter logr.Filter, formatter logr.Formatter, opts FileOption
Compress: opts.Compress,
}
f := &File{out: lumber}
f.Basic.Start(f, f, filter, formatter, maxQueue)
return f
}
// Write converts the log record to bytes, via the Formatter,
// and outputs to a file.
func (f *File) Write(rec *logr.LogRec) error {
_, stacktrace := f.IsLevelEnabled(rec.Level())
buf := rec.Logger().Logr().BorrowBuffer()
defer rec.Logger().Logr().ReleaseBuffer(buf)
buf, err := f.Formatter().Format(rec, stacktrace, buf)
if err != nil {
return err
}
_, err = f.out.Write(buf.Bytes())
return err
// Init is called once to initialize the target.
func (f *File) Init() error {
return nil
}
// Shutdown flushes any remaining log records and closes the file.
func (f *File) Shutdown(ctx context.Context) error {
errs := merror.New()
err := f.Basic.Shutdown(ctx)
errs.Append(err)
err = f.out.Close()
errs.Append(err)
return errs.ErrorOrNil()
// Write outputs bytes to this file target.
func (f *File) Write(p []byte, rec *logr.LogRec) (int, error) {
return f.out.Write(p)
}
// Shutdown is called once to free/close any resources.
// Target queue is already drained when this is called.
func (f *File) Shutdown() error {
return f.out.Close()
}

112
vendor/github.com/mattermost/logr/v2/targets/syslog.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,112 @@
// +build !windows,!nacl,!plan9
package targets
import (
"crypto/tls"
"errors"
"fmt"
"github.com/mattermost/logr/v2"
syslog "github.com/wiggin77/srslog"
)
// Syslog outputs log records to local or remote syslog.
type Syslog struct {
params *SyslogOptions
writer *syslog.Writer
}
// SyslogOptions provides parameters for dialing a syslog daemon.
type SyslogOptions struct {
IP string `json:"ip,omitempty"` // deprecated
Host string `json:"host"`
Port int `json:"port"`
TLS bool `json:"tls"`
Cert string `json:"cert"`
Insecure bool `json:"insecure"`
Tag string `json:"tag"`
}
func (so SyslogOptions) CheckValid() error {
if so.Host == "" && so.IP == "" {
return errors.New("missing host")
}
if so.Port == 0 {
return errors.New("missing port")
}
return nil
}
// NewSyslogTarget creates a target capable of outputting log records to remote or local syslog, with or without TLS.
func NewSyslogTarget(params *SyslogOptions) (*Syslog, error) {
if params == nil {
return nil, errors.New("params cannot be nil")
}
s := &Syslog{
params: params,
}
return s, nil
}
// Init is called once to initialize the target.
func (s *Syslog) Init() error {
network := "tcp"
var config *tls.Config
if s.params.TLS {
network = "tcp+tls"
config = &tls.Config{InsecureSkipVerify: s.params.Insecure}
if s.params.Cert != "" {
pool, err := GetCertPool(s.params.Cert)
if err != nil {
return err
}
config.RootCAs = pool
}
}
raddr := fmt.Sprintf("%s:%d", s.params.IP, s.params.Port)
if raddr == ":0" {
// If no IP:port provided then connect to local syslog.
raddr = ""
network = ""
}
var err error
s.writer, err = syslog.DialWithTLSConfig(network, raddr, syslog.LOG_INFO, s.params.Tag, config)
return err
}
// Write outputs bytes to this file target.
func (s *Syslog) Write(p []byte, rec *logr.LogRec) (int, error) {
txt := string(p)
n := len(txt)
var err error
switch rec.Level() {
case logr.Panic, logr.Fatal:
err = s.writer.Crit(txt)
case logr.Error:
err = s.writer.Err(txt)
case logr.Warn:
err = s.writer.Warning(txt)
case logr.Debug, logr.Trace:
err = s.writer.Debug(txt)
default:
// logr.Info plus all custom levels.
err = s.writer.Info(txt)
}
if err != nil {
n = 0
// syslog writer will try to reconnect.
}
return n, err
}
// Shutdown is called once to free/close any resources.
// Target queue is already drained when this is called.
func (s *Syslog) Shutdown() error {
return s.writer.Close()
}

56
vendor/github.com/mattermost/logr/v2/targets/syslog_unsupported.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,56 @@
// +build windows nacl plan9
package targets
import (
"errors"
"github.com/mattermost/logr/v2"
syslog "github.com/wiggin77/srslog"
)
const (
unsupported = "Syslog target is not supported on this platform."
)
// Syslog outputs log records to local or remote syslog.
type Syslog struct {
params *SyslogOptions
writer *syslog.Writer
}
// SyslogOptions provides parameters for dialing a syslog daemon.
type SyslogOptions struct {
IP string `json:"ip,omitempty"` // deprecated
Host string `json:"host"`
Port int `json:"port"`
TLS bool `json:"tls"`
Cert string `json:"cert"`
Insecure bool `json:"insecure"`
Tag string `json:"tag"`
}
func (so SyslogOptions) CheckValid() error {
return errors.New(unsupported)
}
// NewSyslogTarget creates a target capable of outputting log records to remote or local syslog, with or without TLS.
func NewSyslogTarget(params *SyslogOptions) (*Syslog, error) {
return nil, errors.New(unsupported)
}
// Init is called once to initialize the target.
func (s *Syslog) Init() error {
return errors.New(unsupported)
}
// Write outputs bytes to this file target.
func (s *Syslog) Write(p []byte, rec *logr.LogRec) (int, error) {
return 0, errors.New(unsupported)
}
// Shutdown is called once to free/close any resources.
// Target queue is already drained when this is called.
func (s *Syslog) Shutdown() error {
return errors.New(unsupported)
}

251
vendor/github.com/mattermost/logr/v2/targets/tcp.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,251 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package targets
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"sync"
"time"
"github.com/mattermost/logr/v2"
)
const (
DialTimeoutSecs = 30
WriteTimeoutSecs = 30
RetryBackoffMillis int64 = 100
MaxRetryBackoffMillis int64 = 30 * 1000 // 30 seconds
)
// Tcp outputs log records to raw socket server.
type Tcp struct {
options *TcpOptions
addy string
mutex sync.Mutex
conn net.Conn
monitor chan struct{}
shutdown chan struct{}
}
// TcpOptions provides parameters for dialing a socket server.
type TcpOptions struct {
IP string `json:"ip,omitempty"` // deprecated
Host string `json:"host"`
Port int `json:"port"`
TLS bool `json:"tls"`
Cert string `json:"cert"`
Insecure bool `json:"insecure"`
}
func (to TcpOptions) CheckValid() error {
if to.Host == "" && to.IP == "" {
return errors.New("missing host")
}
if to.Port == 0 {
return errors.New("missing port")
}
return nil
}
// NewTcpTarget creates a target capable of outputting log records to a raw socket, with or without TLS.
func NewTcpTarget(options *TcpOptions) *Tcp {
tcp := &Tcp{
options: options,
addy: fmt.Sprintf("%s:%d", options.IP, options.Port),
monitor: make(chan struct{}),
shutdown: make(chan struct{}),
}
return tcp
}
// Init is called once to initialize the target.
func (tcp *Tcp) Init() error {
return nil
}
// getConn provides a net.Conn. If a connection already exists, it is returned immediately,
// otherwise this method blocks until a new connection is created, timeout or shutdown.
func (tcp *Tcp) getConn(reporter func(err interface{})) (net.Conn, error) {
tcp.mutex.Lock()
defer tcp.mutex.Unlock()
if tcp.conn != nil {
return tcp.conn, nil
}
type result struct {
conn net.Conn
err error
}
connChan := make(chan result)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*DialTimeoutSecs)
defer cancel()
go func(ctx context.Context, ch chan result) {
conn, err := tcp.dial(ctx)
if err != nil {
reporter(fmt.Errorf("log target %s connection error: %w", tcp.String(), err))
return
}
tcp.conn = conn
tcp.monitor = make(chan struct{})
go monitor(tcp.conn, tcp.monitor)
ch <- result{conn: conn, err: err}
}(ctx, connChan)
select {
case <-tcp.shutdown:
return nil, errors.New("shutdown")
case res := <-connChan:
return res.conn, res.err
}
}
// dial connects to a TCP socket, and optionally performs a TLS handshake.
// A non-nil context must be provided which can cancel the dial.
func (tcp *Tcp) dial(ctx context.Context) (net.Conn, error) {
var dialer net.Dialer
dialer.Timeout = time.Second * DialTimeoutSecs
conn, err := dialer.DialContext(ctx, "tcp", fmt.Sprintf("%s:%d", tcp.options.IP, tcp.options.Port))
if err != nil {
return nil, err
}
if !tcp.options.TLS {
return conn, nil
}
tlsconfig := &tls.Config{
ServerName: tcp.options.IP,
InsecureSkipVerify: tcp.options.Insecure,
}
if tcp.options.Cert != "" {
pool, err := GetCertPool(tcp.options.Cert)
if err != nil {
return nil, err
}
tlsconfig.RootCAs = pool
}
tlsConn := tls.Client(conn, tlsconfig)
if err := tlsConn.Handshake(); err != nil {
return nil, err
}
return tlsConn, nil
}
func (tcp *Tcp) close() error {
tcp.mutex.Lock()
defer tcp.mutex.Unlock()
var err error
if tcp.conn != nil {
close(tcp.monitor)
err = tcp.conn.Close()
tcp.conn = nil
}
return err
}
// Shutdown stops processing log records after making best effort to flush queue.
func (tcp *Tcp) Shutdown() error {
err := tcp.close()
close(tcp.shutdown)
return err
}
// Write converts the log record to bytes, via the Formatter, and outputs to the socket.
// Called by dedicated target goroutine and will block until success or shutdown.
func (tcp *Tcp) Write(p []byte, rec *logr.LogRec) (int, error) {
try := 1
backoff := RetryBackoffMillis
for {
select {
case <-tcp.shutdown:
return 0, nil
default:
}
reporter := rec.Logger().Logr().ReportError
conn, err := tcp.getConn(reporter)
if err != nil {
reporter(fmt.Errorf("log target %s connection error: %w", tcp.String(), err))
backoff = tcp.sleep(backoff)
continue
}
err = conn.SetWriteDeadline(time.Now().Add(time.Second * WriteTimeoutSecs))
if err != nil {
reporter(fmt.Errorf("log target %s set write deadline error: %w", tcp.String(), err))
}
count, err := conn.Write(p)
if err == nil {
return count, nil
}
reporter(fmt.Errorf("log target %s write error: %w", tcp.String(), err))
_ = tcp.close()
backoff = tcp.sleep(backoff)
try++
}
}
// monitor continuously tries to read from the connection to detect socket close.
// This is needed because TCP target uses a write only socket and Linux systems
// take a long time to detect a loss of connectivity on a socket when only writing;
// the writes simply fail without an error returned.
func monitor(conn net.Conn, done <-chan struct{}) {
buf := make([]byte, 1)
for {
select {
case <-done:
return
case <-time.After(1 * time.Second):
}
err := conn.SetReadDeadline(time.Now().Add(time.Second * 30))
if err != nil {
continue
}
_, err = conn.Read(buf)
if errt, ok := err.(net.Error); ok && errt.Timeout() {
// read timeout is expected, keep looping.
continue
}
// Any other error closes the connection, forcing a reconnect.
conn.Close()
return
}
}
// String returns a string representation of this target.
func (tcp *Tcp) String() string {
return fmt.Sprintf("TcpTarget[%s:%d]", tcp.options.IP, tcp.options.Port)
}
func (tcp *Tcp) sleep(backoff int64) int64 {
select {
case <-tcp.shutdown:
case <-time.After(time.Millisecond * time.Duration(backoff)):
}
nextBackoff := backoff + (backoff >> 1)
if nextBackoff > MaxRetryBackoffMillis {
nextBackoff = MaxRetryBackoffMillis
}
return nextBackoff
}

43
vendor/github.com/mattermost/logr/v2/targets/test-tls-client-cert.pem сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,43 @@
-----BEGIN CERTIFICATE-----
MIIDjzCCAnegAwIBAgIRAPYfRSwdzKopBKxYxKqslJUwDQYJKoZIhvcNAQELBQAw
JzElMCMGA1UEAwwcTWF0dGVybW9zdCwgSW5jLiBJbnRlcm5hbCBDQTAeFw0xOTAz
MjIwMDE0MTVaFw0yMjAzMDYwMDE0MTVaMDsxOTA3BgNVBAMTME1hdHRlcm1vc3Qs
IEluYy4gSW50ZXJuYWwgSW50ZXJtZWRpYXRlIEF1dGhvcml0eTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAMjliRdmvnNL4u/Jr/M2dPwQmTJXEBY/Vq9Q
vAU52X3tRMCPxcaFz+x6ftuvdO2NdohXGAmtx9QU5LZcvFeTDpoVEBo9A+4jtLvD
DZYaTNLpJmoSoJHaDbdWX+OAOqyDiWS741LuiMKWHhew9QOisat2ZINPxjmAd9wE
xthTMgzsv7MUqnMer8U5OGQ0Qy7wAmNRc+2K3qPwkxe2RUvcte50DUFNgxEginsh
vrkOXR383vUCZfu72qu8oggjiQpyTllu5je2Ap6JLjYLkEMiMqrYADuWor/ZHwa6
WrFqVETxWfAV5u9Eh0wZM/KKYwRQuw9y+Nans77FmUl1tVWWNN8CAwEAAaOBoTCB
njAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBQY4Uqswyr2hO/HetZt2RDxJdTIPjBi
BgNVHSMEWzBZgBRFZXVg2Z5tNIsWeWjBLEy2yzKbMKErpCkwJzElMCMGA1UEAwwc
TWF0dGVybW9zdCwgSW5jLiBJbnRlcm5hbCBDQYIUEifGUOM+bIFZo1tkjZB5YGBr
0xEwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQAEdexL30Q0zBHmPAH8
LhdK7dbzW1CmILbxRZlKAwRN+hKRXiMW3MHIkhNuoV9Aev602Q+ja4lWsRi/ktOL
ni1FWx5gSScgdG8JGj47dOmoT3vXKX7+umiv4rQLPDl9/DKMuv204OYJq6VT+uNU
6C6kL157jGJEO76H4fMZ8oYsD7Sq0zjiNKtuCYii0ngH3j3gB1jACLqRgveU7MdT
pqOV2KfY31+h8VBtkUvljNztQ9xNY8Fjmt0SMf7E3FaUcaar3ZCr70G5aU3dKbe7
47vGOBa5tCqw4YK0jgDKid3IJQul9a3J1mSsH8Wy3to9cAV4KGZBQLnzCX15a/+v
3yVh
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDfjCCAmagAwIBAgIUEifGUOM+bIFZo1tkjZB5YGBr0xEwDQYJKoZIhvcNAQEL
BQAwJzElMCMGA1UEAwwcTWF0dGVybW9zdCwgSW5jLiBJbnRlcm5hbCBDQTAeFw0x
OTAzMjEyMTI4NDNaFw0yOTAzMTgyMTI4NDNaMCcxJTAjBgNVBAMMHE1hdHRlcm1v
c3QsIEluYy4gSW50ZXJuYWwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDH0Xq5rMBGpKOVWTpb5MnaJIWFP/vOtvEk+7hVrfOfe1/5x0Kk3UgAHj85
otaEZD1Lhn/JLkEqCiE/UXMJFwJDlNcO4CkdKBSpYX4bKAqy5q/X3QwioMSNpJG1
+YYrNGBH0sgKcKjyCaLhmqYLD0xZDVOmWIYBU9jUPyXw5U0tnsVrTqGMxVkm1xCY
krCWN1ZoUrLvL0MCZc5qpxoPTopr9UO9cqSBSuy6BVWVuEWBZhpqHt+ul8VxhzzY
q1k4l7r2qw+/wm1iJBedTeBVeWNag8JaVfLgu+/W7oJVlPO32Po7pnvHp8iJ3b4K
zXyVHaTX4S6Em+6LV8855TYrShzlAgMBAAGjgaEwgZ4wHQYDVR0OBBYEFEVldWDZ
nm00ixZ5aMEsTLbLMpswMGIGA1UdIwRbMFmAFEVldWDZnm00ixZ5aMEsTLbLMpsw
oSukKTAnMSUwIwYDVQQDDBxNYXR0ZXJtb3N0LCBJbmMuIEludGVybmFsIENBghQS
J8ZQ4z5sgVmjW2SNkHlgYGvTETAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjAN
BgkqhkiG9w0BAQsFAAOCAQEAPiCWFmopyAkY2T3Zyo4yaRPhX1+VOTMKJtY6EUhq
/GHz6kzEyvCUBf0N892cibGxekrEoItY9NqO6RQRfowg+Gn5kc13z4NyL2W8/eoT
Xy0ZvfaQbU++fQ6pVtWtMblDMU9xiYd7/MDvJpO328l1Vhcdp8kEi+lCvpy0sCRc
PxzPhbgCMAbZEGx+4TMQd4SZKzlRxW/2fflpReh6v1Dv0VDUSYQWwsUnaLpdKHfh
a5k0vuySYcszE4YKlY0zakeFlJfp7fBp1xTwcdW8aTfw15EicPMwTc6xxA4JJUJx
cddu817n1nayK5u6r9Qh1oIVkr0nC9YELMMy4dpPgJ88SA==
-----END CERTIFICATE-----

33
vendor/github.com/mattermost/logr/v2/targets/utils.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,33 @@
package targets
import (
"crypto/x509"
"encoding/base64"
"errors"
"io/ioutil"
)
// GetCertPool returns a x509.CertPool containing the cert(s)
// from `cert`, which can be a path to a .pem or .crt file,
// or a base64 encoded cert.
func GetCertPool(cert string) (*x509.CertPool, error) {
if cert == "" {
return nil, errors.New("no cert provided")
}
// first treat as a file and try to read.
serverCert, err := ioutil.ReadFile(cert)
if err != nil {
// maybe it's a base64 encoded cert
serverCert, err = base64.StdEncoding.DecodeString(cert)
if err != nil {
return nil, errors.New("cert cannot be read")
}
}
pool := x509.NewCertPool()
if ok := pool.AppendCertsFromPEM(serverCert); ok {
return pool, nil
}
return nil, errors.New("cannot parse cert")
}

38
vendor/github.com/mattermost/logr/v2/targets/writer.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,38 @@
package targets
import (
"io"
"io/ioutil"
"github.com/mattermost/logr/v2"
)
// Writer outputs log records to any `io.Writer`.
type Writer struct {
out io.Writer
}
// NewWriterTarget creates a target capable of outputting log records to an io.Writer.
func NewWriterTarget(out io.Writer) *Writer {
if out == nil {
out = ioutil.Discard
}
w := &Writer{out: out}
return w
}
// Init is called once to initialize the target.
func (w *Writer) Init() error {
return nil
}
// Write outputs bytes to this file target.
func (w *Writer) Write(p []byte, rec *logr.LogRec) (int, error) {
return w.out.Write(p)
}
// Shutdown is called once to free/close any resources.
// Target queue is already drained when this is called.
func (w *Writer) Shutdown() error {
return nil
}

Просмотреть файл

12
vendor/github.com/wiggin77/cfg/.gitignore сгенерированный поставляемый
Просмотреть файл

@@ -1,12 +0,0 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

5
vendor/github.com/wiggin77/cfg/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -1,5 +0,0 @@
language: go
sudo: false
before_script:
- go vet ./...

21
vendor/github.com/wiggin77/cfg/LICENSE сгенерированный поставляемый
Просмотреть файл

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 wiggin77
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.

43
vendor/github.com/wiggin77/cfg/README.md сгенерированный поставляемый
Просмотреть файл

@@ -1,43 +0,0 @@
# cfg
[![GoDoc](https://godoc.org/github.com/wiggin77/cfg?status.svg)](https://godoc.org/github.com/wiggin77/cfg)
[![Build Status](https://travis-ci.org/wiggin77/cfg.svg?branch=master)](https://travis-ci.org/wiggin77/cfg)
Go package for app configuration. Supports chained configuration sources for multiple levels of defaults.
Includes APIs for loading Linux style configuration files (name/value pairs) or INI files, map based properties,
or easily create new configuration sources (e.g. load from database).
Supports monitoring configuration sources for changes, hot loading properties, and notifying listeners of changes.
## Usage
```Go
config := &cfg.Config{}
defer config.Shutdown() // stops monitoring
// load file via filespec string, os.File
src, err := Config.NewSrcFileFromFilespec("./myfile.conf")
if err != nil {
return err
}
// add src to top of chain, meaning first searched
cfg.PrependSource(src)
// fetch prop 'retries', default to 3 if not found
val := config.Int("retries", 3)
```
See [example](./example_test.go) for more complete example, including listening for configuration changes.
Config API parses the following data types:
| type | method | example property values |
| ------- | ------ | -------- |
| string | Config.String | test, "" |
| int | Config.Int | -1, 77, 0 |
| int64 | Config.Int64 | -9223372036854775, 372036854775808 |
| float64 | Config.Float64 | -77.3456, 95642331.1 |
| bool | Config.Bool | T,t,true,True,1,0,False,false,f,F |
| time.Duration | Config.Duration | "10ms", "2 hours", "5 min" * |
\* Units of measure supported: ms, sec, min, hour, day, week, year.

366
vendor/github.com/wiggin77/cfg/config.go сгенерированный поставляемый
Просмотреть файл

@@ -1,366 +0,0 @@
package cfg
import (
"errors"
"fmt"
"strconv"
"strings"
"sync"
"time"
"github.com/wiggin77/cfg/timeconv"
)
// ErrNotFound returned when an operation is attempted on a
// resource that doesn't exist, such as fetching a non-existing
// property name.
var ErrNotFound = errors.New("not found")
type sourceEntry struct {
src Source
props map[string]string
}
// Config provides methods for retrieving property values from one or more
// configuration sources.
type Config struct {
mutexSrc sync.RWMutex
mutexListeners sync.RWMutex
srcs []*sourceEntry
chgListeners []ChangedListener
shutdown chan interface{}
wantPanicOnError bool
}
// PrependSource inserts one or more `Sources` at the beginning of
// the list of sources such that the first source will be the
// source checked first when resolving a property value.
func (config *Config) PrependSource(srcs ...Source) {
arr := config.wrapSources(srcs...)
config.mutexSrc.Lock()
if config.shutdown == nil {
config.shutdown = make(chan interface{})
}
config.srcs = append(arr, config.srcs...)
config.mutexSrc.Unlock()
for _, se := range arr {
if _, ok := se.src.(SourceMonitored); ok {
config.monitor(se)
}
}
}
// AppendSource appends one or more `Sources` at the end of
// the list of sources such that the last source will be the
// source checked last when resolving a property value.
func (config *Config) AppendSource(srcs ...Source) {
arr := config.wrapSources(srcs...)
config.mutexSrc.Lock()
if config.shutdown == nil {
config.shutdown = make(chan interface{})
}
config.srcs = append(config.srcs, arr...)
config.mutexSrc.Unlock()
for _, se := range arr {
if _, ok := se.src.(SourceMonitored); ok {
config.monitor(se)
}
}
}
// wrapSources wraps one or more Source's and returns
// them as an array of `sourceEntry`.
func (config *Config) wrapSources(srcs ...Source) []*sourceEntry {
arr := make([]*sourceEntry, 0, len(srcs))
for _, src := range srcs {
se := &sourceEntry{src: src}
config.reloadProps(se)
arr = append(arr, se)
}
return arr
}
// SetWantPanicOnError sets the flag determining if Config
// should panic when `GetProps` or `GetLastModified` errors
// for a `Source`.
func (config *Config) SetWantPanicOnError(b bool) {
config.mutexSrc.Lock()
config.wantPanicOnError = b
config.mutexSrc.Unlock()
}
// ShouldPanicOnError gets the flag determining if Config
// should panic when `GetProps` or `GetLastModified` errors
// for a `Source`.
func (config *Config) ShouldPanicOnError() (b bool) {
config.mutexSrc.RLock()
b = config.wantPanicOnError
config.mutexSrc.RUnlock()
return b
}
// getProp returns the value of a named property.
// Each `Source` is checked, in the order created by adding via
// `AppendSource` and `PrependSource`, until a value for the
// property is found.
func (config *Config) getProp(name string) (val string, ok bool) {
config.mutexSrc.RLock()
defer config.mutexSrc.RUnlock()
var s string
for _, se := range config.srcs {
if se.props != nil {
if s, ok = se.props[name]; ok {
val = strings.TrimSpace(s)
return
}
}
}
return
}
// String returns the value of the named prop as a string.
// If the property is not found then the supplied default `def`
// and `ErrNotFound` are returned.
func (config *Config) String(name string, def string) (val string, err error) {
if v, ok := config.getProp(name); ok {
val = v
err = nil
return
}
err = ErrNotFound
val = def
return
}
// Int returns the value of the named prop as an `int`.
// If the property is not found then the supplied default `def`
// and `ErrNotFound` are returned.
//
// See config.String
func (config *Config) Int(name string, def int) (val int, err error) {
var s string
if s, err = config.String(name, ""); err == nil {
var i int64
if i, err = strconv.ParseInt(s, 10, 32); err == nil {
val = int(i)
}
}
if err != nil {
val = def
}
return
}
// Int64 returns the value of the named prop as an `int64`.
// If the property is not found then the supplied default `def`
// and `ErrNotFound` are returned.
//
// See config.String
func (config *Config) Int64(name string, def int64) (val int64, err error) {
var s string
if s, err = config.String(name, ""); err == nil {
val, err = strconv.ParseInt(s, 10, 64)
}
if err != nil {
val = def
}
return
}
// Float64 returns the value of the named prop as a `float64`.
// If the property is not found then the supplied default `def`
// and `ErrNotFound` are returned.
//
// See config.String
func (config *Config) Float64(name string, def float64) (val float64, err error) {
var s string
if s, err = config.String(name, ""); err == nil {
val, err = strconv.ParseFloat(s, 64)
}
if err != nil {
val = def
}
return
}
// Bool returns the value of the named prop as a `bool`.
// If the property is not found then the supplied default `def`
// and `ErrNotFound` are returned.
//
// Supports (t, true, 1, y, yes) for true, and (f, false, 0, n, no) for false,
// all case-insensitive.
//
// See config.String
func (config *Config) Bool(name string, def bool) (val bool, err error) {
var s string
if s, err = config.String(name, ""); err == nil {
switch strings.ToLower(s) {
case "t", "true", "1", "y", "yes":
val = true
case "f", "false", "0", "n", "no":
val = false
default:
err = errors.New("invalid syntax")
}
}
if err != nil {
val = def
}
return
}
// Duration returns the value of the named prop as a `time.Duration`, representing
// a span of time.
//
// Units of measure are supported: ms, sec, min, hour, day, week, year.
// See config.UnitsToMillis for a complete list of units supported.
//
// If the property is not found then the supplied default `def`
// and `ErrNotFound` are returned.
//
// See config.String
func (config *Config) Duration(name string, def time.Duration) (val time.Duration, err error) {
var s string
if s, err = config.String(name, ""); err == nil {
var ms int64
ms, err = timeconv.ParseMilliseconds(s)
val = time.Duration(ms) * time.Millisecond
}
if err != nil {
val = def
}
return
}
// AddChangedListener adds a listener that will receive notifications
// whenever one or more property values change within the config.
func (config *Config) AddChangedListener(l ChangedListener) {
config.mutexListeners.Lock()
defer config.mutexListeners.Unlock()
config.chgListeners = append(config.chgListeners, l)
}
// RemoveChangedListener removes all instances of a ChangedListener.
// Returns `ErrNotFound` if the listener was not present.
func (config *Config) RemoveChangedListener(l ChangedListener) error {
config.mutexListeners.Lock()
defer config.mutexListeners.Unlock()
dest := make([]ChangedListener, 0, len(config.chgListeners))
err := ErrNotFound
// Remove all instances of the listener by
// copying list while filtering.
for _, s := range config.chgListeners {
if s != l {
dest = append(dest, s)
} else {
err = nil
}
}
config.chgListeners = dest
return err
}
// Shutdown can be called to stop monitoring of all config sources.
func (config *Config) Shutdown() {
config.mutexSrc.RLock()
defer config.mutexSrc.RUnlock()
if config.shutdown != nil {
close(config.shutdown)
}
}
// onSourceChanged is called whenever one or more properties of a
// config source has changed.
func (config *Config) onSourceChanged(src SourceMonitored) {
defer func() {
if p := recover(); p != nil {
fmt.Println(p)
}
}()
config.mutexListeners.RLock()
defer config.mutexListeners.RUnlock()
for _, l := range config.chgListeners {
l.ConfigChanged(config, src)
}
}
// monitor periodically checks a config source for changes.
func (config *Config) monitor(se *sourceEntry) {
go func(se *sourceEntry, shutdown <-chan interface{}) {
var src SourceMonitored
var ok bool
if src, ok = se.src.(SourceMonitored); !ok {
return
}
paused := false
last := time.Time{}
freq := src.GetMonitorFreq()
if freq <= 0 {
paused = true
freq = 10
last, _ = src.GetLastModified()
}
timer := time.NewTimer(freq)
for {
select {
case <-timer.C:
if !paused {
if latest, err := src.GetLastModified(); err != nil {
if config.ShouldPanicOnError() {
panic(fmt.Sprintf("error <%v> getting last modified for %v", err, src))
}
} else {
if last.Before(latest) {
last = latest
config.reloadProps(se)
// TODO: calc diff and provide detailed changes
config.onSourceChanged(src)
}
}
}
freq = src.GetMonitorFreq()
if freq <= 0 {
paused = true
freq = 10
} else {
paused = false
}
timer.Reset(freq)
case <-shutdown:
// stop the timer and exit
if !timer.Stop() {
<-timer.C
}
return
}
}
}(se, config.shutdown)
}
// reloadProps causes a Source to reload its properties.
func (config *Config) reloadProps(se *sourceEntry) {
config.mutexSrc.Lock()
defer config.mutexSrc.Unlock()
m, err := se.src.GetProps()
if err != nil {
if config.wantPanicOnError {
panic(fmt.Sprintf("GetProps error for %v", se.src))
}
return
}
se.props = make(map[string]string)
for k, v := range m {
se.props[k] = v
}
}

5
vendor/github.com/wiggin77/cfg/go.mod сгенерированный поставляемый
Просмотреть файл

@@ -1,5 +0,0 @@
module github.com/wiggin77/cfg
go 1.12
require github.com/wiggin77/merror v1.0.2

2
vendor/github.com/wiggin77/cfg/go.sum сгенерированный поставляемый
Просмотреть файл

@@ -1,2 +0,0 @@
github.com/wiggin77/merror v1.0.2 h1:V0nH9eFp64ASyaXC+pB5WpvBoCg7NUwvaCSKdzlcHqw=
github.com/wiggin77/merror v1.0.2/go.mod h1:uQTcIU0Z6jRK4OwqganPYerzQxSFJ4GSHM3aurxxQpg=

167
vendor/github.com/wiggin77/cfg/ini/ini.go сгенерированный поставляемый
Просмотреть файл

@@ -1,167 +0,0 @@
package ini
import (
"fmt"
"io"
"io/ioutil"
"os"
"sync"
"time"
)
// Ini provides parsing and querying of INI format or simple name/value pairs
// such as a simple config file.
// A name/value pair format is just an INI with no sections, and properties can
// be queried using an empty section name.
type Ini struct {
mutex sync.RWMutex
m map[string]*Section
lm time.Time
}
// LoadFromFilespec loads an INI file from string containing path and filename.
func (ini *Ini) LoadFromFilespec(filespec string) error {
f, err := os.Open(filespec)
if err != nil {
return err
}
return ini.LoadFromFile(f)
}
// LoadFromFile loads an INI file from `os.File`.
func (ini *Ini) LoadFromFile(file *os.File) error {
fi, err := file.Stat()
if err != nil {
return err
}
lm := fi.ModTime()
if err := ini.LoadFromReader(file); err != nil {
return err
}
ini.lm = lm
return nil
}
// LoadFromReader loads an INI file from an `io.Reader`.
func (ini *Ini) LoadFromReader(reader io.Reader) error {
data, err := ioutil.ReadAll(reader)
if err != nil {
return err
}
return ini.LoadFromString(string(data))
}
// LoadFromString parses an INI from a string .
func (ini *Ini) LoadFromString(s string) error {
m, err := getSections(s)
if err != nil {
return err
}
ini.mutex.Lock()
ini.m = m
ini.lm = time.Now()
ini.mutex.Unlock()
return nil
}
// GetLastModified returns the last modified timestamp of the
// INI contents.
func (ini *Ini) GetLastModified() time.Time {
return ini.lm
}
// GetSectionNames returns the names of all sections in this INI.
// Note, the returned section names are a snapshot in time, meaning
// other goroutines may change the contents of this INI as soon as
// the method returns.
func (ini *Ini) GetSectionNames() []string {
ini.mutex.RLock()
defer ini.mutex.RUnlock()
arr := make([]string, 0, len(ini.m))
for key := range ini.m {
arr = append(arr, key)
}
return arr
}
// GetKeys returns the names of all keys in the specified section.
// Note, the returned key names are a snapshot in time, meaning other
// goroutines may change the contents of this INI as soon as the
// method returns.
func (ini *Ini) GetKeys(sectionName string) ([]string, error) {
sec, err := ini.getSection(sectionName)
if err != nil {
return nil, err
}
return sec.getKeys(), nil
}
// getSection returns the named section.
func (ini *Ini) getSection(sectionName string) (*Section, error) {
ini.mutex.RLock()
defer ini.mutex.RUnlock()
sec, ok := ini.m[sectionName]
if !ok {
return nil, fmt.Errorf("section '%s' not found", sectionName)
}
return sec, nil
}
// GetFlattenedKeys returns all section names plus keys as one
// flattened array.
func (ini *Ini) GetFlattenedKeys() []string {
ini.mutex.RLock()
defer ini.mutex.RUnlock()
arr := make([]string, 0, len(ini.m)*2)
for _, section := range ini.m {
keys := section.getKeys()
for _, key := range keys {
name := section.GetName()
if name != "" {
key = name + "." + key
}
arr = append(arr, key)
}
}
return arr
}
// GetProp returns the value of the specified key in the named section.
func (ini *Ini) GetProp(section string, key string) (val string, ok bool) {
sec, err := ini.getSection(section)
if err != nil {
return val, false
}
return sec.GetProp(key)
}
// ToMap returns a flattened map of the section name plus keys mapped
// to values.
func (ini *Ini) ToMap() map[string]string {
m := make(map[string]string)
ini.mutex.RLock()
defer ini.mutex.RUnlock()
for _, section := range ini.m {
for _, key := range section.getKeys() {
val, ok := section.GetProp(key)
if ok {
name := section.GetName()
var mapkey string
if name != "" {
mapkey = name + "." + key
} else {
mapkey = key
}
m[mapkey] = val
}
}
}
return m
}

142
vendor/github.com/wiggin77/cfg/ini/parser.go сгенерированный поставляемый
Просмотреть файл

@@ -1,142 +0,0 @@
package ini
import (
"fmt"
"strings"
"github.com/wiggin77/merror"
)
// LF is linefeed
const LF byte = 0x0A
// CR is carriage return
const CR byte = 0x0D
// getSections parses an INI formatted string, or string containing just name/value pairs,
// returns map of `Section`'s.
//
// Any name/value pairs appearing before a section name are added to the section named
// with an empty string (""). Also true for Linux-style config files where all props
// are outside a named section.
//
// Any errors encountered are aggregated and returned, along with the partially parsed
// sections.
func getSections(str string) (map[string]*Section, error) {
merr := merror.New()
mapSections := make(map[string]*Section)
lines := buildLineArray(str)
section := newSection("")
for _, line := range lines {
name, ok := parseSection(line)
if ok {
// A section name encountered. Stop processing the current one.
// Don't add the current section to the map if the section name is blank
// and the prop map is empty.
nameCurr := section.GetName()
if nameCurr != "" || section.hasKeys() {
mapSections[nameCurr] = section
}
// Start processing a new section.
section = newSection(name)
} else {
// Parse the property and add to the current section, or ignore if comment.
if k, v, comment, err := parseProp(line); !comment && err == nil {
section.setProp(k, v)
} else if err != nil {
merr.Append(err) // aggregate errors
}
}
}
// If the current section is not empty, add it.
if section.hasKeys() {
mapSections[section.GetName()] = section
}
return mapSections, merr.ErrorOrNil()
}
// buildLineArray parses the given string buffer and creates a list of strings,
// one for each line in the string buffer.
//
// A line is considered to be terminated by any one of a line feed ('\n'),
// a carriage return ('\r'), or a carriage return followed immediately by a
// linefeed.
//
// Lines prefixed with ';' or '#' are considered comments and skipped.
func buildLineArray(str string) []string {
arr := make([]string, 0, 10)
str = str + "\n"
iLen := len(str)
iPos, iBegin := 0, 0
var ch byte
for iPos < iLen {
ch = str[iPos]
if ch == LF || ch == CR {
sub := str[iBegin:iPos]
sub = strings.TrimSpace(sub)
if sub != "" && !strings.HasPrefix(sub, ";") && !strings.HasPrefix(sub, "#") {
arr = append(arr, sub)
}
iPos++
if ch == CR && iPos < iLen && str[iPos] == LF {
iPos++
}
iBegin = iPos
} else {
iPos++
}
}
return arr
}
// parseSection parses the specified string for a section name enclosed in square brackets.
// Returns the section name found, or `ok=false` if `str` is not a section header.
func parseSection(str string) (name string, ok bool) {
str = strings.TrimSpace(str)
if !strings.HasPrefix(str, "[") {
return "", false
}
iCloser := strings.Index(str, "]")
if iCloser == -1 {
return "", false
}
return strings.TrimSpace(str[1:iCloser]), true
}
// parseProp parses the specified string and extracts a key/value pair.
//
// If the string is a comment (prefixed with ';' or '#') then `comment=true`
// and key will be empty.
func parseProp(str string) (key string, val string, comment bool, err error) {
iLen := len(str)
iEqPos := strings.Index(str, "=")
if iEqPos == -1 {
return "", "", false, fmt.Errorf("not a key/value pair:'%s'", str)
}
key = str[0:iEqPos]
key = strings.TrimSpace(key)
if iEqPos+1 < iLen {
val = str[iEqPos+1:]
val = strings.TrimSpace(val)
}
// Check that the key has at least 1 char.
if key == "" {
return "", "", false, fmt.Errorf("key is empty for '%s'", str)
}
// Check if this line is a comment that just happens
// to have an equals sign in it. Not an error, but not a
// useable line either.
if strings.HasPrefix(key, ";") || strings.HasPrefix(key, "#") {
key = ""
val = ""
comment = true
}
return key, val, comment, err
}

109
vendor/github.com/wiggin77/cfg/ini/section.go сгенерированный поставляемый
Просмотреть файл

@@ -1,109 +0,0 @@
package ini
import (
"fmt"
"strings"
"sync"
)
// Section represents a section in an INI file. The section has a name, which is
// enclosed in square brackets in the file. The section also has an array of
// key/value pairs.
type Section struct {
name string
props map[string]string
mtx sync.RWMutex
}
func newSection(name string) *Section {
sec := &Section{}
sec.name = name
sec.props = make(map[string]string)
return sec
}
// addLines addes an array of strings containing name/value pairs
// of the format `key=value`.
//func addLines(lines []string) {
// TODO
//}
// GetName returns the name of the section.
func (sec *Section) GetName() (name string) {
sec.mtx.RLock()
name = sec.name
sec.mtx.RUnlock()
return
}
// GetProp returns the value associated with the given key, or
// `ok=false` if key does not exist.
func (sec *Section) GetProp(key string) (val string, ok bool) {
sec.mtx.RLock()
val, ok = sec.props[key]
sec.mtx.RUnlock()
return
}
// SetProp sets the value associated with the given key.
func (sec *Section) setProp(key string, val string) {
sec.mtx.Lock()
sec.props[key] = val
sec.mtx.Unlock()
}
// hasKeys returns true if there are one or more properties in
// this section.
func (sec *Section) hasKeys() (b bool) {
sec.mtx.RLock()
b = len(sec.props) > 0
sec.mtx.RUnlock()
return
}
// getKeys returns an array containing all keys in this section.
func (sec *Section) getKeys() []string {
sec.mtx.RLock()
defer sec.mtx.RUnlock()
arr := make([]string, len(sec.props))
idx := 0
for k := range sec.props {
arr[idx] = k
idx++
}
return arr
}
// combine the given section with this one.
func (sec *Section) combine(sec2 *Section) {
sec.mtx.Lock()
sec2.mtx.RLock()
defer sec.mtx.Unlock()
defer sec2.mtx.RUnlock()
for k, v := range sec2.props {
sec.props[k] = v
}
}
// String returns a string representation of this section.
func (sec *Section) String() string {
return fmt.Sprintf("[%s]\n%s", sec.GetName(), sec.StringPropsOnly())
}
// StringPropsOnly returns a string representation of this section
// without the section header.
func (sec *Section) StringPropsOnly() string {
sec.mtx.RLock()
defer sec.mtx.RUnlock()
sb := &strings.Builder{}
for k, v := range sec.props {
sb.WriteString(k)
sb.WriteString("=")
sb.WriteString(v)
sb.WriteString("\n")
}
return sb.String()
}

11
vendor/github.com/wiggin77/cfg/listener.go сгенерированный поставляемый
Просмотреть файл

@@ -1,11 +0,0 @@
package cfg
// ChangedListener interface is for receiving notifications
// when one or more properties within monitored config sources
// (SourceMonitored) have changed values.
type ChangedListener interface {
// Changed is called when one or more properties in a `SourceMonitored` has a
// changed value.
ConfigChanged(cfg *Config, src SourceMonitored)
}

11
vendor/github.com/wiggin77/cfg/nocopy.go сгенерированный поставляемый
Просмотреть файл

@@ -1,11 +0,0 @@
package cfg
// noCopy may be embedded into structs which must not be copied
// after the first use.
//
// See https://golang.org/issues/8005#issuecomment-190753527
// for details.
type noCopy struct{}
// Lock is a no-op used by -copylocks checker from `go vet`.
func (*noCopy) Lock() {}

58
vendor/github.com/wiggin77/cfg/source.go сгенерированный поставляемый
Просмотреть файл

@@ -1,58 +0,0 @@
package cfg
import (
"sync"
"time"
)
// Source is the interface required for any source of name/value pairs.
type Source interface {
// GetProps fetches all the properties from a source and returns
// them as a map.
GetProps() (map[string]string, error)
}
// SourceMonitored is the interface required for any config source that is
// monitored for changes.
type SourceMonitored interface {
Source
// GetLastModified returns the time of the latest modification to any
// property value within the source. If a source does not support
// modifying properties at runtime then the zero value for `Time`
// should be returned to ensure reload events are not generated.
GetLastModified() (time.Time, error)
// GetMonitorFreq returns the frequency as a `time.Duration` between
// checks for changes to this config source.
//
// Returning zero (or less) will temporarily suspend calls to `GetLastModified`
// and `GetMonitorFreq` will be called every 10 seconds until resumed, after which
// `GetMontitorFreq` will be called at a frequency roughly equal to the `time.Duration`
// returned.
GetMonitorFreq() time.Duration
}
// AbstractSourceMonitor can be embedded in a custom `Source` to provide the
// basic plumbing for monitor frequency.
type AbstractSourceMonitor struct {
mutex sync.RWMutex
freq time.Duration
}
// GetMonitorFreq returns the frequency as a `time.Duration` between
// checks for changes to this config source.
func (asm *AbstractSourceMonitor) GetMonitorFreq() (freq time.Duration) {
asm.mutex.RLock()
freq = asm.freq
asm.mutex.RUnlock()
return
}
// SetMonitorFreq sets the frequency between checks for changes to this config source.
func (asm *AbstractSourceMonitor) SetMonitorFreq(freq time.Duration) {
asm.mutex.Lock()
asm.freq = freq
asm.mutex.Unlock()
}

63
vendor/github.com/wiggin77/cfg/srcfile.go сгенерированный поставляемый
Просмотреть файл

@@ -1,63 +0,0 @@
package cfg
import (
"os"
"time"
"github.com/wiggin77/cfg/ini"
)
// SrcFile is a configuration `Source` backed by a file containing
// name/value pairs or INI format.
type SrcFile struct {
AbstractSourceMonitor
ini ini.Ini
file *os.File
}
// NewSrcFileFromFilespec creates a new SrcFile with the specified filespec.
func NewSrcFileFromFilespec(filespec string) (*SrcFile, error) {
file, err := os.Open(filespec)
if err != nil {
return nil, err
}
return NewSrcFile(file)
}
// NewSrcFile creates a new SrcFile with the specified os.File.
func NewSrcFile(file *os.File) (*SrcFile, error) {
sf := &SrcFile{}
sf.freq = time.Minute
sf.file = file
if err := sf.ini.LoadFromFile(file); err != nil {
return nil, err
}
return sf, nil
}
// GetProps fetches all the properties from a source and returns
// them as a map.
func (sf *SrcFile) GetProps() (map[string]string, error) {
lm, err := sf.GetLastModified()
if err != nil {
return nil, err
}
// Check if we need to reload.
if sf.ini.GetLastModified() != lm {
if err := sf.ini.LoadFromFile(sf.file); err != nil {
return nil, err
}
}
return sf.ini.ToMap(), nil
}
// GetLastModified returns the time of the latest modification to any
// property value within the source.
func (sf *SrcFile) GetLastModified() (time.Time, error) {
fi, err := sf.file.Stat()
if err != nil {
return time.Now(), err
}
return fi.ModTime(), nil
}

78
vendor/github.com/wiggin77/cfg/srcmap.go сгенерированный поставляемый
Просмотреть файл

@@ -1,78 +0,0 @@
package cfg
import (
"time"
)
// SrcMap is a configuration `Source` backed by a simple map.
type SrcMap struct {
AbstractSourceMonitor
m map[string]string
lm time.Time
}
// NewSrcMap creates an empty `SrcMap`.
func NewSrcMap() *SrcMap {
sm := &SrcMap{}
sm.m = make(map[string]string)
sm.lm = time.Now()
sm.freq = time.Minute
return sm
}
// NewSrcMapFromMap creates a `SrcMap` containing a copy of the
// specified map.
func NewSrcMapFromMap(mapIn map[string]string) *SrcMap {
sm := NewSrcMap()
sm.PutAll(mapIn)
return sm
}
// Put inserts or updates a value in the `SrcMap`.
func (sm *SrcMap) Put(key string, val string) {
sm.mutex.Lock()
sm.m[key] = val
sm.lm = time.Now()
sm.mutex.Unlock()
}
// PutAll inserts a copy of `mapIn` into the `SrcMap`
func (sm *SrcMap) PutAll(mapIn map[string]string) {
sm.mutex.Lock()
defer sm.mutex.Unlock()
for k, v := range mapIn {
sm.m[k] = v
}
sm.lm = time.Now()
}
// GetProps fetches all the properties from a source and returns
// them as a map.
func (sm *SrcMap) GetProps() (m map[string]string, err error) {
sm.mutex.RLock()
m = sm.m
sm.mutex.RUnlock()
return
}
// GetLastModified returns the time of the latest modification to any
// property value within the source. If a source does not support
// modifying properties at runtime then the zero value for `Time`
// should be returned to ensure reload events are not generated.
func (sm *SrcMap) GetLastModified() (last time.Time, err error) {
sm.mutex.RLock()
last = sm.lm
sm.mutex.RUnlock()
return
}
// GetMonitorFreq returns the frequency as a `time.Duration` between
// checks for changes to this config source. Defaults to 1 minute
// unless changed with `SetMonitorFreq`.
func (sm *SrcMap) GetMonitorFreq() (freq time.Duration) {
sm.mutex.RLock()
freq = sm.freq
sm.mutex.RUnlock()
return
}

108
vendor/github.com/wiggin77/cfg/timeconv/parse.go сгенерированный поставляемый
Просмотреть файл

@@ -1,108 +0,0 @@
package timeconv
import (
"fmt"
"math"
"regexp"
"strconv"
"strings"
)
// MillisPerSecond is the number of millseconds per second.
const MillisPerSecond int64 = 1000
// MillisPerMinute is the number of millseconds per minute.
const MillisPerMinute int64 = MillisPerSecond * 60
// MillisPerHour is the number of millseconds per hour.
const MillisPerHour int64 = MillisPerMinute * 60
// MillisPerDay is the number of millseconds per day.
const MillisPerDay int64 = MillisPerHour * 24
// MillisPerWeek is the number of millseconds per week.
const MillisPerWeek int64 = MillisPerDay * 7
// MillisPerYear is the approximate number of millseconds per year.
const MillisPerYear int64 = MillisPerDay*365 + int64((float64(MillisPerDay) * 0.25))
// ParseMilliseconds parses a string containing a number plus
// a unit of measure for time and returns the number of milliseconds
// it represents.
//
// Example:
// * "1 second" returns 1000
// * "1 minute" returns 60000
// * "1 hour" returns 3600000
//
// See config.UnitsToMillis for a list of supported units of measure.
func ParseMilliseconds(str string) (int64, error) {
s := strings.TrimSpace(str)
reg := regexp.MustCompile("([0-9\\.\\-+]*)(.*)")
matches := reg.FindStringSubmatch(s)
if matches == nil || len(matches) < 1 || matches[1] == "" {
return 0, fmt.Errorf("invalid syntax - '%s'", s)
}
digits := matches[1]
units := "ms"
if len(matches) > 1 && matches[2] != "" {
units = matches[2]
}
fDigits, err := strconv.ParseFloat(digits, 64)
if err != nil {
return 0, err
}
msPerUnit, err := UnitsToMillis(units)
if err != nil {
return 0, err
}
// Check for overflow.
fms := float64(msPerUnit) * fDigits
if fms > math.MaxInt64 || fms < math.MinInt64 {
return 0, fmt.Errorf("out of range - '%s' overflows", s)
}
ms := int64(fms)
return ms, nil
}
// UnitsToMillis returns the number of milliseconds represented by the specified unit of measure.
//
// Example:
// * "second" returns 1000 <br/>
// * "minute" returns 60000 <br/>
// * "hour" returns 3600000 <br/>
//
// Supported units of measure:
// * "milliseconds", "millis", "ms", "millisecond"
// * "seconds", "sec", "s", "second"
// * "minutes", "mins", "min", "m", "minute"
// * "hours", "h", "hour"
// * "days", "d", "day"
// * "weeks", "w", "week"
// * "years", "y", "year"
func UnitsToMillis(units string) (ms int64, err error) {
u := strings.TrimSpace(units)
u = strings.ToLower(u)
switch u {
case "milliseconds", "millisecond", "millis", "ms":
ms = 1
case "seconds", "second", "sec", "s":
ms = MillisPerSecond
case "minutes", "minute", "mins", "min", "m":
ms = MillisPerMinute
case "hours", "hour", "h":
ms = MillisPerHour
case "days", "day", "d":
ms = MillisPerDay
case "weeks", "week", "w":
ms = MillisPerWeek
case "years", "year", "y":
ms = MillisPerYear
default:
err = fmt.Errorf("invalid syntax - '%s' not a supported unit of measure", u)
}
return
}

15
vendor/go.uber.org/multierr/.codecov.yml сгенерированный поставляемый
Просмотреть файл

@@ -1,15 +0,0 @@
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 100 # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure

4
vendor/go.uber.org/multierr/.gitignore сгенерированный поставляемый
Просмотреть файл

@@ -1,4 +0,0 @@
/vendor
cover.html
cover.out
/bin

66
vendor/go.uber.org/multierr/CHANGELOG.md сгенерированный поставляемый
Просмотреть файл

@@ -1,66 +0,0 @@
Releases
========
v1.7.0 (2021-05-06)
===================
- Add `AppendInvoke` to append into errors from `defer` blocks.
v1.6.0 (2020-09-14)
===================
- Actually drop library dependency on development-time tooling.
v1.5.0 (2020-02-24)
===================
- Drop library dependency on development-time tooling.
v1.4.0 (2019-11-04)
===================
- Add `AppendInto` function to more ergonomically build errors inside a
loop.
v1.3.0 (2019-10-29)
===================
- Switch to Go modules.
v1.2.0 (2019-09-26)
===================
- Support extracting and matching against wrapped errors with `errors.As`
and `errors.Is`.
v1.1.0 (2017-06-30)
===================
- Added an `Errors(error) []error` function to extract the underlying list of
errors for a multierr error.
v1.0.0 (2017-05-31)
===================
No changes since v0.2.0. This release is committing to making no breaking
changes to the current API in the 1.X series.
v0.2.0 (2017-04-11)
===================
- Repeatedly appending to the same error is now faster due to fewer
allocations.
v0.1.0 (2017-31-03)
===================
- Initial release

19
vendor/go.uber.org/multierr/LICENSE.txt сгенерированный поставляемый
Просмотреть файл

@@ -1,19 +0,0 @@
Copyright (c) 2017-2021 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.

38
vendor/go.uber.org/multierr/Makefile сгенерированный поставляемый
Просмотреть файл

@@ -1,38 +0,0 @@
# Directory to put `go install`ed binaries in.
export GOBIN ?= $(shell pwd)/bin
GO_FILES := $(shell \
find . '(' -path '*/.*' -o -path './vendor' ')' -prune \
-o -name '*.go' -print | cut -b3-)
.PHONY: build
build:
go build ./...
.PHONY: test
test:
go test -race ./...
.PHONY: gofmt
gofmt:
$(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX))
@gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true
@[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" | cat - $(FMT_LOG) && false)
.PHONY: golint
golint:
@cd tools && go install golang.org/x/lint/golint
@$(GOBIN)/golint ./...
.PHONY: staticcheck
staticcheck:
@cd tools && go install honnef.co/go/tools/cmd/staticcheck
@$(GOBIN)/staticcheck ./...
.PHONY: lint
lint: gofmt golint staticcheck
.PHONY: cover
cover:
go test -race -coverprofile=cover.out -coverpkg=./... -v ./...
go tool cover -html=cover.out -o cover.html

23
vendor/go.uber.org/multierr/README.md сгенерированный поставляемый
Просмотреть файл

@@ -1,23 +0,0 @@
# multierr [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
`multierr` allows combining one or more Go `error`s together.
## Installation
go get -u go.uber.org/multierr
## Status
Stable: No breaking changes will be made before 2.0.
-------------------------------------------------------------------------------
Released under the [MIT License].
[MIT License]: LICENSE.txt
[doc-img]: https://pkg.go.dev/badge/go.uber.org/multierr
[doc]: https://pkg.go.dev/go.uber.org/multierr
[ci-img]: https://github.com/uber-go/multierr/actions/workflows/go.yml/badge.svg
[cov-img]: https://codecov.io/gh/uber-go/multierr/branch/master/graph/badge.svg
[ci]: https://github.com/uber-go/multierr/actions/workflows/go.yml
[cov]: https://codecov.io/gh/uber-go/multierr

639
vendor/go.uber.org/multierr/error.go сгенерированный поставляемый
Просмотреть файл

@@ -1,639 +0,0 @@
// Copyright (c) 2017-2021 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 multierr allows combining one or more errors together.
//
// Overview
//
// Errors can be combined with the use of the Combine function.
//
// multierr.Combine(
// reader.Close(),
// writer.Close(),
// conn.Close(),
// )
//
// If only two errors are being combined, the Append function may be used
// instead.
//
// err = multierr.Append(reader.Close(), writer.Close())
//
// The underlying list of errors for a returned error object may be retrieved
// with the Errors function.
//
// errors := multierr.Errors(err)
// if len(errors) > 0 {
// fmt.Println("The following errors occurred:", errors)
// }
//
// Appending from a loop
//
// You sometimes need to append into an error from a loop.
//
// var err error
// for _, item := range items {
// err = multierr.Append(err, process(item))
// }
//
// Cases like this may require knowledge of whether an individual instance
// failed. This usually requires introduction of a new variable.
//
// var err error
// for _, item := range items {
// if perr := process(item); perr != nil {
// log.Warn("skipping item", item)
// err = multierr.Append(err, perr)
// }
// }
//
// multierr includes AppendInto to simplify cases like this.
//
// var err error
// for _, item := range items {
// if multierr.AppendInto(&err, process(item)) {
// log.Warn("skipping item", item)
// }
// }
//
// This will append the error into the err variable, and return true if that
// individual error was non-nil.
//
// See AppendInto for more information.
//
// Deferred Functions
//
// Go makes it possible to modify the return value of a function in a defer
// block if the function was using named returns. This makes it possible to
// record resource cleanup failures from deferred blocks.
//
// func sendRequest(req Request) (err error) {
// conn, err := openConnection()
// if err != nil {
// return err
// }
// defer func() {
// err = multierr.Append(err, conn.Close())
// }()
// // ...
// }
//
// multierr provides the Invoker type and AppendInvoke function to make cases
// like the above simpler and obviate the need for a closure. The following is
// roughly equivalent to the example above.
//
// func sendRequest(req Request) (err error) {
// conn, err := openConnection()
// if err != nil {
// return err
// }
// defer multierr.AppendInvoke(err, multierr.Close(conn))
// // ...
// }
//
// See AppendInvoke and Invoker for more information.
//
// Advanced Usage
//
// Errors returned by Combine and Append MAY implement the following
// interface.
//
// type errorGroup interface {
// // Returns a slice containing the underlying list of errors.
// //
// // This slice MUST NOT be modified by the caller.
// Errors() []error
// }
//
// Note that if you need access to list of errors behind a multierr error, you
// should prefer using the Errors function. That said, if you need cheap
// read-only access to the underlying errors slice, you can attempt to cast
// the error to this interface. You MUST handle the failure case gracefully
// because errors returned by Combine and Append are not guaranteed to
// implement this interface.
//
// var errors []error
// group, ok := err.(errorGroup)
// if ok {
// errors = group.Errors()
// } else {
// errors = []error{err}
// }
package multierr // import "go.uber.org/multierr"
import (
"bytes"
"errors"
"fmt"
"io"
"strings"
"sync"
"go.uber.org/atomic"
)
var (
// Separator for single-line error messages.
_singlelineSeparator = []byte("; ")
// Prefix for multi-line messages
_multilinePrefix = []byte("the following errors occurred:")
// Prefix for the first and following lines of an item in a list of
// multi-line error messages.
//
// For example, if a single item is:
//
// foo
// bar
//
// It will become,
//
// - foo
// bar
_multilineSeparator = []byte("\n - ")
_multilineIndent = []byte(" ")
)
// _bufferPool is a pool of bytes.Buffers.
var _bufferPool = sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
type errorGroup interface {
Errors() []error
}
// Errors returns a slice containing zero or more errors that the supplied
// error is composed of. If the error is nil, a nil slice is returned.
//
// err := multierr.Append(r.Close(), w.Close())
// errors := multierr.Errors(err)
//
// If the error is not composed of other errors, the returned slice contains
// just the error that was passed in.
//
// Callers of this function are free to modify the returned slice.
func Errors(err error) []error {
if err == nil {
return nil
}
// Note that we're casting to multiError, not errorGroup. Our contract is
// that returned errors MAY implement errorGroup. Errors, however, only
// has special behavior for multierr-specific error objects.
//
// This behavior can be expanded in the future but I think it's prudent to
// start with as little as possible in terms of contract and possibility
// of misuse.
eg, ok := err.(*multiError)
if !ok {
return []error{err}
}
errors := eg.Errors()
result := make([]error, len(errors))
copy(result, errors)
return result
}
// multiError is an error that holds one or more errors.
//
// An instance of this is guaranteed to be non-empty and flattened. That is,
// none of the errors inside multiError are other multiErrors.
//
// multiError formats to a semi-colon delimited list of error messages with
// %v and with a more readable multi-line format with %+v.
type multiError struct {
copyNeeded atomic.Bool
errors []error
}
var _ errorGroup = (*multiError)(nil)
// Errors returns the list of underlying errors.
//
// This slice MUST NOT be modified.
func (merr *multiError) Errors() []error {
if merr == nil {
return nil
}
return merr.errors
}
// As attempts to find the first error in the error list that matches the type
// of the value that target points to.
//
// This function allows errors.As to traverse the values stored on the
// multierr error.
func (merr *multiError) As(target interface{}) bool {
for _, err := range merr.Errors() {
if errors.As(err, target) {
return true
}
}
return false
}
// Is attempts to match the provided error against errors in the error list.
//
// This function allows errors.Is to traverse the values stored on the
// multierr error.
func (merr *multiError) Is(target error) bool {
for _, err := range merr.Errors() {
if errors.Is(err, target) {
return true
}
}
return false
}
func (merr *multiError) Error() string {
if merr == nil {
return ""
}
buff := _bufferPool.Get().(*bytes.Buffer)
buff.Reset()
merr.writeSingleline(buff)
result := buff.String()
_bufferPool.Put(buff)
return result
}
func (merr *multiError) Format(f fmt.State, c rune) {
if c == 'v' && f.Flag('+') {
merr.writeMultiline(f)
} else {
merr.writeSingleline(f)
}
}
func (merr *multiError) writeSingleline(w io.Writer) {
first := true
for _, item := range merr.errors {
if first {
first = false
} else {
w.Write(_singlelineSeparator)
}
io.WriteString(w, item.Error())
}
}
func (merr *multiError) writeMultiline(w io.Writer) {
w.Write(_multilinePrefix)
for _, item := range merr.errors {
w.Write(_multilineSeparator)
writePrefixLine(w, _multilineIndent, fmt.Sprintf("%+v", item))
}
}
// Writes s to the writer with the given prefix added before each line after
// the first.
func writePrefixLine(w io.Writer, prefix []byte, s string) {
first := true
for len(s) > 0 {
if first {
first = false
} else {
w.Write(prefix)
}
idx := strings.IndexByte(s, '\n')
if idx < 0 {
idx = len(s) - 1
}
io.WriteString(w, s[:idx+1])
s = s[idx+1:]
}
}
type inspectResult struct {
// Number of top-level non-nil errors
Count int
// Total number of errors including multiErrors
Capacity int
// Index of the first non-nil error in the list. Value is meaningless if
// Count is zero.
FirstErrorIdx int
// Whether the list contains at least one multiError
ContainsMultiError bool
}
// Inspects the given slice of errors so that we can efficiently allocate
// space for it.
func inspect(errors []error) (res inspectResult) {
first := true
for i, err := range errors {
if err == nil {
continue
}
res.Count++
if first {
first = false
res.FirstErrorIdx = i
}
if merr, ok := err.(*multiError); ok {
res.Capacity += len(merr.errors)
res.ContainsMultiError = true
} else {
res.Capacity++
}
}
return
}
// fromSlice converts the given list of errors into a single error.
func fromSlice(errors []error) error {
res := inspect(errors)
switch res.Count {
case 0:
return nil
case 1:
// only one non-nil entry
return errors[res.FirstErrorIdx]
case len(errors):
if !res.ContainsMultiError {
// already flat
return &multiError{errors: errors}
}
}
nonNilErrs := make([]error, 0, res.Capacity)
for _, err := range errors[res.FirstErrorIdx:] {
if err == nil {
continue
}
if nested, ok := err.(*multiError); ok {
nonNilErrs = append(nonNilErrs, nested.errors...)
} else {
nonNilErrs = append(nonNilErrs, err)
}
}
return &multiError{errors: nonNilErrs}
}
// Combine combines the passed errors into a single error.
//
// If zero arguments were passed or if all items are nil, a nil error is
// returned.
//
// Combine(nil, nil) // == nil
//
// If only a single error was passed, it is returned as-is.
//
// Combine(err) // == err
//
// Combine skips over nil arguments so this function may be used to combine
// together errors from operations that fail independently of each other.
//
// multierr.Combine(
// reader.Close(),
// writer.Close(),
// pipe.Close(),
// )
//
// If any of the passed errors is a multierr error, it will be flattened along
// with the other errors.
//
// multierr.Combine(multierr.Combine(err1, err2), err3)
// // is the same as
// multierr.Combine(err1, err2, err3)
//
// The returned error formats into a readable multi-line error message if
// formatted with %+v.
//
// fmt.Sprintf("%+v", multierr.Combine(err1, err2))
func Combine(errors ...error) error {
return fromSlice(errors)
}
// Append appends the given errors together. Either value may be nil.
//
// This function is a specialization of Combine for the common case where
// there are only two errors.
//
// err = multierr.Append(reader.Close(), writer.Close())
//
// The following pattern may also be used to record failure of deferred
// operations without losing information about the original error.
//
// func doSomething(..) (err error) {
// f := acquireResource()
// defer func() {
// err = multierr.Append(err, f.Close())
// }()
func Append(left error, right error) error {
switch {
case left == nil:
return right
case right == nil:
return left
}
if _, ok := right.(*multiError); !ok {
if l, ok := left.(*multiError); ok && !l.copyNeeded.Swap(true) {
// Common case where the error on the left is constantly being
// appended to.
errs := append(l.errors, right)
return &multiError{errors: errs}
} else if !ok {
// Both errors are single errors.
return &multiError{errors: []error{left, right}}
}
}
// Either right or both, left and right, are multiErrors. Rely on usual
// expensive logic.
errors := [2]error{left, right}
return fromSlice(errors[0:])
}
// AppendInto appends an error into the destination of an error pointer and
// returns whether the error being appended was non-nil.
//
// var err error
// multierr.AppendInto(&err, r.Close())
// multierr.AppendInto(&err, w.Close())
//
// The above is equivalent to,
//
// err := multierr.Append(r.Close(), w.Close())
//
// As AppendInto reports whether the provided error was non-nil, it may be
// used to build a multierr error in a loop more ergonomically. For example:
//
// var err error
// for line := range lines {
// var item Item
// if multierr.AppendInto(&err, parse(line, &item)) {
// continue
// }
// items = append(items, item)
// }
//
// Compare this with a version that relies solely on Append:
//
// var err error
// for line := range lines {
// var item Item
// if parseErr := parse(line, &item); parseErr != nil {
// err = multierr.Append(err, parseErr)
// continue
// }
// items = append(items, item)
// }
func AppendInto(into *error, err error) (errored bool) {
if into == nil {
// We panic if 'into' is nil. This is not documented above
// because suggesting that the pointer must be non-nil may
// confuse users into thinking that the error that it points
// to must be non-nil.
panic("misuse of multierr.AppendInto: into pointer must not be nil")
}
if err == nil {
return false
}
*into = Append(*into, err)
return true
}
// Invoker is an operation that may fail with an error. Use it with
// AppendInvoke to append the result of calling the function into an error.
// This allows you to conveniently defer capture of failing operations.
//
// See also, Close and Invoke.
type Invoker interface {
Invoke() error
}
// Invoke wraps a function which may fail with an error to match the Invoker
// interface. Use it to supply functions matching this signature to
// AppendInvoke.
//
// For example,
//
// func processReader(r io.Reader) (err error) {
// scanner := bufio.NewScanner(r)
// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
// for scanner.Scan() {
// // ...
// }
// // ...
// }
//
// In this example, the following line will construct the Invoker right away,
// but defer the invocation of scanner.Err() until the function returns.
//
// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
type Invoke func() error
// Invoke calls the supplied function and returns its result.
func (i Invoke) Invoke() error { return i() }
// Close builds an Invoker that closes the provided io.Closer. Use it with
// AppendInvoke to close io.Closers and append their results into an error.
//
// For example,
//
// func processFile(path string) (err error) {
// f, err := os.Open(path)
// if err != nil {
// return err
// }
// defer multierr.AppendInvoke(&err, multierr.Close(f))
// return processReader(f)
// }
//
// In this example, multierr.Close will construct the Invoker right away, but
// defer the invocation of f.Close until the function returns.
//
// defer multierr.AppendInvoke(&err, multierr.Close(f))
func Close(closer io.Closer) Invoker {
return Invoke(closer.Close)
}
// AppendInvoke appends the result of calling the given Invoker into the
// provided error pointer. Use it with named returns to safely defer
// invocation of fallible operations until a function returns, and capture the
// resulting errors.
//
// func doSomething(...) (err error) {
// // ...
// f, err := openFile(..)
// if err != nil {
// return err
// }
//
// // multierr will call f.Close() when this function returns and
// // if the operation fails, its append its error into the
// // returned error.
// defer multierr.AppendInvoke(&err, multierr.Close(f))
//
// scanner := bufio.NewScanner(f)
// // Similarly, this scheduled scanner.Err to be called and
// // inspected when the function returns and append its error
// // into the returned error.
// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
//
// // ...
// }
//
// Without defer, AppendInvoke behaves exactly like AppendInto.
//
// err := // ...
// multierr.AppendInvoke(&err, mutltierr.Invoke(foo))
//
// // ...is roughly equivalent to...
//
// err := // ...
// multierr.AppendInto(&err, foo())
//
// The advantage of the indirection introduced by Invoker is to make it easy
// to defer the invocation of a function. Without this indirection, the
// invoked function will be evaluated at the time of the defer block rather
// than when the function returns.
//
// // BAD: This is likely not what the caller intended. This will evaluate
// // foo() right away and append its result into the error when the
// // function returns.
// defer multierr.AppendInto(&err, foo())
//
// // GOOD: This will defer invocation of foo unutil the function returns.
// defer multierr.AppendInvoke(&err, multierr.Invoke(foo))
//
// multierr provides a few Invoker implementations out of the box for
// convenience. See Invoker for more information.
func AppendInvoke(into *error, invoker Invoker) {
AppendInto(into, invoker.Invoke())
}

8
vendor/go.uber.org/multierr/glide.yaml сгенерированный поставляемый
Просмотреть файл

@@ -1,8 +0,0 @@
package: go.uber.org/multierr
import:
- package: go.uber.org/atomic
version: ^1
testImport:
- package: github.com/stretchr/testify
subpackages:
- assert

9
vendor/go.uber.org/multierr/go.mod сгенерированный поставляемый
Просмотреть файл

@@ -1,9 +0,0 @@
module go.uber.org/multierr
go 1.14
require (
github.com/stretchr/testify v1.7.0
go.uber.org/atomic v1.7.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)

16
vendor/go.uber.org/multierr/go.sum сгенерированный поставляемый
Просмотреть файл

@@ -1,16 +0,0 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

17
vendor/go.uber.org/zap/.codecov.yml сгенерированный поставляемый
Просмотреть файл

@@ -1,17 +0,0 @@
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 95% # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure
ignore:
- internal/readme/readme.go

32
vendor/go.uber.org/zap/.gitignore сгенерированный поставляемый
Просмотреть файл

@@ -1,32 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
vendor
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
*.pprof
*.out
*.log
/bin
cover.out
cover.html

109
vendor/go.uber.org/zap/.readme.tmpl сгенерированный поставляемый
Просмотреть файл

@@ -1,109 +0,0 @@
# :zap: zap [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
Blazing fast, structured, leveled logging in Go.
## Installation
`go get -u go.uber.org/zap`
Note that zap only supports the two most recent minor versions of Go.
## Quick Start
In contexts where performance is nice, but not critical, use the
`SugaredLogger`. It's 4-10x faster than other structured logging
packages and includes both structured and `printf`-style APIs.
```go
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
```
When performance and type safety are critical, use the `Logger`. It's even
faster than the `SugaredLogger` and allocates far less, but it only supports
structured logging.
```go
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
```
See the [documentation][doc] and [FAQ](FAQ.md) for more details.
## Performance
For applications that log in the hot path, reflection-based serialization and
string formatting are prohibitively expensive &mdash; they're CPU-intensive
and make many small allocations. Put differently, using `encoding/json` and
`fmt.Fprintf` to log tons of `interface{}`s makes your application slow.
Zap takes a different approach. It includes a reflection-free, zero-allocation
JSON encoder, and the base `Logger` strives to avoid serialization overhead
and allocations wherever possible. By building the high-level `SugaredLogger`
on that foundation, zap lets users *choose* when they need to count every
allocation and when they'd prefer a more familiar, loosely typed API.
As measured by its own [benchmarking suite][], not only is zap more performant
than comparable structured logging packages &mdash; it's also faster than the
standard library. Like all benchmarks, take these with a grain of salt.<sup
id="anchor-versions">[1](#footnote-versions)</sup>
Log a message and 10 fields:
{{.BenchmarkAddingFields}}
Log a message with a logger that already has 10 fields of context:
{{.BenchmarkAccumulatedContext}}
Log a static string, without any context or `printf`-style templating:
{{.BenchmarkWithoutFields}}
## Development Status: Stable
All APIs are finalized, and no breaking changes will be made in the 1.x series
of releases. Users of semver-aware dependency management systems should pin
zap to `^1`.
## Contributing
We encourage and support an active, healthy community of contributors &mdash;
including you! Details are in the [contribution guide](CONTRIBUTING.md) and
the [code of conduct](CODE_OF_CONDUCT.md). The zap maintainers keep an eye on
issues and pull requests, but you can also report any negative conduct to
oss-conduct@uber.com. That email list is a private, safe space; even the zap
maintainers don't have access, so don't hesitate to hold us to a high
standard.
<hr>
Released under the [MIT License](LICENSE.txt).
<sup id="footnote-versions">1</sup> In particular, keep in mind that we may be
benchmarking against slightly older versions of other packages. Versions are
pinned in zap's [glide.lock][] file. [↩](#anchor-versions)
[doc-img]: https://godoc.org/go.uber.org/zap?status.svg
[doc]: https://godoc.org/go.uber.org/zap
[ci-img]: https://travis-ci.com/uber-go/zap.svg?branch=master
[ci]: https://travis-ci.com/uber-go/zap
[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/zap
[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks
[glide.lock]: https://github.com/uber-go/zap/blob/master/glide.lock

460
vendor/go.uber.org/zap/CHANGELOG.md сгенерированный поставляемый
Просмотреть файл

@@ -1,460 +0,0 @@
# Changelog
## 1.17.0 (25 May 2021)
Bugfixes:
* [#867][]: Encode `<nil>` for nil `error` instead of a panic.
* [#931][], [#936][]: Update minimum version constraints to address
vulnerabilities in dependencies.
Enhancements:
* [#865][]: Improve alignment of fields of the Logger struct, reducing its
size from 96 to 80 bytes.
* [#881][]: Support `grpclog.LoggerV2` in zapgrpc.
* [#903][]: Support URL-encoded POST requests to the AtomicLevel HTTP handler
with the `application/x-www-form-urlencoded` content type.
* [#912][]: Support multi-field encoding with `zap.Inline`.
* [#913][]: Speed up SugaredLogger for calls with a single string.
* [#928][]: Add support for filtering by field name to `zaptest/observer`.
Thanks to @ash2k, @FMLS, @jimmystewpot, @Oncilla, @tsoslow, @tylitianrui, @withshubh, and @wziww for their contributions to this release.
## 1.16.0 (1 Sep 2020)
Bugfixes:
* [#828][]: Fix missing newline in IncreaseLevel error messages.
* [#835][]: Fix panic in JSON encoder when encoding times or durations
without specifying a time or duration encoder.
* [#843][]: Honor CallerSkip when taking stack traces.
* [#862][]: Fix the default file permissions to use `0666` and rely on the umask instead.
* [#854][]: Encode `<nil>` for nil `Stringer` instead of a panic error log.
Enhancements:
* [#629][]: Added `zapcore.TimeEncoderOfLayout` to easily create time encoders
for custom layouts.
* [#697][]: Added support for a configurable delimiter in the console encoder.
* [#852][]: Optimize console encoder by pooling the underlying JSON encoder.
* [#844][]: Add ability to include the calling function as part of logs.
* [#843][]: Add `StackSkip` for including truncated stacks as a field.
* [#861][]: Add options to customize Fatal behaviour for better testability.
Thanks to @SteelPhase, @tmshn, @lixingwang, @wyxloading, @moul, @segevfiner, @andy-retailnext and @jcorbin for their contributions to this release.
## 1.15.0 (23 Apr 2020)
Bugfixes:
* [#804][]: Fix handling of `Time` values out of `UnixNano` range.
* [#812][]: Fix `IncreaseLevel` being reset after a call to `With`.
Enhancements:
* [#806][]: Add `WithCaller` option to supersede the `AddCaller` option. This
allows disabling annotation of log entries with caller information if
previously enabled with `AddCaller`.
* [#813][]: Deprecate `NewSampler` constructor in favor of
`NewSamplerWithOptions` which supports a `SamplerHook` option. This option
adds support for monitoring sampling decisions through a hook.
Thanks to @danielbprice for their contributions to this release.
## 1.14.1 (14 Mar 2020)
Bugfixes:
* [#791][]: Fix panic on attempting to build a logger with an invalid Config.
* [#795][]: Vendoring Zap with `go mod vendor` no longer includes Zap's
development-time dependencies.
* [#799][]: Fix issue introduced in 1.14.0 that caused invalid JSON output to
be generated for arrays of `time.Time` objects when using string-based time
formats.
Thanks to @YashishDua for their contributions to this release.
## 1.14.0 (20 Feb 2020)
Enhancements:
* [#771][]: Optimize calls for disabled log levels.
* [#773][]: Add millisecond duration encoder.
* [#775][]: Add option to increase the level of a logger.
* [#786][]: Optimize time formatters using `Time.AppendFormat` where possible.
Thanks to @caibirdme for their contributions to this release.
## 1.13.0 (13 Nov 2019)
Enhancements:
* [#758][]: Add `Intp`, `Stringp`, and other similar `*p` field constructors
to log pointers to primitives with support for `nil` values.
Thanks to @jbizzle for their contributions to this release.
## 1.12.0 (29 Oct 2019)
Enhancements:
* [#751][]: Migrate to Go modules.
## 1.11.0 (21 Oct 2019)
Enhancements:
* [#725][]: Add `zapcore.OmitKey` to omit keys in an `EncoderConfig`.
* [#736][]: Add `RFC3339` and `RFC3339Nano` time encoders.
Thanks to @juicemia, @uhthomas for their contributions to this release.
## 1.10.0 (29 Apr 2019)
Bugfixes:
* [#657][]: Fix `MapObjectEncoder.AppendByteString` not adding value as a
string.
* [#706][]: Fix incorrect call depth to determine caller in Go 1.12.
Enhancements:
* [#610][]: Add `zaptest.WrapOptions` to wrap `zap.Option` for creating test
loggers.
* [#675][]: Don't panic when encoding a String field.
* [#704][]: Disable HTML escaping for JSON objects encoded using the
reflect-based encoder.
Thanks to @iaroslav-ciupin, @lelenanam, @joa, @NWilson for their contributions
to this release.
## v1.9.1 (06 Aug 2018)
Bugfixes:
* [#614][]: MapObjectEncoder should not ignore empty slices.
## v1.9.0 (19 Jul 2018)
Enhancements:
* [#602][]: Reduce number of allocations when logging with reflection.
* [#572][], [#606][]: Expose a registry for third-party logging sinks.
Thanks to @nfarah86, @AlekSi, @JeanMertz, @philippgille, @etsangsplk, and
@dimroc for their contributions to this release.
## v1.8.0 (13 Apr 2018)
Enhancements:
* [#508][]: Make log level configurable when redirecting the standard
library's logger.
* [#518][]: Add a logger that writes to a `*testing.TB`.
* [#577][]: Add a top-level alias for `zapcore.Field` to clean up GoDoc.
Bugfixes:
* [#574][]: Add a missing import comment to `go.uber.org/zap/buffer`.
Thanks to @DiSiqueira and @djui for their contributions to this release.
## v1.7.1 (25 Sep 2017)
Bugfixes:
* [#504][]: Store strings when using AddByteString with the map encoder.
## v1.7.0 (21 Sep 2017)
Enhancements:
* [#487][]: Add `NewStdLogAt`, which extends `NewStdLog` by allowing the user
to specify the level of the logged messages.
## v1.6.0 (30 Aug 2017)
Enhancements:
* [#491][]: Omit zap stack frames from stacktraces.
* [#490][]: Add a `ContextMap` method to observer logs for simpler
field validation in tests.
## v1.5.0 (22 Jul 2017)
Enhancements:
* [#460][] and [#470][]: Support errors produced by `go.uber.org/multierr`.
* [#465][]: Support user-supplied encoders for logger names.
Bugfixes:
* [#477][]: Fix a bug that incorrectly truncated deep stacktraces.
Thanks to @richard-tunein and @pavius for their contributions to this release.
## v1.4.1 (08 Jun 2017)
This release fixes two bugs.
Bugfixes:
* [#435][]: Support a variety of case conventions when unmarshaling levels.
* [#444][]: Fix a panic in the observer.
## v1.4.0 (12 May 2017)
This release adds a few small features and is fully backward-compatible.
Enhancements:
* [#424][]: Add a `LineEnding` field to `EncoderConfig`, allowing users to
override the Unix-style default.
* [#425][]: Preserve time zones when logging times.
* [#431][]: Make `zap.AtomicLevel` implement `fmt.Stringer`, which makes a
variety of operations a bit simpler.
## v1.3.0 (25 Apr 2017)
This release adds an enhancement to zap's testing helpers as well as the
ability to marshal an AtomicLevel. It is fully backward-compatible.
Enhancements:
* [#415][]: Add a substring-filtering helper to zap's observer. This is
particularly useful when testing the `SugaredLogger`.
* [#416][]: Make `AtomicLevel` implement `encoding.TextMarshaler`.
## v1.2.0 (13 Apr 2017)
This release adds a gRPC compatibility wrapper. It is fully backward-compatible.
Enhancements:
* [#402][]: Add a `zapgrpc` package that wraps zap's Logger and implements
`grpclog.Logger`.
## v1.1.0 (31 Mar 2017)
This release fixes two bugs and adds some enhancements to zap's testing helpers.
It is fully backward-compatible.
Bugfixes:
* [#385][]: Fix caller path trimming on Windows.
* [#396][]: Fix a panic when attempting to use non-existent directories with
zap's configuration struct.
Enhancements:
* [#386][]: Add filtering helpers to zaptest's observing logger.
Thanks to @moitias for contributing to this release.
## v1.0.0 (14 Mar 2017)
This is zap's first stable release. All exported APIs are now final, and no
further breaking changes will be made in the 1.x release series. Anyone using a
semver-aware dependency manager should now pin to `^1`.
Breaking changes:
* [#366][]: Add byte-oriented APIs to encoders to log UTF-8 encoded text without
casting from `[]byte` to `string`.
* [#364][]: To support buffering outputs, add `Sync` methods to `zapcore.Core`,
`zap.Logger`, and `zap.SugaredLogger`.
* [#371][]: Rename the `testutils` package to `zaptest`, which is less likely to
clash with other testing helpers.
Bugfixes:
* [#362][]: Make the ISO8601 time formatters fixed-width, which is friendlier
for tab-separated console output.
* [#369][]: Remove the automatic locks in `zapcore.NewCore`, which allows zap to
work with concurrency-safe `WriteSyncer` implementations.
* [#347][]: Stop reporting errors when trying to `fsync` standard out on Linux
systems.
* [#373][]: Report the correct caller from zap's standard library
interoperability wrappers.
Enhancements:
* [#348][]: Add a registry allowing third-party encodings to work with zap's
built-in `Config`.
* [#327][]: Make the representation of logger callers configurable (like times,
levels, and durations).
* [#376][]: Allow third-party encoders to use their own buffer pools, which
removes the last performance advantage that zap's encoders have over plugins.
* [#346][]: Add `CombineWriteSyncers`, a convenience function to tee multiple
`WriteSyncer`s and lock the result.
* [#365][]: Make zap's stacktraces compatible with mid-stack inlining (coming in
Go 1.9).
* [#372][]: Export zap's observing logger as `zaptest/observer`. This makes it
easier for particularly punctilious users to unit test their application's
logging.
Thanks to @suyash, @htrendev, @flisky, @Ulexus, and @skipor for their
contributions to this release.
## v1.0.0-rc.3 (7 Mar 2017)
This is the third release candidate for zap's stable release. There are no
breaking changes.
Bugfixes:
* [#339][]: Byte slices passed to `zap.Any` are now correctly treated as binary blobs
rather than `[]uint8`.
Enhancements:
* [#307][]: Users can opt into colored output for log levels.
* [#353][]: In addition to hijacking the output of the standard library's
package-global logging functions, users can now construct a zap-backed
`log.Logger` instance.
* [#311][]: Frames from common runtime functions and some of zap's internal
machinery are now omitted from stacktraces.
Thanks to @ansel1 and @suyash for their contributions to this release.
## v1.0.0-rc.2 (21 Feb 2017)
This is the second release candidate for zap's stable release. It includes two
breaking changes.
Breaking changes:
* [#316][]: Zap's global loggers are now fully concurrency-safe
(previously, users had to ensure that `ReplaceGlobals` was called before the
loggers were in use). However, they must now be accessed via the `L()` and
`S()` functions. Users can update their projects with
```
gofmt -r "zap.L -> zap.L()" -w .
gofmt -r "zap.S -> zap.S()" -w .
```
* [#309][] and [#317][]: RC1 was mistakenly shipped with invalid
JSON and YAML struct tags on all config structs. This release fixes the tags
and adds static analysis to prevent similar bugs in the future.
Bugfixes:
* [#321][]: Redirecting the standard library's `log` output now
correctly reports the logger's caller.
Enhancements:
* [#325][] and [#333][]: Zap now transparently supports non-standard, rich
errors like those produced by `github.com/pkg/errors`.
* [#326][]: Though `New(nil)` continues to return a no-op logger, `NewNop()` is
now preferred. Users can update their projects with `gofmt -r 'zap.New(nil) ->
zap.NewNop()' -w .`.
* [#300][]: Incorrectly importing zap as `github.com/uber-go/zap` now returns a
more informative error.
Thanks to @skipor and @chapsuk for their contributions to this release.
## v1.0.0-rc.1 (14 Feb 2017)
This is the first release candidate for zap's stable release. There are multiple
breaking changes and improvements from the pre-release version. Most notably:
* **Zap's import path is now "go.uber.org/zap"** &mdash; all users will
need to update their code.
* User-facing types and functions remain in the `zap` package. Code relevant
largely to extension authors is now in the `zapcore` package.
* The `zapcore.Core` type makes it easy for third-party packages to use zap's
internals but provide a different user-facing API.
* `Logger` is now a concrete type instead of an interface.
* A less verbose (though slower) logging API is included by default.
* Package-global loggers `L` and `S` are included.
* A human-friendly console encoder is included.
* A declarative config struct allows common logger configurations to be managed
as configuration instead of code.
* Sampling is more accurate, and doesn't depend on the standard library's shared
timer heap.
## v0.1.0-beta.1 (6 Feb 2017)
This is a minor version, tagged to allow users to pin to the pre-1.0 APIs and
upgrade at their leisure. Since this is the first tagged release, there are no
backward compatibility concerns and all functionality is new.
Early zap adopters should pin to the 0.1.x minor version until they're ready to
upgrade to the upcoming stable release.
[#316]: https://github.com/uber-go/zap/pull/316
[#309]: https://github.com/uber-go/zap/pull/309
[#317]: https://github.com/uber-go/zap/pull/317
[#321]: https://github.com/uber-go/zap/pull/321
[#325]: https://github.com/uber-go/zap/pull/325
[#333]: https://github.com/uber-go/zap/pull/333
[#326]: https://github.com/uber-go/zap/pull/326
[#300]: https://github.com/uber-go/zap/pull/300
[#339]: https://github.com/uber-go/zap/pull/339
[#307]: https://github.com/uber-go/zap/pull/307
[#353]: https://github.com/uber-go/zap/pull/353
[#311]: https://github.com/uber-go/zap/pull/311
[#366]: https://github.com/uber-go/zap/pull/366
[#364]: https://github.com/uber-go/zap/pull/364
[#371]: https://github.com/uber-go/zap/pull/371
[#362]: https://github.com/uber-go/zap/pull/362
[#369]: https://github.com/uber-go/zap/pull/369
[#347]: https://github.com/uber-go/zap/pull/347
[#373]: https://github.com/uber-go/zap/pull/373
[#348]: https://github.com/uber-go/zap/pull/348
[#327]: https://github.com/uber-go/zap/pull/327
[#376]: https://github.com/uber-go/zap/pull/376
[#346]: https://github.com/uber-go/zap/pull/346
[#365]: https://github.com/uber-go/zap/pull/365
[#372]: https://github.com/uber-go/zap/pull/372
[#385]: https://github.com/uber-go/zap/pull/385
[#396]: https://github.com/uber-go/zap/pull/396
[#386]: https://github.com/uber-go/zap/pull/386
[#402]: https://github.com/uber-go/zap/pull/402
[#415]: https://github.com/uber-go/zap/pull/415
[#416]: https://github.com/uber-go/zap/pull/416
[#424]: https://github.com/uber-go/zap/pull/424
[#425]: https://github.com/uber-go/zap/pull/425
[#431]: https://github.com/uber-go/zap/pull/431
[#435]: https://github.com/uber-go/zap/pull/435
[#444]: https://github.com/uber-go/zap/pull/444
[#477]: https://github.com/uber-go/zap/pull/477
[#465]: https://github.com/uber-go/zap/pull/465
[#460]: https://github.com/uber-go/zap/pull/460
[#470]: https://github.com/uber-go/zap/pull/470
[#487]: https://github.com/uber-go/zap/pull/487
[#490]: https://github.com/uber-go/zap/pull/490
[#491]: https://github.com/uber-go/zap/pull/491
[#504]: https://github.com/uber-go/zap/pull/504
[#508]: https://github.com/uber-go/zap/pull/508
[#518]: https://github.com/uber-go/zap/pull/518
[#577]: https://github.com/uber-go/zap/pull/577
[#574]: https://github.com/uber-go/zap/pull/574
[#602]: https://github.com/uber-go/zap/pull/602
[#572]: https://github.com/uber-go/zap/pull/572
[#606]: https://github.com/uber-go/zap/pull/606
[#614]: https://github.com/uber-go/zap/pull/614
[#657]: https://github.com/uber-go/zap/pull/657
[#706]: https://github.com/uber-go/zap/pull/706
[#610]: https://github.com/uber-go/zap/pull/610
[#675]: https://github.com/uber-go/zap/pull/675
[#704]: https://github.com/uber-go/zap/pull/704
[#725]: https://github.com/uber-go/zap/pull/725
[#736]: https://github.com/uber-go/zap/pull/736
[#751]: https://github.com/uber-go/zap/pull/751
[#758]: https://github.com/uber-go/zap/pull/758
[#771]: https://github.com/uber-go/zap/pull/771
[#773]: https://github.com/uber-go/zap/pull/773
[#775]: https://github.com/uber-go/zap/pull/775
[#786]: https://github.com/uber-go/zap/pull/786
[#791]: https://github.com/uber-go/zap/pull/791
[#795]: https://github.com/uber-go/zap/pull/795
[#799]: https://github.com/uber-go/zap/pull/799
[#804]: https://github.com/uber-go/zap/pull/804
[#812]: https://github.com/uber-go/zap/pull/812
[#806]: https://github.com/uber-go/zap/pull/806
[#813]: https://github.com/uber-go/zap/pull/813
[#629]: https://github.com/uber-go/zap/pull/629
[#697]: https://github.com/uber-go/zap/pull/697
[#828]: https://github.com/uber-go/zap/pull/828
[#835]: https://github.com/uber-go/zap/pull/835
[#843]: https://github.com/uber-go/zap/pull/843
[#844]: https://github.com/uber-go/zap/pull/844
[#852]: https://github.com/uber-go/zap/pull/852
[#854]: https://github.com/uber-go/zap/pull/854
[#861]: https://github.com/uber-go/zap/pull/861
[#862]: https://github.com/uber-go/zap/pull/862
[#865]: https://github.com/uber-go/zap/pull/865
[#867]: https://github.com/uber-go/zap/pull/867
[#881]: https://github.com/uber-go/zap/pull/881
[#903]: https://github.com/uber-go/zap/pull/903
[#912]: https://github.com/uber-go/zap/pull/912
[#913]: https://github.com/uber-go/zap/pull/913
[#928]: https://github.com/uber-go/zap/pull/928
[#931]: https://github.com/uber-go/zap/pull/931
[#936]: https://github.com/uber-go/zap/pull/936

75
vendor/go.uber.org/zap/CODE_OF_CONDUCT.md сгенерированный поставляемый
Просмотреть файл

@@ -1,75 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age,
body size, disability, ethnicity, gender identity and expression, level of
experience, nationality, personal appearance, race, religion, or sexual
identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an
appointed representative at an online or offline event. Representation of a
project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at oss-conduct@uber.com. The project
team will review and investigate all complaints, and will respond in a way
that it deems appropriate to the circumstances. The project team is obligated
to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at
[http://contributor-covenant.org/version/1/4][version].
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

75
vendor/go.uber.org/zap/CONTRIBUTING.md сгенерированный поставляемый
Просмотреть файл

@@ -1,75 +0,0 @@
# Contributing
We'd love your help making zap the very best structured logging library in Go!
If you'd like to add new exported APIs, please [open an issue][open-issue]
describing your proposal &mdash; discussing API changes ahead of time makes
pull request review much smoother. In your issue, pull request, and any other
communications, please remember to treat your fellow contributors with
respect! We take our [code of conduct](CODE_OF_CONDUCT.md) seriously.
Note that you'll need to sign [Uber's Contributor License Agreement][cla]
before we can accept any of your contributions. If necessary, a bot will remind
you to accept the CLA when you open your pull request.
## Setup
[Fork][fork], then clone the repository:
```
mkdir -p $GOPATH/src/go.uber.org
cd $GOPATH/src/go.uber.org
git clone git@github.com:your_github_username/zap.git
cd zap
git remote add upstream https://github.com/uber-go/zap.git
git fetch upstream
```
Make sure that the tests and the linters pass:
```
make test
make lint
```
If you're not using the minor version of Go specified in the Makefile's
`LINTABLE_MINOR_VERSIONS` variable, `make lint` doesn't do anything. This is
fine, but it means that you'll only discover lint failures after you open your
pull request.
## Making Changes
Start by creating a new branch for your changes:
```
cd $GOPATH/src/go.uber.org/zap
git checkout master
git fetch upstream
git rebase upstream/master
git checkout -b cool_new_feature
```
Make your changes, then ensure that `make lint` and `make test` still pass. If
you're satisfied with your changes, push them to your fork.
```
git push origin cool_new_feature
```
Then use the GitHub UI to open a pull request.
At this point, you're waiting on us to review your changes. We *try* to respond
to issues and pull requests within a few business days, and we may suggest some
improvements or alternatives. Once your changes are approved, one of the
project maintainers will merge them.
We're much more likely to approve your changes if you:
* Add tests for new functionality.
* Write a [good commit message][commit-message].
* Maintain backward compatibility.
[fork]: https://github.com/uber-go/zap/fork
[open-issue]: https://github.com/uber-go/zap/issues/new
[cla]: https://cla-assistant.io/uber-go/zap
[commit-message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html

164
vendor/go.uber.org/zap/FAQ.md сгенерированный поставляемый
Просмотреть файл

@@ -1,164 +0,0 @@
# Frequently Asked Questions
## Design
### Why spend so much effort on logger performance?
Of course, most applications won't notice the impact of a slow logger: they
already take tens or hundreds of milliseconds for each operation, so an extra
millisecond doesn't matter.
On the other hand, why *not* make structured logging fast? The `SugaredLogger`
isn't any harder to use than other logging packages, and the `Logger` makes
structured logging possible in performance-sensitive contexts. Across a fleet
of Go microservices, making each application even slightly more efficient adds
up quickly.
### Why aren't `Logger` and `SugaredLogger` interfaces?
Unlike the familiar `io.Writer` and `http.Handler`, `Logger` and
`SugaredLogger` interfaces would include *many* methods. As [Rob Pike points
out][go-proverbs], "The bigger the interface, the weaker the abstraction."
Interfaces are also rigid &mdash; *any* change requires releasing a new major
version, since it breaks all third-party implementations.
Making the `Logger` and `SugaredLogger` concrete types doesn't sacrifice much
abstraction, and it lets us add methods without introducing breaking changes.
Your applications should define and depend upon an interface that includes
just the methods you use.
### Why are some of my logs missing?
Logs are dropped intentionally by zap when sampling is enabled. The production
configuration (as returned by `NewProductionConfig()` enables sampling which will
cause repeated logs within a second to be sampled. See more details on why sampling
is enabled in [Why sample application logs](https://github.com/uber-go/zap/blob/master/FAQ.md#why-sample-application-logs).
### Why sample application logs?
Applications often experience runs of errors, either because of a bug or
because of a misbehaving user. Logging errors is usually a good idea, but it
can easily make this bad situation worse: not only is your application coping
with a flood of errors, it's also spending extra CPU cycles and I/O logging
those errors. Since writes are typically serialized, logging limits throughput
when you need it most.
Sampling fixes this problem by dropping repetitive log entries. Under normal
conditions, your application writes out every entry. When similar entries are
logged hundreds or thousands of times each second, though, zap begins dropping
duplicates to preserve throughput.
### Why do the structured logging APIs take a message in addition to fields?
Subjectively, we find it helpful to accompany structured context with a brief
description. This isn't critical during development, but it makes debugging
and operating unfamiliar systems much easier.
More concretely, zap's sampling algorithm uses the message to identify
duplicate entries. In our experience, this is a practical middle ground
between random sampling (which often drops the exact entry that you need while
debugging) and hashing the complete entry (which is prohibitively expensive).
### Why include package-global loggers?
Since so many other logging packages include a global logger, many
applications aren't designed to accept loggers as explicit parameters.
Changing function signatures is often a breaking change, so zap includes
global loggers to simplify migration.
Avoid them where possible.
### Why include dedicated Panic and Fatal log levels?
In general, application code should handle errors gracefully instead of using
`panic` or `os.Exit`. However, every rule has exceptions, and it's common to
crash when an error is truly unrecoverable. To avoid losing any information
&mdash; especially the reason for the crash &mdash; the logger must flush any
buffered entries before the process exits.
Zap makes this easy by offering `Panic` and `Fatal` logging methods that
automatically flush before exiting. Of course, this doesn't guarantee that
logs will never be lost, but it eliminates a common error.
See the discussion in uber-go/zap#207 for more details.
### What's `DPanic`?
`DPanic` stands for "panic in development." In development, it logs at
`PanicLevel`; otherwise, it logs at `ErrorLevel`. `DPanic` makes it easier to
catch errors that are theoretically possible, but shouldn't actually happen,
*without* crashing in production.
If you've ever written code like this, you need `DPanic`:
```go
if err != nil {
panic(fmt.Sprintf("shouldn't ever get here: %v", err))
}
```
## Installation
### What does the error `expects import "go.uber.org/zap"` mean?
Either zap was installed incorrectly or you're referencing the wrong package
name in your code.
Zap's source code happens to be hosted on GitHub, but the [import
path][import-path] is `go.uber.org/zap`. This gives us, the project
maintainers, the freedom to move the source code if necessary. However, it
means that you need to take a little care when installing and using the
package.
If you follow two simple rules, everything should work: install zap with `go
get -u go.uber.org/zap`, and always import it in your code with `import
"go.uber.org/zap"`. Your code shouldn't contain *any* references to
`github.com/uber-go/zap`.
## Usage
### Does zap support log rotation?
Zap doesn't natively support rotating log files, since we prefer to leave this
to an external program like `logrotate`.
However, it's easy to integrate a log rotation package like
[`gopkg.in/natefinch/lumberjack.v2`][lumberjack] as a `zapcore.WriteSyncer`.
```go
// lumberjack.Logger is already safe for concurrent use, so we don't need to
// lock it.
w := zapcore.AddSync(&lumberjack.Logger{
Filename: "/var/log/myapp/foo.log",
MaxSize: 500, // megabytes
MaxBackups: 3,
MaxAge: 28, // days
})
core := zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
w,
zap.InfoLevel,
)
logger := zap.New(core)
```
## Extensions
We'd love to support every logging need within zap itself, but we're only
familiar with a handful of log ingestion systems, flag-parsing packages, and
the like. Rather than merging code that we can't effectively debug and
support, we'd rather grow an ecosystem of zap extensions.
We're aware of the following extensions, but haven't used them ourselves:
| Package | Integration |
| --- | --- |
| `github.com/tchap/zapext` | Sentry, syslog |
| `github.com/fgrosse/zaptest` | Ginkgo |
| `github.com/blendle/zapdriver` | Stackdriver |
| `github.com/moul/zapgorm` | Gorm |
| `github.com/moul/zapfilter` | Advanced filtering rules |
[go-proverbs]: https://go-proverbs.github.io/
[import-path]: https://golang.org/cmd/go/#hdr-Remote_import_paths
[lumberjack]: https://godoc.org/gopkg.in/natefinch/lumberjack.v2

19
vendor/go.uber.org/zap/LICENSE.txt сгенерированный поставляемый
Просмотреть файл

@@ -1,19 +0,0 @@
Copyright (c) 2016-2017 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.

73
vendor/go.uber.org/zap/Makefile сгенерированный поставляемый
Просмотреть файл

@@ -1,73 +0,0 @@
export GOBIN ?= $(shell pwd)/bin
GOLINT = $(GOBIN)/golint
STATICCHECK = $(GOBIN)/staticcheck
BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem
# Directories containing independent Go modules.
#
# We track coverage only for the main module.
MODULE_DIRS = . ./benchmarks ./zapgrpc/internal/test
# Many Go tools take file globs or directories as arguments instead of packages.
GO_FILES := $(shell \
find . '(' -path '*/.*' -o -path './vendor' ')' -prune \
-o -name '*.go' -print | cut -b3-)
.PHONY: all
all: lint test
.PHONY: lint
lint: $(GOLINT) $(STATICCHECK)
@rm -rf lint.log
@echo "Checking formatting..."
@gofmt -d -s $(GO_FILES) 2>&1 | tee lint.log
@echo "Checking vet..."
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go vet ./... 2>&1) &&) true | tee -a lint.log
@echo "Checking lint..."
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && $(GOLINT) ./... 2>&1) &&) true | tee -a lint.log
@echo "Checking staticcheck..."
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && $(STATICCHECK) ./... 2>&1) &&) true | tee -a lint.log
@echo "Checking for unresolved FIXMEs..."
@git grep -i fixme | grep -v -e Makefile | tee -a lint.log
@echo "Checking for license headers..."
@./checklicense.sh | tee -a lint.log
@[ ! -s lint.log ]
@echo "Checking 'go mod tidy'..."
@make tidy
@if ! git diff --quiet; then \
echo "'go mod tidy' resulted in changes or working tree is dirty:"; \
git --no-pager diff; \
fi
$(GOLINT):
cd tools && go install golang.org/x/lint/golint
$(STATICCHECK):
cd tools && go install honnef.co/go/tools/cmd/staticcheck
.PHONY: test
test:
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go test -race ./...) &&) true
.PHONY: cover
cover:
go test -race -coverprofile=cover.out -coverpkg=./... ./...
go tool cover -html=cover.out -o cover.html
.PHONY: bench
BENCH ?= .
bench:
@$(foreach dir,$(MODULE_DIRS), ( \
cd $(dir) && \
go list ./... | xargs -n1 go test -bench=$(BENCH) -run="^$$" $(BENCH_FLAGS) \
) &&) true
.PHONY: updatereadme
updatereadme:
rm -f README.md
cat .readme.tmpl | go run internal/readme/readme.go > README.md
.PHONY: tidy
tidy:
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go mod tidy) &&) true

134
vendor/go.uber.org/zap/README.md сгенерированный поставляемый
Просмотреть файл

@@ -1,134 +0,0 @@
# :zap: zap [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
Blazing fast, structured, leveled logging in Go.
## Installation
`go get -u go.uber.org/zap`
Note that zap only supports the two most recent minor versions of Go.
## Quick Start
In contexts where performance is nice, but not critical, use the
`SugaredLogger`. It's 4-10x faster than other structured logging
packages and includes both structured and `printf`-style APIs.
```go
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
```
When performance and type safety are critical, use the `Logger`. It's even
faster than the `SugaredLogger` and allocates far less, but it only supports
structured logging.
```go
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
```
See the [documentation][doc] and [FAQ](FAQ.md) for more details.
## Performance
For applications that log in the hot path, reflection-based serialization and
string formatting are prohibitively expensive &mdash; they're CPU-intensive
and make many small allocations. Put differently, using `encoding/json` and
`fmt.Fprintf` to log tons of `interface{}`s makes your application slow.
Zap takes a different approach. It includes a reflection-free, zero-allocation
JSON encoder, and the base `Logger` strives to avoid serialization overhead
and allocations wherever possible. By building the high-level `SugaredLogger`
on that foundation, zap lets users *choose* when they need to count every
allocation and when they'd prefer a more familiar, loosely typed API.
As measured by its own [benchmarking suite][], not only is zap more performant
than comparable structured logging packages &mdash; it's also faster than the
standard library. Like all benchmarks, take these with a grain of salt.<sup
id="anchor-versions">[1](#footnote-versions)</sup>
Log a message and 10 fields:
| Package | Time | Time % to zap | Objects Allocated |
| :------ | :--: | :-----------: | :---------------: |
| :zap: zap | 862 ns/op | +0% | 5 allocs/op
| :zap: zap (sugared) | 1250 ns/op | +45% | 11 allocs/op
| zerolog | 4021 ns/op | +366% | 76 allocs/op
| go-kit | 4542 ns/op | +427% | 105 allocs/op
| apex/log | 26785 ns/op | +3007% | 115 allocs/op
| logrus | 29501 ns/op | +3322% | 125 allocs/op
| log15 | 29906 ns/op | +3369% | 122 allocs/op
Log a message with a logger that already has 10 fields of context:
| Package | Time | Time % to zap | Objects Allocated |
| :------ | :--: | :-----------: | :---------------: |
| :zap: zap | 126 ns/op | +0% | 0 allocs/op
| :zap: zap (sugared) | 187 ns/op | +48% | 2 allocs/op
| zerolog | 88 ns/op | -30% | 0 allocs/op
| go-kit | 5087 ns/op | +3937% | 103 allocs/op
| log15 | 18548 ns/op | +14621% | 73 allocs/op
| apex/log | 26012 ns/op | +20544% | 104 allocs/op
| logrus | 27236 ns/op | +21516% | 113 allocs/op
Log a static string, without any context or `printf`-style templating:
| Package | Time | Time % to zap | Objects Allocated |
| :------ | :--: | :-----------: | :---------------: |
| :zap: zap | 118 ns/op | +0% | 0 allocs/op
| :zap: zap (sugared) | 191 ns/op | +62% | 2 allocs/op
| zerolog | 93 ns/op | -21% | 0 allocs/op
| go-kit | 280 ns/op | +137% | 11 allocs/op
| standard library | 499 ns/op | +323% | 2 allocs/op
| apex/log | 1990 ns/op | +1586% | 10 allocs/op
| logrus | 3129 ns/op | +2552% | 24 allocs/op
| log15 | 3887 ns/op | +3194% | 23 allocs/op
## Development Status: Stable
All APIs are finalized, and no breaking changes will be made in the 1.x series
of releases. Users of semver-aware dependency management systems should pin
zap to `^1`.
## Contributing
We encourage and support an active, healthy community of contributors &mdash;
including you! Details are in the [contribution guide](CONTRIBUTING.md) and
the [code of conduct](CODE_OF_CONDUCT.md). The zap maintainers keep an eye on
issues and pull requests, but you can also report any negative conduct to
oss-conduct@uber.com. That email list is a private, safe space; even the zap
maintainers don't have access, so don't hesitate to hold us to a high
standard.
<hr>
Released under the [MIT License](LICENSE.txt).
<sup id="footnote-versions">1</sup> In particular, keep in mind that we may be
benchmarking against slightly older versions of other packages. Versions are
pinned in the [benchmarks/go.mod][] file. [](#anchor-versions)
[doc-img]: https://pkg.go.dev/badge/go.uber.org/zap
[doc]: https://pkg.go.dev/go.uber.org/zap
[ci-img]: https://github.com/uber-go/zap/actions/workflows/go.yml/badge.svg
[ci]: https://github.com/uber-go/zap/actions/workflows/go.yml
[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/zap
[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks
[benchmarks/go.mod]: https://github.com/uber-go/zap/blob/master/benchmarks/go.mod

320
vendor/go.uber.org/zap/array.go сгенерированный поставляемый
Просмотреть файл

@@ -1,320 +0,0 @@
// 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 zap
import (
"time"
"go.uber.org/zap/zapcore"
)
// Array constructs a field with the given key and ArrayMarshaler. It provides
// a flexible, but still type-safe and efficient, way to add array-like types
// to the logging context. The struct's MarshalLogArray method is called lazily.
func Array(key string, val zapcore.ArrayMarshaler) Field {
return Field{Key: key, Type: zapcore.ArrayMarshalerType, Interface: val}
}
// Bools constructs a field that carries a slice of bools.
func Bools(key string, bs []bool) Field {
return Array(key, bools(bs))
}
// ByteStrings constructs a field that carries a slice of []byte, each of which
// must be UTF-8 encoded text.
func ByteStrings(key string, bss [][]byte) Field {
return Array(key, byteStringsArray(bss))
}
// Complex128s constructs a field that carries a slice of complex numbers.
func Complex128s(key string, nums []complex128) Field {
return Array(key, complex128s(nums))
}
// Complex64s constructs a field that carries a slice of complex numbers.
func Complex64s(key string, nums []complex64) Field {
return Array(key, complex64s(nums))
}
// Durations constructs a field that carries a slice of time.Durations.
func Durations(key string, ds []time.Duration) Field {
return Array(key, durations(ds))
}
// Float64s constructs a field that carries a slice of floats.
func Float64s(key string, nums []float64) Field {
return Array(key, float64s(nums))
}
// Float32s constructs a field that carries a slice of floats.
func Float32s(key string, nums []float32) Field {
return Array(key, float32s(nums))
}
// Ints constructs a field that carries a slice of integers.
func Ints(key string, nums []int) Field {
return Array(key, ints(nums))
}
// Int64s constructs a field that carries a slice of integers.
func Int64s(key string, nums []int64) Field {
return Array(key, int64s(nums))
}
// Int32s constructs a field that carries a slice of integers.
func Int32s(key string, nums []int32) Field {
return Array(key, int32s(nums))
}
// Int16s constructs a field that carries a slice of integers.
func Int16s(key string, nums []int16) Field {
return Array(key, int16s(nums))
}
// Int8s constructs a field that carries a slice of integers.
func Int8s(key string, nums []int8) Field {
return Array(key, int8s(nums))
}
// Strings constructs a field that carries a slice of strings.
func Strings(key string, ss []string) Field {
return Array(key, stringArray(ss))
}
// Times constructs a field that carries a slice of time.Times.
func Times(key string, ts []time.Time) Field {
return Array(key, times(ts))
}
// Uints constructs a field that carries a slice of unsigned integers.
func Uints(key string, nums []uint) Field {
return Array(key, uints(nums))
}
// Uint64s constructs a field that carries a slice of unsigned integers.
func Uint64s(key string, nums []uint64) Field {
return Array(key, uint64s(nums))
}
// Uint32s constructs a field that carries a slice of unsigned integers.
func Uint32s(key string, nums []uint32) Field {
return Array(key, uint32s(nums))
}
// Uint16s constructs a field that carries a slice of unsigned integers.
func Uint16s(key string, nums []uint16) Field {
return Array(key, uint16s(nums))
}
// Uint8s constructs a field that carries a slice of unsigned integers.
func Uint8s(key string, nums []uint8) Field {
return Array(key, uint8s(nums))
}
// Uintptrs constructs a field that carries a slice of pointer addresses.
func Uintptrs(key string, us []uintptr) Field {
return Array(key, uintptrs(us))
}
// Errors constructs a field that carries a slice of errors.
func Errors(key string, errs []error) Field {
return Array(key, errArray(errs))
}
type bools []bool
func (bs bools) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range bs {
arr.AppendBool(bs[i])
}
return nil
}
type byteStringsArray [][]byte
func (bss byteStringsArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range bss {
arr.AppendByteString(bss[i])
}
return nil
}
type complex128s []complex128
func (nums complex128s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendComplex128(nums[i])
}
return nil
}
type complex64s []complex64
func (nums complex64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendComplex64(nums[i])
}
return nil
}
type durations []time.Duration
func (ds durations) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ds {
arr.AppendDuration(ds[i])
}
return nil
}
type float64s []float64
func (nums float64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendFloat64(nums[i])
}
return nil
}
type float32s []float32
func (nums float32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendFloat32(nums[i])
}
return nil
}
type ints []int
func (nums ints) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt(nums[i])
}
return nil
}
type int64s []int64
func (nums int64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt64(nums[i])
}
return nil
}
type int32s []int32
func (nums int32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt32(nums[i])
}
return nil
}
type int16s []int16
func (nums int16s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt16(nums[i])
}
return nil
}
type int8s []int8
func (nums int8s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt8(nums[i])
}
return nil
}
type stringArray []string
func (ss stringArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ss {
arr.AppendString(ss[i])
}
return nil
}
type times []time.Time
func (ts times) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ts {
arr.AppendTime(ts[i])
}
return nil
}
type uints []uint
func (nums uints) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint(nums[i])
}
return nil
}
type uint64s []uint64
func (nums uint64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint64(nums[i])
}
return nil
}
type uint32s []uint32
func (nums uint32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint32(nums[i])
}
return nil
}
type uint16s []uint16
func (nums uint16s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint16(nums[i])
}
return nil
}
type uint8s []uint8
func (nums uint8s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint8(nums[i])
}
return nil
}
type uintptrs []uintptr
func (nums uintptrs) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUintptr(nums[i])
}
return nil
}

123
vendor/go.uber.org/zap/buffer/buffer.go сгенерированный поставляемый
Просмотреть файл

@@ -1,123 +0,0 @@
// 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 buffer provides a thin wrapper around a byte slice. Unlike the
// standard library's bytes.Buffer, it supports a portion of the strconv
// package's zero-allocation formatters.
package buffer // import "go.uber.org/zap/buffer"
import (
"strconv"
"time"
)
const _size = 1024 // by default, create 1 KiB buffers
// Buffer is a thin wrapper around a byte slice. It's intended to be pooled, so
// the only way to construct one is via a Pool.
type Buffer struct {
bs []byte
pool Pool
}
// AppendByte writes a single byte to the Buffer.
func (b *Buffer) AppendByte(v byte) {
b.bs = append(b.bs, v)
}
// AppendString writes a string to the Buffer.
func (b *Buffer) AppendString(s string) {
b.bs = append(b.bs, s...)
}
// AppendInt appends an integer to the underlying buffer (assuming base 10).
func (b *Buffer) AppendInt(i int64) {
b.bs = strconv.AppendInt(b.bs, i, 10)
}
// AppendTime appends the time formatted using the specified layout.
func (b *Buffer) AppendTime(t time.Time, layout string) {
b.bs = t.AppendFormat(b.bs, layout)
}
// AppendUint appends an unsigned integer to the underlying buffer (assuming
// base 10).
func (b *Buffer) AppendUint(i uint64) {
b.bs = strconv.AppendUint(b.bs, i, 10)
}
// AppendBool appends a bool to the underlying buffer.
func (b *Buffer) AppendBool(v bool) {
b.bs = strconv.AppendBool(b.bs, v)
}
// AppendFloat appends a float to the underlying buffer. It doesn't quote NaN
// or +/- Inf.
func (b *Buffer) AppendFloat(f float64, bitSize int) {
b.bs = strconv.AppendFloat(b.bs, f, 'f', -1, bitSize)
}
// Len returns the length of the underlying byte slice.
func (b *Buffer) Len() int {
return len(b.bs)
}
// Cap returns the capacity of the underlying byte slice.
func (b *Buffer) Cap() int {
return cap(b.bs)
}
// Bytes returns a mutable reference to the underlying byte slice.
func (b *Buffer) Bytes() []byte {
return b.bs
}
// String returns a string copy of the underlying byte slice.
func (b *Buffer) String() string {
return string(b.bs)
}
// Reset resets the underlying byte slice. Subsequent writes re-use the slice's
// backing array.
func (b *Buffer) Reset() {
b.bs = b.bs[:0]
}
// Write implements io.Writer.
func (b *Buffer) Write(bs []byte) (int, error) {
b.bs = append(b.bs, bs...)
return len(bs), nil
}
// TrimNewline trims any final "\n" byte from the end of the buffer.
func (b *Buffer) TrimNewline() {
if i := len(b.bs) - 1; i >= 0 {
if b.bs[i] == '\n' {
b.bs = b.bs[:i]
}
}
}
// Free returns the Buffer to its Pool.
//
// Callers must not retain references to the Buffer after calling Free.
func (b *Buffer) Free() {
b.pool.put(b)
}

49
vendor/go.uber.org/zap/buffer/pool.go сгенерированный поставляемый
Просмотреть файл

@@ -1,49 +0,0 @@
// 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 buffer
import "sync"
// A Pool is a type-safe wrapper around a sync.Pool.
type Pool struct {
p *sync.Pool
}
// NewPool constructs a new Pool.
func NewPool() Pool {
return Pool{p: &sync.Pool{
New: func() interface{} {
return &Buffer{bs: make([]byte, 0, _size)}
},
}}
}
// Get retrieves a Buffer from the pool, creating one if necessary.
func (p Pool) Get() *Buffer {
buf := p.p.Get().(*Buffer)
buf.Reset()
buf.pool = p
return buf
}
func (p Pool) put(buf *Buffer) {
p.p.Put(buf)
}

17
vendor/go.uber.org/zap/checklicense.sh сгенерированный поставляемый
Просмотреть файл

@@ -1,17 +0,0 @@
#!/bin/bash -e
ERROR_COUNT=0
while read -r file
do
case "$(head -1 "${file}")" in
*"Copyright (c) "*" Uber Technologies, Inc.")
# everything's cool
;;
*)
echo "$file is missing license header."
(( ERROR_COUNT++ ))
;;
esac
done < <(git ls-files "*\.go")
exit $ERROR_COUNT

264
vendor/go.uber.org/zap/config.go сгенерированный поставляемый
Просмотреть файл

@@ -1,264 +0,0 @@
// 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 zap
import (
"fmt"
"sort"
"time"
"go.uber.org/zap/zapcore"
)
// SamplingConfig sets a sampling strategy for the logger. Sampling caps the
// global CPU and I/O load that logging puts on your process while attempting
// to preserve a representative subset of your logs.
//
// If specified, the Sampler will invoke the Hook after each decision.
//
// Values configured here are per-second. See zapcore.NewSamplerWithOptions for
// details.
type SamplingConfig struct {
Initial int `json:"initial" yaml:"initial"`
Thereafter int `json:"thereafter" yaml:"thereafter"`
Hook func(zapcore.Entry, zapcore.SamplingDecision) `json:"-" yaml:"-"`
}
// Config offers a declarative way to construct a logger. It doesn't do
// anything that can't be done with New, Options, and the various
// zapcore.WriteSyncer and zapcore.Core wrappers, but it's a simpler way to
// toggle common options.
//
// Note that Config intentionally supports only the most common options. More
// unusual logging setups (logging to network connections or message queues,
// splitting output between multiple files, etc.) are possible, but require
// direct use of the zapcore package. For sample code, see the package-level
// BasicConfiguration and AdvancedConfiguration examples.
//
// For an example showing runtime log level changes, see the documentation for
// AtomicLevel.
type Config struct {
// Level is the minimum enabled logging level. Note that this is a dynamic
// level, so calling Config.Level.SetLevel will atomically change the log
// level of all loggers descended from this config.
Level AtomicLevel `json:"level" yaml:"level"`
// Development puts the logger in development mode, which changes the
// behavior of DPanicLevel and takes stacktraces more liberally.
Development bool `json:"development" yaml:"development"`
// DisableCaller stops annotating logs with the calling function's file
// name and line number. By default, all logs are annotated.
DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
// DisableStacktrace completely disables automatic stacktrace capturing. By
// default, stacktraces are captured for WarnLevel and above logs in
// development and ErrorLevel and above in production.
DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
// Sampling sets a sampling policy. A nil SamplingConfig disables sampling.
Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
// Encoding sets the logger's encoding. Valid values are "json" and
// "console", as well as any third-party encodings registered via
// RegisterEncoder.
Encoding string `json:"encoding" yaml:"encoding"`
// EncoderConfig sets options for the chosen encoder. See
// zapcore.EncoderConfig for details.
EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
// OutputPaths is a list of URLs or file paths to write logging output to.
// See Open for details.
OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
// ErrorOutputPaths is a list of URLs to write internal logger errors to.
// The default is standard error.
//
// Note that this setting only affects internal errors; for sample code that
// sends error-level logs to a different location from info- and debug-level
// logs, see the package-level AdvancedConfiguration example.
ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
// InitialFields is a collection of fields to add to the root logger.
InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
}
// NewProductionEncoderConfig returns an opinionated EncoderConfig for
// production environments.
func NewProductionEncoderConfig() zapcore.EncoderConfig {
return zapcore.EncoderConfig{
TimeKey: "ts",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
FunctionKey: zapcore.OmitKey,
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.EpochTimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
}
// NewProductionConfig is a reasonable production logging configuration.
// Logging is enabled at InfoLevel and above.
//
// It uses a JSON encoder, writes to standard error, and enables sampling.
// Stacktraces are automatically included on logs of ErrorLevel and above.
func NewProductionConfig() Config {
return Config{
Level: NewAtomicLevelAt(InfoLevel),
Development: false,
Sampling: &SamplingConfig{
Initial: 100,
Thereafter: 100,
},
Encoding: "json",
EncoderConfig: NewProductionEncoderConfig(),
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
}
}
// NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for
// development environments.
func NewDevelopmentEncoderConfig() zapcore.EncoderConfig {
return zapcore.EncoderConfig{
// Keys can be anything except the empty string.
TimeKey: "T",
LevelKey: "L",
NameKey: "N",
CallerKey: "C",
FunctionKey: zapcore.OmitKey,
MessageKey: "M",
StacktraceKey: "S",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
}
// NewDevelopmentConfig is a reasonable development logging configuration.
// Logging is enabled at DebugLevel and above.
//
// It enables development mode (which makes DPanicLevel logs panic), uses a
// console encoder, writes to standard error, and disables sampling.
// Stacktraces are automatically included on logs of WarnLevel and above.
func NewDevelopmentConfig() Config {
return Config{
Level: NewAtomicLevelAt(DebugLevel),
Development: true,
Encoding: "console",
EncoderConfig: NewDevelopmentEncoderConfig(),
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
}
}
// Build constructs a logger from the Config and Options.
func (cfg Config) Build(opts ...Option) (*Logger, error) {
enc, err := cfg.buildEncoder()
if err != nil {
return nil, err
}
sink, errSink, err := cfg.openSinks()
if err != nil {
return nil, err
}
if cfg.Level == (AtomicLevel{}) {
return nil, fmt.Errorf("missing Level")
}
log := New(
zapcore.NewCore(enc, sink, cfg.Level),
cfg.buildOptions(errSink)...,
)
if len(opts) > 0 {
log = log.WithOptions(opts...)
}
return log, nil
}
func (cfg Config) buildOptions(errSink zapcore.WriteSyncer) []Option {
opts := []Option{ErrorOutput(errSink)}
if cfg.Development {
opts = append(opts, Development())
}
if !cfg.DisableCaller {
opts = append(opts, AddCaller())
}
stackLevel := ErrorLevel
if cfg.Development {
stackLevel = WarnLevel
}
if !cfg.DisableStacktrace {
opts = append(opts, AddStacktrace(stackLevel))
}
if scfg := cfg.Sampling; scfg != nil {
opts = append(opts, WrapCore(func(core zapcore.Core) zapcore.Core {
var samplerOpts []zapcore.SamplerOption
if scfg.Hook != nil {
samplerOpts = append(samplerOpts, zapcore.SamplerHook(scfg.Hook))
}
return zapcore.NewSamplerWithOptions(
core,
time.Second,
cfg.Sampling.Initial,
cfg.Sampling.Thereafter,
samplerOpts...,
)
}))
}
if len(cfg.InitialFields) > 0 {
fs := make([]Field, 0, len(cfg.InitialFields))
keys := make([]string, 0, len(cfg.InitialFields))
for k := range cfg.InitialFields {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fs = append(fs, Any(k, cfg.InitialFields[k]))
}
opts = append(opts, Fields(fs...))
}
return opts
}
func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
sink, closeOut, err := Open(cfg.OutputPaths...)
if err != nil {
return nil, nil, err
}
errSink, _, err := Open(cfg.ErrorOutputPaths...)
if err != nil {
closeOut()
return nil, nil, err
}
return sink, errSink, nil
}
func (cfg Config) buildEncoder() (zapcore.Encoder, error) {
return newEncoder(cfg.Encoding, cfg.EncoderConfig)
}

113
vendor/go.uber.org/zap/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -1,113 +0,0 @@
// 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 zap provides fast, structured, leveled logging.
//
// For applications that log in the hot path, reflection-based serialization
// and string formatting are prohibitively expensive - they're CPU-intensive
// and make many small allocations. Put differently, using json.Marshal and
// fmt.Fprintf to log tons of interface{} makes your application slow.
//
// Zap takes a different approach. It includes a reflection-free,
// zero-allocation JSON encoder, and the base Logger strives to avoid
// serialization overhead and allocations wherever possible. By building the
// high-level SugaredLogger on that foundation, zap lets users choose when
// they need to count every allocation and when they'd prefer a more familiar,
// loosely typed API.
//
// Choosing a Logger
//
// In contexts where performance is nice, but not critical, use the
// SugaredLogger. It's 4-10x faster than other structured logging packages and
// supports both structured and printf-style logging. Like log15 and go-kit,
// the SugaredLogger's structured logging APIs are loosely typed and accept a
// variadic number of key-value pairs. (For more advanced use cases, they also
// accept strongly typed fields - see the SugaredLogger.With documentation for
// details.)
// sugar := zap.NewExample().Sugar()
// defer sugar.Sync()
// sugar.Infow("failed to fetch URL",
// "url", "http://example.com",
// "attempt", 3,
// "backoff", time.Second,
// )
// sugar.Infof("failed to fetch URL: %s", "http://example.com")
//
// By default, loggers are unbuffered. However, since zap's low-level APIs
// allow buffering, calling Sync before letting your process exit is a good
// habit.
//
// In the rare contexts where every microsecond and every allocation matter,
// use the Logger. It's even faster than the SugaredLogger and allocates far
// less, but it only supports strongly-typed, structured logging.
// logger := zap.NewExample()
// defer logger.Sync()
// logger.Info("failed to fetch URL",
// zap.String("url", "http://example.com"),
// zap.Int("attempt", 3),
// zap.Duration("backoff", time.Second),
// )
//
// Choosing between the Logger and SugaredLogger doesn't need to be an
// application-wide decision: converting between the two is simple and
// inexpensive.
// logger := zap.NewExample()
// defer logger.Sync()
// sugar := logger.Sugar()
// plain := sugar.Desugar()
//
// Configuring Zap
//
// The simplest way to build a Logger is to use zap's opinionated presets:
// NewExample, NewProduction, and NewDevelopment. These presets build a logger
// with a single function call:
// logger, err := zap.NewProduction()
// if err != nil {
// log.Fatalf("can't initialize zap logger: %v", err)
// }
// defer logger.Sync()
//
// Presets are fine for small projects, but larger projects and organizations
// naturally require a bit more customization. For most users, zap's Config
// struct strikes the right balance between flexibility and convenience. See
// the package-level BasicConfiguration example for sample code.
//
// More unusual configurations (splitting output between files, sending logs
// to a message queue, etc.) are possible, but require direct use of
// go.uber.org/zap/zapcore. See the package-level AdvancedConfiguration
// example for sample code.
//
// Extending Zap
//
// The zap package itself is a relatively thin wrapper around the interfaces
// in go.uber.org/zap/zapcore. Extending zap to support a new encoding (e.g.,
// BSON), a new log sink (e.g., Kafka), or something more exotic (perhaps an
// exception aggregation service, like Sentry or Rollbar) typically requires
// implementing the zapcore.Encoder, zapcore.WriteSyncer, or zapcore.Core
// interfaces. See the zapcore documentation for details.
//
// Similarly, package authors can use the high-performance Encoder and Core
// implementations in the zapcore package to build their own loggers.
//
// Frequently Asked Questions
//
// An FAQ covering everything from installation errors to design decisions is
// available at https://github.com/uber-go/zap/blob/master/FAQ.md.
package zap // import "go.uber.org/zap"

79
vendor/go.uber.org/zap/encoder.go сгенерированный поставляемый
Просмотреть файл

@@ -1,79 +0,0 @@
// 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 zap
import (
"errors"
"fmt"
"sync"
"go.uber.org/zap/zapcore"
)
var (
errNoEncoderNameSpecified = errors.New("no encoder name specified")
_encoderNameToConstructor = map[string]func(zapcore.EncoderConfig) (zapcore.Encoder, error){
"console": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
return zapcore.NewConsoleEncoder(encoderConfig), nil
},
"json": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
return zapcore.NewJSONEncoder(encoderConfig), nil
},
}
_encoderMutex sync.RWMutex
)
// RegisterEncoder registers an encoder constructor, which the Config struct
// can then reference. By default, the "json" and "console" encoders are
// registered.
//
// Attempting to register an encoder whose name is already taken returns an
// error.
func RegisterEncoder(name string, constructor func(zapcore.EncoderConfig) (zapcore.Encoder, error)) error {
_encoderMutex.Lock()
defer _encoderMutex.Unlock()
if name == "" {
return errNoEncoderNameSpecified
}
if _, ok := _encoderNameToConstructor[name]; ok {
return fmt.Errorf("encoder already registered for name %q", name)
}
_encoderNameToConstructor[name] = constructor
return nil
}
func newEncoder(name string, encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
if encoderConfig.TimeKey != "" && encoderConfig.EncodeTime == nil {
return nil, fmt.Errorf("missing EncodeTime in EncoderConfig")
}
_encoderMutex.RLock()
defer _encoderMutex.RUnlock()
if name == "" {
return nil, errNoEncoderNameSpecified
}
constructor, ok := _encoderNameToConstructor[name]
if !ok {
return nil, fmt.Errorf("no encoder registered for name %q", name)
}
return constructor(encoderConfig)
}

80
vendor/go.uber.org/zap/error.go сгенерированный поставляемый
Просмотреть файл

@@ -1,80 +0,0 @@
// Copyright (c) 2017 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 zap
import (
"sync"
"go.uber.org/zap/zapcore"
)
var _errArrayElemPool = sync.Pool{New: func() interface{} {
return &errArrayElem{}
}}
// Error is shorthand for the common idiom NamedError("error", err).
func Error(err error) Field {
return NamedError("error", err)
}
// NamedError constructs a field that lazily stores err.Error() under the
// provided key. Errors which also implement fmt.Formatter (like those produced
// by github.com/pkg/errors) will also have their verbose representation stored
// under key+"Verbose". If passed a nil error, the field is a no-op.
//
// For the common case in which the key is simply "error", the Error function
// is shorter and less repetitive.
func NamedError(key string, err error) Field {
if err == nil {
return Skip()
}
return Field{Key: key, Type: zapcore.ErrorType, Interface: err}
}
type errArray []error
func (errs errArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range errs {
if errs[i] == nil {
continue
}
// To represent each error as an object with an "error" attribute and
// potentially an "errorVerbose" attribute, we need to wrap it in a
// type that implements LogObjectMarshaler. To prevent this from
// allocating, pool the wrapper type.
elem := _errArrayElemPool.Get().(*errArrayElem)
elem.error = errs[i]
arr.AppendObject(elem)
elem.error = nil
_errArrayElemPool.Put(elem)
}
return nil
}
type errArrayElem struct {
error
}
func (e *errArrayElem) MarshalLogObject(enc zapcore.ObjectEncoder) error {
// Re-use the error field's logic, which supports non-standard error types.
Error(e.error).AddTo(enc)
return nil
}

549
vendor/go.uber.org/zap/field.go сгенерированный поставляемый
Просмотреть файл

@@ -1,549 +0,0 @@
// 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 zap
import (
"fmt"
"math"
"time"
"go.uber.org/zap/zapcore"
)
// Field is an alias for Field. Aliasing this type dramatically
// improves the navigability of this package's API documentation.
type Field = zapcore.Field
var (
_minTimeInt64 = time.Unix(0, math.MinInt64)
_maxTimeInt64 = time.Unix(0, math.MaxInt64)
)
// Skip constructs a no-op field, which is often useful when handling invalid
// inputs in other Field constructors.
func Skip() Field {
return Field{Type: zapcore.SkipType}
}
// nilField returns a field which will marshal explicitly as nil. See motivation
// in https://github.com/uber-go/zap/issues/753 . If we ever make breaking
// changes and add zapcore.NilType and zapcore.ObjectEncoder.AddNil, the
// implementation here should be changed to reflect that.
func nilField(key string) Field { return Reflect(key, nil) }
// Binary constructs a field that carries an opaque binary blob.
//
// Binary data is serialized in an encoding-appropriate format. For example,
// zap's JSON encoder base64-encodes binary blobs. To log UTF-8 encoded text,
// use ByteString.
func Binary(key string, val []byte) Field {
return Field{Key: key, Type: zapcore.BinaryType, Interface: val}
}
// Bool constructs a field that carries a bool.
func Bool(key string, val bool) Field {
var ival int64
if val {
ival = 1
}
return Field{Key: key, Type: zapcore.BoolType, Integer: ival}
}
// Boolp constructs a field that carries a *bool. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Boolp(key string, val *bool) Field {
if val == nil {
return nilField(key)
}
return Bool(key, *val)
}
// ByteString constructs a field that carries UTF-8 encoded text as a []byte.
// To log opaque binary blobs (which aren't necessarily valid UTF-8), use
// Binary.
func ByteString(key string, val []byte) Field {
return Field{Key: key, Type: zapcore.ByteStringType, Interface: val}
}
// Complex128 constructs a field that carries a complex number. Unlike most
// numeric fields, this costs an allocation (to convert the complex128 to
// interface{}).
func Complex128(key string, val complex128) Field {
return Field{Key: key, Type: zapcore.Complex128Type, Interface: val}
}
// Complex128p constructs a field that carries a *complex128. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Complex128p(key string, val *complex128) Field {
if val == nil {
return nilField(key)
}
return Complex128(key, *val)
}
// Complex64 constructs a field that carries a complex number. Unlike most
// numeric fields, this costs an allocation (to convert the complex64 to
// interface{}).
func Complex64(key string, val complex64) Field {
return Field{Key: key, Type: zapcore.Complex64Type, Interface: val}
}
// Complex64p constructs a field that carries a *complex64. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Complex64p(key string, val *complex64) Field {
if val == nil {
return nilField(key)
}
return Complex64(key, *val)
}
// Float64 constructs a field that carries a float64. The way the
// floating-point value is represented is encoder-dependent, so marshaling is
// necessarily lazy.
func Float64(key string, val float64) Field {
return Field{Key: key, Type: zapcore.Float64Type, Integer: int64(math.Float64bits(val))}
}
// Float64p constructs a field that carries a *float64. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Float64p(key string, val *float64) Field {
if val == nil {
return nilField(key)
}
return Float64(key, *val)
}
// Float32 constructs a field that carries a float32. The way the
// floating-point value is represented is encoder-dependent, so marshaling is
// necessarily lazy.
func Float32(key string, val float32) Field {
return Field{Key: key, Type: zapcore.Float32Type, Integer: int64(math.Float32bits(val))}
}
// Float32p constructs a field that carries a *float32. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Float32p(key string, val *float32) Field {
if val == nil {
return nilField(key)
}
return Float32(key, *val)
}
// Int constructs a field with the given key and value.
func Int(key string, val int) Field {
return Int64(key, int64(val))
}
// Intp constructs a field that carries a *int. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Intp(key string, val *int) Field {
if val == nil {
return nilField(key)
}
return Int(key, *val)
}
// Int64 constructs a field with the given key and value.
func Int64(key string, val int64) Field {
return Field{Key: key, Type: zapcore.Int64Type, Integer: val}
}
// Int64p constructs a field that carries a *int64. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Int64p(key string, val *int64) Field {
if val == nil {
return nilField(key)
}
return Int64(key, *val)
}
// Int32 constructs a field with the given key and value.
func Int32(key string, val int32) Field {
return Field{Key: key, Type: zapcore.Int32Type, Integer: int64(val)}
}
// Int32p constructs a field that carries a *int32. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Int32p(key string, val *int32) Field {
if val == nil {
return nilField(key)
}
return Int32(key, *val)
}
// Int16 constructs a field with the given key and value.
func Int16(key string, val int16) Field {
return Field{Key: key, Type: zapcore.Int16Type, Integer: int64(val)}
}
// Int16p constructs a field that carries a *int16. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Int16p(key string, val *int16) Field {
if val == nil {
return nilField(key)
}
return Int16(key, *val)
}
// Int8 constructs a field with the given key and value.
func Int8(key string, val int8) Field {
return Field{Key: key, Type: zapcore.Int8Type, Integer: int64(val)}
}
// Int8p constructs a field that carries a *int8. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Int8p(key string, val *int8) Field {
if val == nil {
return nilField(key)
}
return Int8(key, *val)
}
// String constructs a field with the given key and value.
func String(key string, val string) Field {
return Field{Key: key, Type: zapcore.StringType, String: val}
}
// Stringp constructs a field that carries a *string. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Stringp(key string, val *string) Field {
if val == nil {
return nilField(key)
}
return String(key, *val)
}
// Uint constructs a field with the given key and value.
func Uint(key string, val uint) Field {
return Uint64(key, uint64(val))
}
// Uintp constructs a field that carries a *uint. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Uintp(key string, val *uint) Field {
if val == nil {
return nilField(key)
}
return Uint(key, *val)
}
// Uint64 constructs a field with the given key and value.
func Uint64(key string, val uint64) Field {
return Field{Key: key, Type: zapcore.Uint64Type, Integer: int64(val)}
}
// Uint64p constructs a field that carries a *uint64. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Uint64p(key string, val *uint64) Field {
if val == nil {
return nilField(key)
}
return Uint64(key, *val)
}
// Uint32 constructs a field with the given key and value.
func Uint32(key string, val uint32) Field {
return Field{Key: key, Type: zapcore.Uint32Type, Integer: int64(val)}
}
// Uint32p constructs a field that carries a *uint32. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Uint32p(key string, val *uint32) Field {
if val == nil {
return nilField(key)
}
return Uint32(key, *val)
}
// Uint16 constructs a field with the given key and value.
func Uint16(key string, val uint16) Field {
return Field{Key: key, Type: zapcore.Uint16Type, Integer: int64(val)}
}
// Uint16p constructs a field that carries a *uint16. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Uint16p(key string, val *uint16) Field {
if val == nil {
return nilField(key)
}
return Uint16(key, *val)
}
// Uint8 constructs a field with the given key and value.
func Uint8(key string, val uint8) Field {
return Field{Key: key, Type: zapcore.Uint8Type, Integer: int64(val)}
}
// Uint8p constructs a field that carries a *uint8. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Uint8p(key string, val *uint8) Field {
if val == nil {
return nilField(key)
}
return Uint8(key, *val)
}
// Uintptr constructs a field with the given key and value.
func Uintptr(key string, val uintptr) Field {
return Field{Key: key, Type: zapcore.UintptrType, Integer: int64(val)}
}
// Uintptrp constructs a field that carries a *uintptr. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Uintptrp(key string, val *uintptr) Field {
if val == nil {
return nilField(key)
}
return Uintptr(key, *val)
}
// Reflect constructs a field with the given key and an arbitrary object. It uses
// an encoding-appropriate, reflection-based function to lazily serialize nearly
// any object into the logging context, but it's relatively slow and
// allocation-heavy. Outside tests, Any is always a better choice.
//
// If encoding fails (e.g., trying to serialize a map[int]string to JSON), Reflect
// includes the error message in the final log output.
func Reflect(key string, val interface{}) Field {
return Field{Key: key, Type: zapcore.ReflectType, Interface: val}
}
// Namespace creates a named, isolated scope within the logger's context. All
// subsequent fields will be added to the new namespace.
//
// This helps prevent key collisions when injecting loggers into sub-components
// or third-party libraries.
func Namespace(key string) Field {
return Field{Key: key, Type: zapcore.NamespaceType}
}
// Stringer constructs a field with the given key and the output of the value's
// String method. The Stringer's String method is called lazily.
func Stringer(key string, val fmt.Stringer) Field {
return Field{Key: key, Type: zapcore.StringerType, Interface: val}
}
// Time constructs a Field with the given key and value. The encoder
// controls how the time is serialized.
func Time(key string, val time.Time) Field {
if val.Before(_minTimeInt64) || val.After(_maxTimeInt64) {
return Field{Key: key, Type: zapcore.TimeFullType, Interface: val}
}
return Field{Key: key, Type: zapcore.TimeType, Integer: val.UnixNano(), Interface: val.Location()}
}
// Timep constructs a field that carries a *time.Time. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Timep(key string, val *time.Time) Field {
if val == nil {
return nilField(key)
}
return Time(key, *val)
}
// Stack constructs a field that stores a stacktrace of the current goroutine
// under provided key. Keep in mind that taking a stacktrace is eager and
// expensive (relatively speaking); this function both makes an allocation and
// takes about two microseconds.
func Stack(key string) Field {
return StackSkip(key, 1) // skip Stack
}
// StackSkip constructs a field similarly to Stack, but also skips the given
// number of frames from the top of the stacktrace.
func StackSkip(key string, skip int) Field {
// Returning the stacktrace as a string costs an allocation, but saves us
// from expanding the zapcore.Field union struct to include a byte slice. Since
// taking a stacktrace is already so expensive (~10us), the extra allocation
// is okay.
return String(key, takeStacktrace(skip+1)) // skip StackSkip
}
// Duration constructs a field with the given key and value. The encoder
// controls how the duration is serialized.
func Duration(key string, val time.Duration) Field {
return Field{Key: key, Type: zapcore.DurationType, Integer: int64(val)}
}
// Durationp constructs a field that carries a *time.Duration. The returned Field will safely
// and explicitly represent `nil` when appropriate.
func Durationp(key string, val *time.Duration) Field {
if val == nil {
return nilField(key)
}
return Duration(key, *val)
}
// Object constructs a field with the given key and ObjectMarshaler. It
// provides a flexible, but still type-safe and efficient, way to add map- or
// struct-like user-defined types to the logging context. The struct's
// MarshalLogObject method is called lazily.
func Object(key string, val zapcore.ObjectMarshaler) Field {
return Field{Key: key, Type: zapcore.ObjectMarshalerType, Interface: val}
}
// Inline constructs a Field that is similar to Object, but it
// will add the elements of the provided ObjectMarshaler to the
// current namespace.
func Inline(val zapcore.ObjectMarshaler) Field {
return zapcore.Field{
Type: zapcore.InlineMarshalerType,
Interface: val,
}
}
// Any takes a key and an arbitrary value and chooses the best way to represent
// them as a field, falling back to a reflection-based approach only if
// necessary.
//
// Since byte/uint8 and rune/int32 are aliases, Any can't differentiate between
// them. To minimize surprises, []byte values are treated as binary blobs, byte
// values are treated as uint8, and runes are always treated as integers.
func Any(key string, value interface{}) Field {
switch val := value.(type) {
case zapcore.ObjectMarshaler:
return Object(key, val)
case zapcore.ArrayMarshaler:
return Array(key, val)
case bool:
return Bool(key, val)
case *bool:
return Boolp(key, val)
case []bool:
return Bools(key, val)
case complex128:
return Complex128(key, val)
case *complex128:
return Complex128p(key, val)
case []complex128:
return Complex128s(key, val)
case complex64:
return Complex64(key, val)
case *complex64:
return Complex64p(key, val)
case []complex64:
return Complex64s(key, val)
case float64:
return Float64(key, val)
case *float64:
return Float64p(key, val)
case []float64:
return Float64s(key, val)
case float32:
return Float32(key, val)
case *float32:
return Float32p(key, val)
case []float32:
return Float32s(key, val)
case int:
return Int(key, val)
case *int:
return Intp(key, val)
case []int:
return Ints(key, val)
case int64:
return Int64(key, val)
case *int64:
return Int64p(key, val)
case []int64:
return Int64s(key, val)
case int32:
return Int32(key, val)
case *int32:
return Int32p(key, val)
case []int32:
return Int32s(key, val)
case int16:
return Int16(key, val)
case *int16:
return Int16p(key, val)
case []int16:
return Int16s(key, val)
case int8:
return Int8(key, val)
case *int8:
return Int8p(key, val)
case []int8:
return Int8s(key, val)
case string:
return String(key, val)
case *string:
return Stringp(key, val)
case []string:
return Strings(key, val)
case uint:
return Uint(key, val)
case *uint:
return Uintp(key, val)
case []uint:
return Uints(key, val)
case uint64:
return Uint64(key, val)
case *uint64:
return Uint64p(key, val)
case []uint64:
return Uint64s(key, val)
case uint32:
return Uint32(key, val)
case *uint32:
return Uint32p(key, val)
case []uint32:
return Uint32s(key, val)
case uint16:
return Uint16(key, val)
case *uint16:
return Uint16p(key, val)
case []uint16:
return Uint16s(key, val)
case uint8:
return Uint8(key, val)
case *uint8:
return Uint8p(key, val)
case []byte:
return Binary(key, val)
case uintptr:
return Uintptr(key, val)
case *uintptr:
return Uintptrp(key, val)
case []uintptr:
return Uintptrs(key, val)
case time.Time:
return Time(key, val)
case *time.Time:
return Timep(key, val)
case []time.Time:
return Times(key, val)
case time.Duration:
return Duration(key, val)
case *time.Duration:
return Durationp(key, val)
case []time.Duration:
return Durations(key, val)
case error:
return NamedError(key, val)
case []error:
return Errors(key, val)
case fmt.Stringer:
return Stringer(key, val)
default:
return Reflect(key, val)
}
}

39
vendor/go.uber.org/zap/flag.go сгенерированный поставляемый
Просмотреть файл

@@ -1,39 +0,0 @@
// 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 zap
import (
"flag"
"go.uber.org/zap/zapcore"
)
// LevelFlag uses the standard library's flag.Var to declare a global flag
// with the specified name, default, and usage guidance. The returned value is
// a pointer to the value of the flag.
//
// If you don't want to use the flag package's global state, you can use any
// non-nil *Level as a flag.Value with your own *flag.FlagSet.
func LevelFlag(name string, defaultLevel zapcore.Level, usage string) *zapcore.Level {
lvl := defaultLevel
flag.Var(&lvl, name, usage)
return &lvl
}

34
vendor/go.uber.org/zap/glide.yaml сгенерированный поставляемый
Просмотреть файл

@@ -1,34 +0,0 @@
package: go.uber.org/zap
license: MIT
import:
- package: go.uber.org/atomic
version: ^1
- package: go.uber.org/multierr
version: ^1
testImport:
- package: github.com/satori/go.uuid
- package: github.com/sirupsen/logrus
- package: github.com/apex/log
subpackages:
- handlers/json
- package: github.com/go-kit/kit
subpackages:
- log
- package: github.com/stretchr/testify
subpackages:
- assert
- require
- package: gopkg.in/inconshreveable/log15.v2
- package: github.com/mattn/goveralls
- package: github.com/pborman/uuid
- package: github.com/pkg/errors
- package: github.com/rs/zerolog
- package: golang.org/x/tools
subpackages:
- cover
- package: golang.org/x/lint
subpackages:
- golint
- package: github.com/axw/gocov
subpackages:
- gocov

168
vendor/go.uber.org/zap/global.go сгенерированный поставляемый
Просмотреть файл

@@ -1,168 +0,0 @@
// 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 zap
import (
"bytes"
"fmt"
"log"
"os"
"sync"
"go.uber.org/zap/zapcore"
)
const (
_loggerWriterDepth = 2
_programmerErrorTemplate = "You've found a bug in zap! Please file a bug at " +
"https://github.com/uber-go/zap/issues/new and reference this error: %v"
)
var (
_globalMu sync.RWMutex
_globalL = NewNop()
_globalS = _globalL.Sugar()
)
// L returns the global Logger, which can be reconfigured with ReplaceGlobals.
// It's safe for concurrent use.
func L() *Logger {
_globalMu.RLock()
l := _globalL
_globalMu.RUnlock()
return l
}
// S returns the global SugaredLogger, which can be reconfigured with
// ReplaceGlobals. It's safe for concurrent use.
func S() *SugaredLogger {
_globalMu.RLock()
s := _globalS
_globalMu.RUnlock()
return s
}
// ReplaceGlobals replaces the global Logger and SugaredLogger, and returns a
// function to restore the original values. It's safe for concurrent use.
func ReplaceGlobals(logger *Logger) func() {
_globalMu.Lock()
prev := _globalL
_globalL = logger
_globalS = logger.Sugar()
_globalMu.Unlock()
return func() { ReplaceGlobals(prev) }
}
// NewStdLog returns a *log.Logger which writes to the supplied zap Logger at
// InfoLevel. To redirect the standard library's package-global logging
// functions, use RedirectStdLog instead.
func NewStdLog(l *Logger) *log.Logger {
logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
f := logger.Info
return log.New(&loggerWriter{f}, "" /* prefix */, 0 /* flags */)
}
// NewStdLogAt returns *log.Logger which writes to supplied zap logger at
// required level.
func NewStdLogAt(l *Logger, level zapcore.Level) (*log.Logger, error) {
logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
logFunc, err := levelToFunc(logger, level)
if err != nil {
return nil, err
}
return log.New(&loggerWriter{logFunc}, "" /* prefix */, 0 /* flags */), nil
}
// RedirectStdLog redirects output from the standard library's package-global
// logger to the supplied logger at InfoLevel. Since zap already handles caller
// annotations, timestamps, etc., it automatically disables the standard
// library's annotations and prefixing.
//
// It returns a function to restore the original prefix and flags and reset the
// standard library's output to os.Stderr.
func RedirectStdLog(l *Logger) func() {
f, err := redirectStdLogAt(l, InfoLevel)
if err != nil {
// Can't get here, since passing InfoLevel to redirectStdLogAt always
// works.
panic(fmt.Sprintf(_programmerErrorTemplate, err))
}
return f
}
// RedirectStdLogAt redirects output from the standard library's package-global
// logger to the supplied logger at the specified level. Since zap already
// handles caller annotations, timestamps, etc., it automatically disables the
// standard library's annotations and prefixing.
//
// It returns a function to restore the original prefix and flags and reset the
// standard library's output to os.Stderr.
func RedirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
return redirectStdLogAt(l, level)
}
func redirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
flags := log.Flags()
prefix := log.Prefix()
log.SetFlags(0)
log.SetPrefix("")
logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
logFunc, err := levelToFunc(logger, level)
if err != nil {
return nil, err
}
log.SetOutput(&loggerWriter{logFunc})
return func() {
log.SetFlags(flags)
log.SetPrefix(prefix)
log.SetOutput(os.Stderr)
}, nil
}
func levelToFunc(logger *Logger, lvl zapcore.Level) (func(string, ...Field), error) {
switch lvl {
case DebugLevel:
return logger.Debug, nil
case InfoLevel:
return logger.Info, nil
case WarnLevel:
return logger.Warn, nil
case ErrorLevel:
return logger.Error, nil
case DPanicLevel:
return logger.DPanic, nil
case PanicLevel:
return logger.Panic, nil
case FatalLevel:
return logger.Fatal, nil
}
return nil, fmt.Errorf("unrecognized level: %q", lvl)
}
type loggerWriter struct {
logFunc func(msg string, fields ...Field)
}
func (l *loggerWriter) Write(p []byte) (int, error) {
p = bytes.TrimSpace(p)
l.logFunc(string(p))
return len(p), nil
}

26
vendor/go.uber.org/zap/global_go112.go сгенерированный поставляемый
Просмотреть файл

@@ -1,26 +0,0 @@
// Copyright (c) 2019 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.
// See #682 for more information.
// +build go1.12
package zap
const _stdLogDefaultDepth = 1

26
vendor/go.uber.org/zap/global_prego112.go сгенерированный поставляемый
Просмотреть файл

@@ -1,26 +0,0 @@
// Copyright (c) 2019 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.
// See #682 for more information.
// +build !go1.12
package zap
const _stdLogDefaultDepth = 2

12
vendor/go.uber.org/zap/go.mod сгенерированный поставляемый
Просмотреть файл

@@ -1,12 +0,0 @@
module go.uber.org/zap
go 1.13
require (
github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.7.0
go.uber.org/atomic v1.7.0
go.uber.org/multierr v1.6.0
gopkg.in/yaml.v2 v2.2.8
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше