overdue
This commit is contained in:
460
.rclone_repo/vendor/github.com/pengsrc/go-shared/log/event.go
generated
vendored
Executable file
460
.rclone_repo/vendor/github.com/pengsrc/go-shared/log/event.go
generated
vendored
Executable 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()
|
||||
151
.rclone_repo/vendor/github.com/pengsrc/go-shared/log/exported.go
generated
vendored
Executable file
151
.rclone_repo/vendor/github.com/pengsrc/go-shared/log/exported.go
generated
vendored
Executable 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
|
||||
67
.rclone_repo/vendor/github.com/pengsrc/go-shared/log/level.go
generated
vendored
Executable file
67
.rclone_repo/vendor/github.com/pengsrc/go-shared/log/level.go
generated
vendored
Executable 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)
|
||||
}
|
||||
327
.rclone_repo/vendor/github.com/pengsrc/go-shared/log/logger.go
generated
vendored
Executable file
327
.rclone_repo/vendor/github.com/pengsrc/go-shared/log/logger.go
generated
vendored
Executable 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...)
|
||||
}
|
||||
83
.rclone_repo/vendor/github.com/pengsrc/go-shared/log/writer.go
generated
vendored
Executable file
83
.rclone_repo/vendor/github.com/pengsrc/go-shared/log/writer.go
generated
vendored
Executable 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
|
||||
}
|
||||
Reference in New Issue
Block a user