vendor: update all dependencies to latest versions

This commit is contained in:
Nick Craig-Wood 2018-01-16 13:20:59 +00:00
parent 8e83fb6fb9
commit 7d3a17725d
4878 changed files with 1974229 additions and 201215 deletions

460
vendor/github.com/pengsrc/go-shared/log/event.go generated vendored Normal file
View file

@ -0,0 +1,460 @@
package log
import (
"context"
"fmt"
"os"
"runtime"
"strconv"
"strings"
"sync"
"time"
"github.com/pengsrc/go-shared/buffer"
"github.com/pengsrc/go-shared/convert"
)
// A EventCallerPool is a type-safe wrapper around a sync.BytesBufferPool.
type EventCallerPool struct {
p *sync.Pool
}
// NewEventCallerPool constructs a new BytesBufferPool.
func NewEventCallerPool() EventCallerPool {
return EventCallerPool{
p: &sync.Pool{
New: func() interface{} {
return &EventCaller{}
},
},
}
}
// Get retrieves a EventCaller from the pool, creating one if necessary.
func (p EventCallerPool) Get() *EventCaller {
e := p.p.Get().(*EventCaller)
e.pool = p
e.Defined = false
e.PC = 0
e.File = ""
e.Line = 0
return e
}
func (p EventCallerPool) put(caller *EventCaller) {
p.p.Put(caller)
}
// EventCaller represents the caller of a logging function.
type EventCaller struct {
pool EventCallerPool
Defined bool
PC uintptr
File string
Line int
}
// Free returns the EventCaller to its EventCallerPool.
// Callers must not retain references to the EventCaller after calling Free.
func (ec *EventCaller) Free() {
ec.pool.put(ec)
}
// String returns the full path and line number of the caller.
func (ec EventCaller) String() string {
return ec.FullPath()
}
// FullPath returns a /full/path/to/package/file:line description of the
// caller.
func (ec EventCaller) FullPath() string {
if !ec.Defined {
return "undefined"
}
buf := buffer.GlobalBytesPool().Get()
defer buf.Free()
buf.AppendString(ec.File)
buf.AppendByte(':')
buf.AppendInt(int64(ec.Line))
return buf.String()
}
// TrimmedPath returns a package/file:line description of the caller,
// preserving only the leaf directory name and file name.
func (ec EventCaller) TrimmedPath() string {
if !ec.Defined {
return "undefined"
}
// nb. To make sure we trim the path correctly on Windows too, we
// counter-intuitively need to use '/' and *not* os.PathSeparator here,
// because the path given originates from Go stdlib, specifically
// runtime.Caller() which (as of Mar/17) returns forward slashes even on
// Windows.
//
// See https://github.com/golang/go/issues/3335
// and https://github.com/golang/go/issues/18151
//
// for discussion on the issue on Go side.
//
// Find the last separator.
//
idx := strings.LastIndexByte(ec.File, '/')
if idx == -1 {
return ec.FullPath()
}
// Find the penultimate separator.
idx = strings.LastIndexByte(ec.File[:idx], '/')
if idx == -1 {
return ec.FullPath()
}
buf := buffer.GlobalBytesPool().Get()
defer buf.Free()
// Keep everything after the penultimate separator.
buf.AppendString(ec.File[idx+1:])
buf.AppendByte(':')
buf.AppendInt(int64(ec.Line))
return buf.String()
}
// A EventPool is a type-safe wrapper around a sync.BytesBufferPool.
type EventPool struct {
p *sync.Pool
}
// NewEventPool constructs a new BytesBufferPool.
func NewEventPool() EventPool {
return EventPool{
p: &sync.Pool{
New: func() interface{} {
return &Event{}
},
},
}
}
// Get retrieves a Event from the pool, creating one if necessary.
func (p EventPool) Get() *Event {
e := p.p.Get().(*Event)
e.buffer = buffer.GlobalBytesPool().Get()
e.pool = p
e.level = MuteLevel
e.lw = nil
e.ctx = nil
e.ctxKeys = nil
e.isEnabled = false
e.isCallerEnabled = false
return e
}
func (p EventPool) put(event *Event) {
event.buffer.Free()
event.ctx = nil
event.ctxKeys = nil
p.p.Put(event)
}
// Event represents a log event. It is instanced by one of the with method of
// logger and finalized by the log method such as Debug().
type Event struct {
buffer *buffer.BytesBuffer
pool EventPool
level Level
lw LevelWriter
ctx context.Context
ctxKeys *[]interface{}
ctxKeysMap *map[interface{}]string
isEnabled bool
isCallerEnabled bool
}
// Free returns the Event to its EventPool.
// Callers must not retain references to the Event after calling Free.
func (e *Event) Free() {
e.pool.put(e)
}
// Message writes the *Event to level writer.
//
// NOTICE: Once this method is called, the *Event should be disposed.
// Calling twice can have unexpected result.
func (e *Event) Message(message string) {
if !e.isEnabled {
return
}
e.write(message)
}
// Messagef writes the *Event to level writer.
//
// NOTICE: Once this method is called, the *Event should be disposed.
// Calling twice can have unexpected result.
func (e *Event) Messagef(format string, v ...interface{}) {
if !e.isEnabled {
return
}
e.write(format, v...)
}
// Byte appends string key and byte value to event.
func (e *Event) Byte(key string, value byte) *Event {
return e.appendField(key, func() { e.buffer.AppendByte(value) })
}
// Bytes appends string key and bytes value to event.
func (e *Event) Bytes(key string, value []byte) *Event {
return e.appendField(key, func() {
if needsQuote(string(value)) {
e.buffer.AppendString(strconv.Quote(string(value)))
} else {
e.buffer.AppendBytes(value)
}
})
}
// String appends string key and string value to event.
func (e *Event) String(key string, value string) *Event {
return e.appendField(key, func() {
if needsQuote(string(value)) {
e.buffer.AppendString(strconv.Quote(value))
} else {
e.buffer.AppendString(value)
}
})
}
// Int appends string key and int value to event.
func (e *Event) Int(key string, value int) *Event {
return e.appendField(key, func() { e.buffer.AppendInt(int64(value)) })
}
// Int32 appends string key and int32 value to event.
func (e *Event) Int32(key string, value int32) *Event {
return e.appendField(key, func() { e.buffer.AppendInt(int64(value)) })
}
// Int64 appends string key and int64 value to event.
func (e *Event) Int64(key string, value int64) *Event {
return e.appendField(key, func() { e.buffer.AppendInt(value) })
}
// Uint appends string key and uint value to event.
func (e *Event) Uint(key string, value uint) *Event {
return e.appendField(key, func() { e.buffer.AppendUint(uint64(value)) })
}
// Uint32 appends string key and uint32 value to event.
func (e *Event) Uint32(key string, value uint32) *Event {
return e.appendField(key, func() { e.buffer.AppendUint(uint64(value)) })
}
// Uint64 appends string key and uint64 value to event.
func (e *Event) Uint64(key string, value uint64) *Event {
return e.appendField(key, func() { e.buffer.AppendUint(value) })
}
// Float32 appends string key and float32 value to event.
func (e *Event) Float32(key string, value float32) *Event {
return e.appendField(key, func() { e.buffer.AppendFloat(float64(value), 32) })
}
// Float64 appends string key and float value to event.
func (e *Event) Float64(key string, value float64) *Event {
return e.appendField(key, func() { e.buffer.AppendFloat(value, 64) })
}
// Bool appends string key and bool value to event.
func (e *Event) Bool(key string, value bool) *Event {
return e.appendField(key, func() { e.buffer.AppendBool(value) })
}
// Time appends string key and time value to event.
func (e *Event) Time(key string, value time.Time, format string) *Event {
buf := buffer.GlobalBytesPool().Get()
defer buf.Free()
buf.AppendTime(value, format)
return e.Bytes(key, buf.Bytes())
}
// Error appends string key and error value to event.
func (e *Event) Error(key string, err error) *Event {
return e.String(key, err.Error())
}
// Interface appends string key and interface value to event.
func (e *Event) Interface(key string, value interface{}) *Event {
switch v := value.(type) {
case byte:
e.Byte(key, v)
case []byte:
e.Bytes(key, v)
case string:
e.String(key, v)
case int:
e.Int(key, v)
case int32:
e.Int32(key, v)
case int64:
e.Int64(key, v)
case uint:
e.Uint(key, v)
case uint32:
e.Uint32(key, v)
case uint64:
e.Uint64(key, v)
case float32:
e.Float32(key, v)
case float64:
e.Float64(key, v)
case bool:
e.Bool(key, v)
case time.Time:
e.Time(key, v, convert.ISO8601Milli)
case error:
e.Error(key, v)
case nil:
e.String(key, "nil")
default:
panic(fmt.Sprintf("unknown field type: %v", value))
}
return e
}
func (e *Event) appendField(key string, appendFunc func()) *Event {
if !e.isEnabled {
return e
}
// Ignore field with empty key.
if len(key) <= 0 {
return e
}
// Append space if event field not empty.
if e.buffer.Len() != 0 {
e.buffer.AppendByte(' ')
}
e.buffer.AppendString(key)
e.buffer.AppendString("=")
appendFunc()
return e
}
func (e *Event) write(format string, v ...interface{}) {
defer e.Free()
if !e.isEnabled {
return
}
// Append interested contexts.
if e.ctx != nil && e.ctxKeys != nil && e.ctxKeysMap != nil {
for _, key := range *e.ctxKeys {
if value := e.ctx.Value(key); value != nil {
e.Interface((*e.ctxKeysMap)[key], e.ctx.Value(key))
}
}
}
// Append caller.
if e.isCallerEnabled {
ec := newEventCaller(runtime.Caller(callerSkipOffset))
e.String("source", ec.TrimmedPath())
}
// Compose and store current log.
buf := buffer.GlobalBytesPool().Get()
defer buf.Free()
// Format print message.
if format != "" {
if len(v) == 0 {
fmt.Fprint(buf, format)
} else {
fmt.Fprintf(buf, format, v...)
}
} else {
fmt.Fprint(buf, v...)
}
// Append filed.
buf.AppendByte(' ')
buf.AppendBytes(e.buffer.Bytes())
// Finally write.
if _, err := e.lw.WriteLevel(e.level, buf.Bytes()); err != nil {
fmt.Fprintf(os.Stderr, "log: could not write event: %v", err)
}
switch e.level {
case PanicLevel:
panic(buf.String())
case FatalLevel:
os.Exit(1)
}
}
func newEventCaller(pc uintptr, file string, line int, ok bool) (ec *EventCaller) {
ec = eventCallerPool.Get()
if ok {
ec.PC = pc
ec.File = file
ec.Line = line
ec.Defined = true
}
return
}
func newEvent(
ctx context.Context,
ctxKeys *[]interface{}, ctxKeysMap *map[interface{}]string,
level Level, lw LevelWriter,
isEnabled bool, isCallerEnabled bool,
) (e *Event) {
e = eventPool.Get()
e.level = level
e.lw = lw
e.ctx = ctx
e.ctxKeys = ctxKeys
e.ctxKeysMap = ctxKeysMap
e.isEnabled = isEnabled
e.isCallerEnabled = isCallerEnabled
return
}
func needsQuote(s string) bool {
for i := range s {
if s[i] < 0x20 || s[i] > 0x7e || s[i] == ' ' || s[i] == '\\' || s[i] == '"' {
return true
}
}
return false
}
const callerSkipOffset = 2
// eventCallerPool is a pool of newEvent callers.
var eventCallerPool = NewEventCallerPool()
// eventPool is a pool of events.
var eventPool = NewEventPool()

145
vendor/github.com/pengsrc/go-shared/log/event_test.go generated vendored Normal file
View file

@ -0,0 +1,145 @@
package log
import (
"context"
"errors"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/pengsrc/go-shared/buffer"
"github.com/pengsrc/go-shared/convert"
)
func TestEventCallerPool(t *testing.T) {
p := NewEventCallerPool()
var wg sync.WaitGroup
for g := 0; g < 10; g++ {
wg.Add(1)
go func() {
for i := 0; i < 100; i++ {
eventCaller := p.Get()
assert.NotNil(t, eventCaller)
eventCaller.Free()
}
wg.Done()
}()
}
wg.Wait()
}
func TestEntryCaller(t *testing.T) {
tests := []struct {
caller *EventCaller
full string
short string
}{
{
caller: newEventCaller(100, "/path/to/foo.go", 42, false),
full: "undefined",
short: "undefined",
},
{
caller: newEventCaller(100, "/path/to/foo.go", 42, true),
full: "/path/to/foo.go:42",
short: "to/foo.go:42",
},
{
caller: newEventCaller(100, "to/foo.go", 42, true),
full: "to/foo.go:42",
short: "to/foo.go:42",
},
}
for _, tt := range tests {
assert.Equal(t, tt.full, tt.caller.String(), "Unexpected string from EntryCaller.")
assert.Equal(t, tt.full, tt.caller.FullPath(), "Unexpected FullPath from EntryCaller.")
assert.Equal(t, tt.short, tt.caller.TrimmedPath(), "Unexpected TrimmedPath from EntryCaller.")
}
}
func TestEventPool(t *testing.T) {
p := NewEventPool()
var wg sync.WaitGroup
for g := 0; g < 10; g++ {
wg.Add(1)
go func() {
for i := 0; i < 100; i++ {
event := p.Get()
assert.NotNil(t, event)
event.Free()
}
wg.Done()
}()
}
wg.Wait()
}
func TestEvent(t *testing.T) {
buf := buffer.GlobalBytesPool().Get()
defer buf.Free()
l, err := NewLogger(buf, "DEBUG")
assert.NoError(t, err)
l.DebugEvent(context.TODO()).Byte("b", 'b').Message("DEBUG b")
assert.Contains(t, buf.String(), "DEBUG b b=b")
t.Log(buf.String())
buf.Reset()
l.DebugEvent(context.TODO()).Bytes("bs", []byte("bs")).Message("DEBUG bs")
l.DebugEvent(context.TODO()).Bytes("bs", []byte("bs bs")).Messagef("DEBUG %s", "bs")
assert.Contains(t, buf.String(), "DEBUG bs bs=bs")
assert.Contains(t, buf.String(), `DEBUG bs bs="bs bs"`)
buf.Reset()
l.DebugEvent(context.TODO()).String("s", "s").Message("DEBUG s")
l.DebugEvent(context.TODO()).String("s", "s s").Messagef("DEBUG %d", 1024)
assert.Contains(t, buf.String(), "DEBUG s s=s")
assert.Contains(t, buf.String(), `DEBUG 1024 s="s s"`)
buf.Reset()
l.InfoEvent(context.TODO()).
Int("i", 1).Int32("i32", int32(2)).Int64("i64", int64(3)).
Messagef("INFO %d", 123)
assert.Contains(t, buf.String(), "INFO 123 i=1 i32=2 i64=3")
buf.Reset()
l.InfoEvent(context.TODO()).
Uint("i", 1).Uint32("i32", uint32(2)).Uint64("i64", uint64(3)).
Messagef("INFO %d", 123)
assert.Contains(t, buf.String(), "INFO 123 i=1 i32=2 i64=3")
buf.Reset()
l.WarnEvent(context.TODO()).
Float32("f32", float32(32.2333)).Float64("f64", float64(64.6444)).
Messagef("WARN %s %d.", "hello", 1024)
assert.Contains(t, buf.String(), "WARN hello 1024. f32=32.2333 f64=64.6444")
buf.Reset()
l.WarnEvent(context.TODO()).
Bool("true", true).Bool("false", false).
Message("WARN bool.")
assert.Contains(t, buf.String(), "WARN bool. true=true false=false")
buf.Reset()
l.ErrorEvent(context.TODO()).
Time("time", time.Time{}, convert.RFC822).Error("error", errors.New("error message")).
Message("Error.")
assert.Contains(t, buf.String(), `Error. time="Mon, 01 Jan 0001 00:00:00 GMT" error="error message"`)
buf.Reset()
l.DebugEvent(context.TODO()).
String("a", "a a").
String("b", "b'b").
String("c", `c"c`).
Message("yes")
assert.Contains(t, buf.String(), `a="a a"`)
assert.Contains(t, buf.String(), `b=b'b`)
assert.Contains(t, buf.String(), `c="c\"c"`)
buf.Reset()
}

151
vendor/github.com/pengsrc/go-shared/log/exported.go generated vendored Normal file
View file

@ -0,0 +1,151 @@
package log
import (
"context"
)
// Fatal logs a message with severity FATAL followed by a call to os.Exit(1).
func Fatal(ctx context.Context, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, FatalLevel).write("", v...)
}
}
// Panic logs a message with severity PANIC followed by a call to panic().
func Panic(ctx context.Context, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, PanicLevel).write("", v...)
}
}
// Error logs a message with severity ERROR.
func Error(ctx context.Context, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, ErrorLevel).write("", v...)
}
}
// Warn logs a message with severity WARN.
func Warn(ctx context.Context, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, WarnLevel).write("", v...)
}
}
// Info logs a message with severity INFO.
func Info(ctx context.Context, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, InfoLevel).write("", v...)
}
}
// Debug logs a message with severity DEBUG.
func Debug(ctx context.Context, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, DebugLevel).write("", v...)
}
}
// Fatalf logs a message with severity FATAL in format followed by a call to
// os.Exit(1).
func Fatalf(ctx context.Context, format string, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, FatalLevel).write(format, v...)
}
}
// Panicf logs a message with severity PANIC in format followed by a call to
// panic().
func Panicf(ctx context.Context, format string, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, PanicLevel).write(format, v...)
}
}
// Errorf logs a message with severity ERROR in format.
func Errorf(ctx context.Context, format string, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, ErrorLevel).write(format, v...)
}
}
// Warnf logs a message with severity WARN in format.
func Warnf(ctx context.Context, format string, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, WarnLevel).write(format, v...)
}
}
// Infof logs a message with severity INFO in format.
func Infof(ctx context.Context, format string, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, InfoLevel).write(format, v...)
}
}
// Debugf logs a message with severity DEBUG in format.
func Debugf(ctx context.Context, format string, v ...interface{}) {
if globalLogger != nil {
globalLogger.event(ctx, DebugLevel).write(format, v...)
}
}
// FatalEvent returns a log event with severity FATAL.
func FatalEvent(ctx context.Context) *Event {
if globalLogger != nil {
return globalLogger.event(ctx, FatalLevel)
}
return nil
}
// PanicEvent returns a log event with severity PANIC.
func PanicEvent(ctx context.Context) *Event {
if globalLogger != nil {
return globalLogger.event(ctx, PanicLevel)
}
return nil
}
// ErrorEvent returns a log event with severity ERROR.
func ErrorEvent(ctx context.Context) *Event {
if globalLogger != nil {
return globalLogger.event(ctx, ErrorLevel)
}
return nil
}
// WarnEvent returns a log event with severity WARN.
func WarnEvent(ctx context.Context) *Event {
if globalLogger != nil {
return globalLogger.event(ctx, WarnLevel)
}
return nil
}
// InfoEvent returns a log event with severity INFO.
func InfoEvent(ctx context.Context) *Event {
if globalLogger != nil {
return globalLogger.event(ctx, InfoLevel)
}
return nil
}
// DebugEvent returns a log event with severity DEBUG.
func DebugEvent(ctx context.Context) *Event {
if globalLogger != nil {
return globalLogger.event(ctx, DebugLevel)
}
return nil
}
// SetGlobalLogger sets a logger as global logger.
func SetGlobalLogger(l *Logger) {
globalLogger = l
}
// GlobalLogger returns the global logger.
func GlobalLogger() *Logger {
return globalLogger
}
var globalLogger *Logger

View file

@ -0,0 +1,21 @@
package log
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
)
func TestExported(t *testing.T) {
l, err := NewTerminalLogger("DEBUG")
assert.NoError(t, err)
SetGlobalLogger(l)
c := context.Background()
l.Debug(c, "Singleton logger")
assert.NotNil(t, InfoEvent(context.Background()))
Debugf(c, "Debug message test, hi %s", "Apple")
}

67
vendor/github.com/pengsrc/go-shared/log/level.go generated vendored Normal file
View file

@ -0,0 +1,67 @@
package log
import (
"fmt"
"strings"
)
// Level defines log levels.
type Level uint8
// String returns name of the level.
func (l Level) String() string {
switch l {
case MuteLevel:
return "MUTE"
case FatalLevel:
return "FATAL"
case PanicLevel:
return "PANIC"
case ErrorLevel:
return "ERROR"
case WarnLevel:
return "WARN"
case InfoLevel:
return "INFO"
case DebugLevel:
return "DEBUG"
}
return ""
}
const (
// MuteLevel disables the logger.
MuteLevel Level = iota
// FatalLevel defines fatal log level.
FatalLevel
// PanicLevel defines panic log level.
PanicLevel
// ErrorLevel defines error log level.
ErrorLevel
// WarnLevel defines warn log level.
WarnLevel
// InfoLevel defines info log level.
InfoLevel
// DebugLevel defines debug log level.
DebugLevel
)
// ParseLevel takes a string level and returns the log level constant.
func ParseLevel(level string) (Level, error) {
switch strings.ToUpper(level) {
case "FATAL":
return FatalLevel, nil
case "PANIC":
return PanicLevel, nil
case "ERROR":
return ErrorLevel, nil
case "WARN":
return WarnLevel, nil
case "INFO":
return InfoLevel, nil
case "DEBUG":
return DebugLevel, nil
}
return MuteLevel, fmt.Errorf(`"%q" is not a valid log Level`, level)
}

45
vendor/github.com/pengsrc/go-shared/log/level_test.go generated vendored Normal file
View file

@ -0,0 +1,45 @@
package log
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseLevel(t *testing.T) {
var l Level
var err error
assert.Equal(t, l, MuteLevel)
assert.NoError(t, err)
l, err = ParseLevel("FATAL")
assert.Equal(t, l, FatalLevel)
assert.NoError(t, err)
l, err = ParseLevel("PANIC")
assert.Equal(t, l, PanicLevel)
assert.NoError(t, err)
l, err = ParseLevel("ERROR")
assert.Equal(t, l, ErrorLevel)
assert.NoError(t, err)
l, err = ParseLevel("WARN")
assert.Equal(t, l, WarnLevel)
assert.NoError(t, err)
l, err = ParseLevel("INFO")
assert.Equal(t, l, InfoLevel)
assert.NoError(t, err)
l, err = ParseLevel("DEBUG")
assert.Equal(t, l, DebugLevel)
assert.NoError(t, err)
l, err = ParseLevel("invalid")
assert.Error(t, err)
}
func TestLevelString(t *testing.T) {
assert.Equal(t, "FATAL", FatalLevel.String())
assert.Equal(t, "PANIC", PanicLevel.String())
assert.Equal(t, "ERROR", ErrorLevel.String())
assert.Equal(t, "WARN", WarnLevel.String())
assert.Equal(t, "INFO", InfoLevel.String())
assert.Equal(t, "DEBUG", DebugLevel.String())
}

327
vendor/github.com/pengsrc/go-shared/log/logger.go generated vendored Normal file
View file

@ -0,0 +1,327 @@
// Package log provides support for logging to stdout, stderr and file.
package log
import (
"bufio"
"context"
"errors"
"fmt"
"io"
"os"
"os/signal"
"path"
"syscall"
"time"
"github.com/pengsrc/go-shared/check"
"github.com/pengsrc/go-shared/reopen"
)
// Logger presents a logger.
// The only way to initialize a logger is using the convention construct
// functions like NewLogger().
type Logger struct {
level Level
lw LevelWriter
// Interested context keys.
ctxKeys []interface{}
ctxKeysMap map[interface{}]string
// isCallerEnabled sets whether to annotating logs with the calling
// function's file name and line number. By default, all logs are annotated.
isCallerEnabled bool
}
// GetLevel get the log level string.
func (l *Logger) GetLevel() string {
return l.level.String()
}
// SetLevel sets the log level.
// Valid levels are "debug", "info", "warn", "error", and "fatal".
func (l *Logger) SetLevel(level string) (err error) {
levelFlag, err := ParseLevel(level)
if err == nil {
l.level = levelFlag
}
return err
}
// SetInterestContextKeys sets the contexts keys that the logger should be
// interested in. Value of the interested context key will extract and print as
// newEvent filed.
func (l *Logger) SetInterestContextKeys(keys []interface{}) {
l.ctxKeys = keys
l.ctxKeysMap = make(map[interface{}]string)
for _, key := range l.ctxKeys {
l.ctxKeysMap[key] = fmt.Sprintf("%v", key)
}
}
// SetCallerFlag sets whether to annotating logs with the caller.
func (l *Logger) SetCallerFlag(isEnabled bool) {
l.isCallerEnabled = isEnabled
}
// Flush writes buffered logs.
func (l *Logger) Flush() {
if flusher, ok := l.lw.(Flusher); ok {
flusher.Flush()
}
}
// Fatal logs a message with severity FATAL followed by a call to os.Exit(1).
func (l *Logger) Fatal(ctx context.Context, v ...interface{}) {
l.event(ctx, FatalLevel).write("", v...)
}
// Panic logs a message with severity PANIC followed by a call to panic().
func (l *Logger) Panic(ctx context.Context, v ...interface{}) {
l.event(ctx, PanicLevel).write("", v...)
}
// Error logs a message with severity ERROR.
func (l *Logger) Error(ctx context.Context, v ...interface{}) {
l.event(ctx, ErrorLevel).write("", v...)
}
// Warn logs a message with severity WARN.
func (l *Logger) Warn(ctx context.Context, v ...interface{}) {
l.event(ctx, WarnLevel).write("", v...)
}
// Info logs a message with severity INFO.
func (l *Logger) Info(ctx context.Context, v ...interface{}) {
l.event(ctx, InfoLevel).write("", v...)
}
// Debug logs a message with severity DEBUG.
func (l *Logger) Debug(ctx context.Context, v ...interface{}) {
l.event(ctx, DebugLevel).write("", v...)
}
// Fatalf logs a message with severity FATAL in format followed by a call to
// os.Exit(1).
func (l *Logger) Fatalf(ctx context.Context, format string, v ...interface{}) {
l.event(ctx, FatalLevel).write(format, v...)
}
// Panicf logs a message with severity PANIC in format followed by a call to
// panic().
func (l *Logger) Panicf(ctx context.Context, format string, v ...interface{}) {
l.event(ctx, PanicLevel).write(format, v...)
}
// Errorf logs a message with severity ERROR in format.
func (l *Logger) Errorf(ctx context.Context, format string, v ...interface{}) {
l.event(ctx, ErrorLevel).write(format, v...)
}
// Warnf logs a message with severity WARN in format.
func (l *Logger) Warnf(ctx context.Context, format string, v ...interface{}) {
l.event(ctx, WarnLevel).write(format, v...)
}
// Infof logs a message with severity INFO in format.
func (l *Logger) Infof(ctx context.Context, format string, v ...interface{}) {
l.event(ctx, InfoLevel).write(format, v...)
}
// Debugf logs a message with severity DEBUG in format.
func (l *Logger) Debugf(ctx context.Context, format string, v ...interface{}) {
l.event(ctx, DebugLevel).write(format, v...)
}
// FatalEvent returns a log event with severity FATAL.
func (l *Logger) FatalEvent(ctx context.Context) *Event {
return l.event(ctx, FatalLevel)
}
// PanicEvent returns a log event with severity PANIC.
func (l *Logger) PanicEvent(ctx context.Context) *Event {
return l.event(ctx, PanicLevel)
}
// ErrorEvent returns a log event with severity ERROR.
func (l *Logger) ErrorEvent(ctx context.Context) *Event {
return l.event(ctx, ErrorLevel)
}
// WarnEvent returns a log event with severity WARN.
func (l *Logger) WarnEvent(ctx context.Context) *Event {
return l.event(ctx, WarnLevel)
}
// InfoEvent returns a log event with severity INFO.
func (l *Logger) InfoEvent(ctx context.Context) *Event {
return l.event(ctx, InfoLevel)
}
// DebugEvent returns a log event with severity DEBUG.
func (l *Logger) DebugEvent(ctx context.Context) *Event {
return l.event(ctx, DebugLevel)
}
func (l *Logger) event(ctx context.Context, level Level) (e *Event) {
var ctxKeys *[]interface{}
var ctxKeysMap *map[interface{}]string
if len(l.ctxKeys) > 0 {
ctxKeys = &l.ctxKeys
}
if len(l.ctxKeysMap) > 0 {
ctxKeysMap = &l.ctxKeysMap
}
return newEvent(ctx, ctxKeys, ctxKeysMap, level, l.lw, level <= l.level, l.isCallerEnabled)
}
// NewLogger creates a new logger for given out and level, and the level is
// optional.
func NewLogger(out io.Writer, level ...string) (*Logger, error) {
return NewLoggerWithError(out, nil, level...)
}
// NewLoggerWithError creates a new logger for given out, err out, level, and the
// err out can be nil, and the level is optional.
func NewLoggerWithError(out, errOut io.Writer, level ...string) (l *Logger, err error) {
if out == nil {
return nil, errors.New("logger output must specified")
}
sw := &StandardWriter{w: out, ew: errOut, pid: os.Getpid()}
l = &Logger{lw: sw}
if len(level) == 1 {
if err = l.SetLevel(level[0]); err != nil {
return nil, err
}
}
return l, nil
}
// NewTerminalLogger creates a logger that write into terminal.
func NewTerminalLogger(level ...string) (*Logger, error) {
return NewLogger(os.Stdout, level...)
}
// NewBufferedTerminalLogger creates a buffered logger that write into terminal.
func NewBufferedTerminalLogger(level ...string) (*Logger, error) {
return NewLogger(bufio.NewWriter(os.Stdout), level...)
}
// NewFileLogger creates a logger that write into file.
func NewFileLogger(filePath string, level ...string) (*Logger, error) {
return NewFileLoggerWithError(filePath, "", level...)
}
// NewFileLoggerWithError creates a logger that write into files.
func NewFileLoggerWithError(filePath, errFilePath string, level ...string) (*Logger, error) {
if err := check.Dir(path.Dir(filePath)); err != nil {
return nil, err
}
if errFilePath != "" {
if err := check.Dir(path.Dir(errFilePath)); err != nil {
return nil, err
}
}
out, err := reopen.NewFileWriter(filePath)
if err != nil {
return nil, err
}
var errOut *reopen.FileWriter
if errFilePath != "" {
errOut, err = reopen.NewFileWriter(errFilePath)
if err != nil {
return nil, err
}
}
c := make(chan os.Signal)
go func() {
for {
select {
case <-c:
out.Reopen()
if errOut != nil {
errOut.Reopen()
}
}
}
}()
signal.Notify(c, syscall.SIGHUP)
if errOut == nil {
return NewLoggerWithError(out, nil, level...)
}
return NewLoggerWithError(out, errOut, level...)
}
// NewBufferedFileLogger creates a logger that write into file with buffer.
// The flushSeconds's unit is second.
func NewBufferedFileLogger(filePath string, flushInterval int, level ...string) (*Logger, error) {
return NewBufferedFileLoggerWithError(filePath, "", flushInterval, level...)
}
// NewBufferedFileLoggerWithError creates a logger that write into files with buffer.
// The flushSeconds's unit is second.
func NewBufferedFileLoggerWithError(filePath, errFilePath string, flushInterval int, level ...string) (*Logger, error) {
if err := check.Dir(path.Dir(filePath)); err != nil {
return nil, err
}
if errFilePath != "" {
if err := check.Dir(path.Dir(errFilePath)); err != nil {
return nil, err
}
}
if flushInterval == 0 {
flushInterval = 10
}
out, err := reopen.NewFileWriter(filePath)
if err != nil {
return nil, err
}
var errOut *reopen.FileWriter
if errFilePath != "" {
errOut, err = reopen.NewFileWriter(errFilePath)
if err != nil {
return nil, err
}
}
bufferedOut := reopen.NewBufferedFileWriter(out)
var bufferedErrOut *reopen.BufferedFileWriter
if errOut != nil {
bufferedErrOut = reopen.NewBufferedFileWriter(errOut)
}
c := make(chan os.Signal)
go func() {
for {
select {
case <-c:
bufferedOut.Reopen()
if bufferedErrOut != nil {
bufferedErrOut.Reopen()
}
case <-time.After(time.Duration(flushInterval) * time.Second):
bufferedOut.Flush()
if bufferedErrOut != nil {
bufferedErrOut.Flush()
}
}
}
}()
signal.Notify(c, syscall.SIGHUP)
if bufferedErrOut == nil {
return NewLoggerWithError(bufferedOut, nil, level...)
}
return NewLoggerWithError(bufferedOut, bufferedErrOut, level...)
}

331
vendor/github.com/pengsrc/go-shared/log/logger_test.go generated vendored Normal file
View file

@ -0,0 +1,331 @@
package log
import (
"context"
"fmt"
"io/ioutil"
"os"
"path"
"strings"
"syscall"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/pengsrc/go-shared/buffer"
)
func TestSetAndGetLevel(t *testing.T) {
l, err := NewTerminalLogger()
assert.NoError(t, err)
l.SetLevel("ERROR")
assert.Equal(t, "ERROR", l.GetLevel())
}
func TestNewLogger(t *testing.T) {
buf := buffer.GlobalBytesPool().Get()
defer buf.Free()
l, err := NewLogger(buf, "INFO")
assert.NoError(t, err)
l.Debug(context.Background(), "DEBUG message")
l.Info(context.Background(), "INFO message")
assert.NotContains(t, buf.String(), "DEBUG message")
assert.Contains(t, buf.String(), "INFO message")
buf.Reset()
// Test logging for context.
type contextKey string
const traceID contextKey = "trace_id"
ctx := context.WithValue(nil, traceID, "60b725f10c9c85c70d97880dfe8191b3")
l.SetInterestContextKeys([]interface{}{traceID})
l.Info(ctx, "Hello World!")
assert.Contains(t, buf.String(), "trace_id=60b725f10c9c85c70d97880dfe8191b3")
t.Log(buf.String())
buf.Reset()
l.SetCallerFlag(true)
l.Info(ctx, "Hello World!")
assert.Contains(t, buf.String(), "source=log/logger_test.go")
t.Log(buf.String())
buf.Reset()
l.Infof(ctx, "Hello %s!", "World")
assert.Contains(t, buf.String(), "source=log/logger_test.go")
t.Log(buf.String())
buf.Reset()
l.InfoEvent(ctx).Messagef("Hello %s!", "World")
assert.Contains(t, buf.String(), "source=log/logger_test.go")
t.Log(buf.String())
buf.Reset()
l.InfoEvent(ctx).Int("count", 1024).Messagef("Hello %s!", "World")
assert.Contains(t, buf.String(), "source=log/logger_test.go")
t.Log(buf.String())
buf.Reset()
}
func TestNewLoggerWithError(t *testing.T) {
buf := buffer.GlobalBytesPool().Get()
errBuf := buffer.GlobalBytesPool().Get()
defer buf.Free()
defer errBuf.Free()
l, err := NewLoggerWithError(buf, errBuf, "INFO")
assert.NoError(t, err)
l.Debug(context.Background(), "DEBUG message")
l.Info(context.Background(), "INFO message")
l.Error(context.Background(), "ERROR message")
assert.NotContains(t, buf.String(), "DEBUG message")
assert.Contains(t, buf.String(), "INFO message")
assert.Contains(t, buf.String(), "ERROR message")
assert.NotContains(t, errBuf.String(), "DEBUG message")
assert.NotContains(t, errBuf.String(), "INFO message")
assert.Contains(t, errBuf.String(), "ERROR message")
}
func TestNewFileLogger(t *testing.T) {
t.Skip()
lFile := path.Join(os.TempDir(), "test.log")
defer os.Remove(lFile)
// Create logger failed.
_, err := NewLoggerWithError(nil, nil, "DEBUG")
assert.Error(t, err)
_, err = NewLoggerWithError(ioutil.Discard, ioutil.Discard, "INVALID")
assert.Error(t, err)
// Create logger success.
l, err := NewFileLogger(lFile, "INFO")
assert.NoError(t, err)
l.Debug(context.Background(), "file - DEBUG message")
l.Info(context.Background(), "file - INFO message")
l.Warn(context.Background(), "file - WARN message")
l.Error(context.Background(), "file - ERROR message")
data, err := ioutil.ReadFile(lFile)
assert.NoError(t, err)
assert.Equal(t, 4, len(strings.Split(string(data), "\n")))
// Move log file.
movedLFile := fmt.Sprintf(`%s.move`, lFile)
err = os.Rename(lFile, movedLFile)
assert.NoError(t, err)
defer os.Remove(movedLFile)
l.Error(context.Background(), "file - ERROR message")
data, err = ioutil.ReadFile(movedLFile)
assert.NoError(t, err)
assert.Equal(t, 5, len(strings.Split(string(data), "\n")))
// Reopen.
syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
time.Sleep(1 * time.Second)
l.Warn(context.Background(), "file - WARN message")
l.Error(context.Background(), "file - ERROR message")
data, err = ioutil.ReadFile(lFile)
assert.NoError(t, err)
assert.Equal(t, 3, len(strings.Split(string(data), "\n")))
}
func TestNewFileLoggerWithError(t *testing.T) {
t.Skip()
lFile := path.Join(os.TempDir(), "test.log")
errLFile := path.Join(os.TempDir(), "test.log.wf")
defer os.Remove(lFile)
defer os.Remove(errLFile)
// Create logger failed.
_, err := NewFileLoggerWithError("/not/exists/dir", "/not/exists/dir", "DEBUG")
assert.Error(t, err)
_, err = NewFileLoggerWithError(lFile, "/not/exists/dir", "DEBUG")
assert.Error(t, err)
_, err = NewFileLoggerWithError(os.TempDir(), os.TempDir(), "DEBUG")
assert.Error(t, err)
_, err = NewFileLoggerWithError(lFile, os.TempDir(), "DEBUG")
assert.Error(t, err)
// Create logger success.
l, err := NewFileLoggerWithError(lFile, errLFile, "DEBUG")
assert.NoError(t, err)
l.Debug(context.Background(), "file - DEBUG message")
l.Info(context.Background(), "file - INFO message")
l.Warn(context.Background(), "file - WARN message")
l.Error(context.Background(), "file - ERROR message")
data, err := ioutil.ReadFile(lFile)
assert.NoError(t, err)
assert.Equal(t, 5, len(strings.Split(string(data), "\n")))
errLog, err := ioutil.ReadFile(errLFile)
assert.NoError(t, err)
assert.Equal(t, 3, len(strings.Split(string(errLog), "\n")))
// Move data file.
movedLogFile := fmt.Sprintf(`%s.move`, lFile)
err = os.Rename(lFile, movedLogFile)
assert.NoError(t, err)
defer os.Remove(movedLogFile)
movedErrLogFile := fmt.Sprintf(`%s.move`, errLFile)
err = os.Rename(errLFile, movedErrLogFile)
assert.NoError(t, err)
defer os.Remove(movedErrLogFile)
l.Error(context.Background(), "file - ERROR message")
data, err = ioutil.ReadFile(movedLogFile)
assert.NoError(t, err)
assert.Equal(t, 6, len(strings.Split(string(data), "\n")))
errLog, err = ioutil.ReadFile(movedErrLogFile)
assert.NoError(t, err)
assert.Equal(t, 4, len(strings.Split(string(errLog), "\n")))
// Reopen.
syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
time.Sleep(1 * time.Second)
l.Warn(context.Background(), "file - WARN message")
l.Error(context.Background(), "file - ERROR message")
data, err = ioutil.ReadFile(lFile)
assert.NoError(t, err)
assert.Equal(t, 3, len(strings.Split(string(data), "\n")))
errLog, err = ioutil.ReadFile(errLFile)
assert.NoError(t, err)
assert.Equal(t, 3, len(strings.Split(string(errLog), "\n")))
}
func TestBufferedFileLogger(t *testing.T) {
lFile := path.Join(os.TempDir(), "test.log")
defer os.Remove(lFile)
l, err := NewBufferedFileLogger(lFile, 1, "DEBUG")
assert.NoError(t, err)
l.Debug(context.Background(), "file - DEBUG message")
l.Info(context.Background(), "file - INFO message")
l.Warn(context.Background(), "file - WARN message")
l.Error(context.Background(), "file - ERROR message")
data, err := ioutil.ReadFile(lFile)
assert.NoError(t, err)
assert.Equal(t, 1, len(strings.Split(string(data), "\n")))
// Wait timeout.
time.Sleep(2 * time.Second)
data, err = ioutil.ReadFile(lFile)
assert.NoError(t, err)
assert.Equal(t, 5, len(strings.Split(string(data), "\n")))
}
func TestBufferedFileLoggerWithError(t *testing.T) {
lFile := path.Join(os.TempDir(), "test.log")
errLFile := path.Join(os.TempDir(), "test.log.wf")
defer os.Remove(lFile)
defer os.Remove(errLFile)
// Create logger failed.
_, err := NewBufferedFileLoggerWithError("/not/exists/dir", "/not/exists/dir", 0, "DEBUG")
assert.Error(t, err)
_, err = NewBufferedFileLoggerWithError(lFile, "/not/exists/dir", 0, "DEBUG")
assert.Error(t, err)
_, err = NewBufferedFileLoggerWithError(os.TempDir(), os.TempDir(), 0, "DEBUG")
assert.Error(t, err)
_, err = NewBufferedFileLoggerWithError(lFile, os.TempDir(), 0, "DEBUG")
assert.Error(t, err)
// Create logger success.
errL, err := NewBufferedFileLoggerWithError(lFile, errLFile, 1, "DEBUG")
assert.NoError(t, err)
errL.Debug(context.Background(), "file - DEBUG message")
errL.Info(context.Background(), "file - INFO message")
errL.Warn(context.Background(), "file - WARN message")
errL.Error(context.Background(), "file - ERROR message")
data, err := ioutil.ReadFile(lFile)
assert.NoError(t, err)
assert.Equal(t, 1, len(strings.Split(string(data), "\n")))
errData, err := ioutil.ReadFile(errLFile)
assert.NoError(t, err)
assert.Equal(t, 1, len(strings.Split(string(errData), "\n")))
// Flush log.
errL.Flush()
data, err = ioutil.ReadFile(lFile)
assert.NoError(t, err)
assert.Equal(t, 5, len(strings.Split(string(data), "\n")))
errData, err = ioutil.ReadFile(errLFile)
assert.NoError(t, err)
assert.Equal(t, 3, len(strings.Split(string(errData), "\n")))
// Wait timeout to improve test coverage.
time.Sleep(2 * time.Second)
// Reopen using signal to improve test coverage.
syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
}
func TestTerminalLogger(t *testing.T) {
l, err := NewTerminalLogger("DEBUG")
assert.NoError(t, err)
l.Debug(context.Background(), "terminal - DEBUG message")
l.Info(context.Background(), "terminal - INFO message")
l.Warn(context.Background(), "terminal - WARN message")
l.Error(context.Background(), "terminal - ERROR message")
l.Debugf(context.Background(), "terminal - DEBUG message - %d", time.Now().Unix())
l.Infof(context.Background(), "terminal - INFO message - %d", time.Now().Unix())
l.Warnf(context.Background(), "terminal - WARN message - %d", time.Now().Unix())
l.Errorf(context.Background(), "terminal - ERROR message - %d", time.Now().Unix())
}
func TestBufferedTerminalLogger(t *testing.T) {
l, err := NewBufferedTerminalLogger("DEBUG")
assert.NoError(t, err)
l.Debug(context.Background(), "terminal - DEBUG message")
l.Info(context.Background(), "terminal - INFO message")
l.Warn(context.Background(), "terminal - WARN message")
l.Error(context.Background(), "terminal - ERROR message")
l.Flush()
}
func BenchmarkLogger(b *testing.B) {
l, err := NewLogger(ioutil.Discard, "DEBUG")
assert.NoError(b, err)
ctx := context.Background()
b.ResetTimer()
for i := 0; i < b.N; i++ {
l.DebugEvent(ctx).String("key", "value").Messagef("Hello %s!", "World")
}
}

83
vendor/github.com/pengsrc/go-shared/log/writer.go generated vendored Normal file
View file

@ -0,0 +1,83 @@
package log
import (
"io"
"time"
"github.com/pengsrc/go-shared/buffer"
"github.com/pengsrc/go-shared/convert"
)
// LevelWriter defines as interface a writer may implement in order
// to receive level information with payload.
type LevelWriter interface {
io.Writer
WriteLevel(level Level, message []byte) (n int, err error)
}
// Flusher defines a interface with Flush() method.
type Flusher interface {
Flush() error
}
// StandardWriter implements io.Writer{} and LevelWriter{} interface.
type StandardWriter struct {
w io.Writer
ew io.Writer // Writer for WARN, ERROR, FATAL, PANIC
dl Level // Default level
pid int
}
// Write implements the io.Writer{} interface.
func (sw *StandardWriter) Write(p []byte) (n int, err error) {
return sw.WriteLevel(sw.dl, p)
}
// WriteLevel implements the LevelWriter{} interface.
func (sw *StandardWriter) WriteLevel(level Level, message []byte) (n int, err error) {
levelString := level.String()
if len(levelString) == 4 {
levelString = " " + levelString
}
buf := buffer.GlobalBytesPool().Get()
defer buf.Free()
buf.AppendString("[")
buf.AppendTime(time.Now().UTC(), convert.ISO8601Milli)
buf.AppendString(" #")
buf.AppendInt(int64(sw.pid))
buf.AppendString("] ")
buf.AppendString(levelString)
buf.AppendString(" -- : ")
buf.AppendBytes(message)
buf.AppendString("\n")
if sw.ew != nil {
if level > MuteLevel && level <= WarnLevel {
n, err = sw.ew.Write(buf.Bytes())
if err != nil {
return
}
}
}
return sw.w.Write(buf.Bytes())
}
// Flush implements the Flusher{} interface.
func (sw *StandardWriter) Flush() (err error) {
if flusher, ok := sw.w.(Flusher); ok {
err = flusher.Flush()
if err != nil {
return err
}
}
if sw.ew != nil {
if flusher, ok := sw.ew.(Flusher); ok {
err = flusher.Flush()
return err
}
}
return nil
}

36
vendor/github.com/pengsrc/go-shared/log/writer_test.go generated vendored Normal file
View file

@ -0,0 +1,36 @@
package log
import (
"io"
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func TestStandardWriter(t *testing.T) {
var w io.Writer
w = &StandardWriter{
w: os.Stdout, ew: os.Stderr,
dl: MuteLevel, pid: os.Getpid(),
}
lw, ok := w.(LevelWriter)
assert.True(t, ok)
_, ok = w.(Flusher)
assert.True(t, ok)
_, err := lw.Write([]byte("Hello World!"))
assert.NoError(t, err)
}
func BenchmarkStandardWriter(b *testing.B) {
lw := &StandardWriter{w: ioutil.Discard, ew: ioutil.Discard}
b.ResetTimer()
for i := 0; i < b.N; i++ {
lw.Write([]byte("Hello World!"))
}
}