mirror of
https://github.com/bolucat/Archive.git
synced 2025-12-24 13:28:37 +08:00
143 lines
3.5 KiB
Go
143 lines
3.5 KiB
Go
package log
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Default key names for the default fields.
|
|
const (
|
|
defaultTimestampFormat = time.RFC3339
|
|
FieldKeyMsg = "msg"
|
|
FieldKeyLevel = "level"
|
|
FieldKeyTime = "time"
|
|
FieldKeyFunc = "func"
|
|
FieldKeyFile = "file"
|
|
)
|
|
|
|
// LogPrefix is a fixed string printed at the beginning of each line
|
|
// with DaemonFormatter. Set it as a build time variable to help debug
|
|
// the program.
|
|
var LogPrefix = ""
|
|
|
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
|
// `Entry`. It exposes all the fields, including the default ones:
|
|
//
|
|
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
|
// * `entry.Data["time"]`. The timestamp.
|
|
// * `entry.Data["level"]. The level the entry was logged at.
|
|
//
|
|
// Any additional fields added with `WithField` or `WithFields` are also in
|
|
// `entry.Data`. Format is expected to return an array of bytes which are then
|
|
// logged to `logger.Out`.
|
|
type Formatter interface {
|
|
Format(*Entry) ([]byte, error)
|
|
}
|
|
|
|
// CliFormatter is a log formatter that works best for command output.
|
|
// It doesn't print log prefix, time, level, or field data.
|
|
type CliFormatter struct{}
|
|
|
|
func (f *CliFormatter) Format(entry *Entry) ([]byte, error) {
|
|
var buf *bytes.Buffer
|
|
if entry.Buffer != nil {
|
|
buf = entry.Buffer
|
|
} else {
|
|
buf = &bytes.Buffer{}
|
|
}
|
|
|
|
buf.WriteString(entry.Message)
|
|
buf.WriteString("\n")
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
// DaemonFormatter is the a log formatter that is suitable for daemon.
|
|
// FATAL log is also printed to stderr.
|
|
type DaemonFormatter struct {
|
|
NoPrefix bool
|
|
NoTimestamp bool
|
|
NoLevel bool
|
|
}
|
|
|
|
func (f *DaemonFormatter) Format(entry *Entry) ([]byte, error) {
|
|
userData := make(Fields)
|
|
for k, v := range entry.Data {
|
|
userData[k] = v
|
|
}
|
|
userKeys := make([]string, 0, len(userData))
|
|
for k := range userData {
|
|
userKeys = append(userKeys, k)
|
|
}
|
|
|
|
var fileInfo, funcInfo string
|
|
|
|
orderedKeys := make([]string, 0, 5+len(userData))
|
|
if !f.NoTimestamp {
|
|
orderedKeys = append(orderedKeys, FieldKeyTime)
|
|
}
|
|
if !f.NoLevel {
|
|
orderedKeys = append(orderedKeys, FieldKeyLevel)
|
|
}
|
|
orderedKeys = append(orderedKeys, FieldKeyMsg)
|
|
if entry.HasCaller() {
|
|
fileInfo = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
|
funcInfo = entry.Caller.Function
|
|
orderedKeys = append(orderedKeys, FieldKeyFile)
|
|
orderedKeys = append(orderedKeys, FieldKeyFunc)
|
|
}
|
|
sort.Strings(userKeys)
|
|
orderedKeys = append(orderedKeys, userKeys...)
|
|
|
|
var buf *bytes.Buffer
|
|
if entry.Buffer != nil {
|
|
buf = entry.Buffer
|
|
} else {
|
|
buf = &bytes.Buffer{}
|
|
}
|
|
|
|
if !f.NoPrefix {
|
|
buf.WriteString(LogPrefix)
|
|
}
|
|
for _, key := range orderedKeys {
|
|
var value string
|
|
switch {
|
|
case key == FieldKeyTime:
|
|
value = entry.Time.Format(defaultTimestampFormat)
|
|
case key == FieldKeyLevel:
|
|
value = strings.ToUpper(entry.Level.String())
|
|
case key == FieldKeyMsg:
|
|
value = entry.Message
|
|
case key == FieldKeyFile && entry.HasCaller():
|
|
value = fileInfo
|
|
case key == FieldKeyFunc && entry.HasCaller():
|
|
value = funcInfo
|
|
default:
|
|
value = fmt.Sprintf("%v=%v", key, userData[key])
|
|
}
|
|
|
|
if buf.Len() > 0 {
|
|
// Add a space to separate from the previous field.
|
|
buf.WriteString(" ")
|
|
}
|
|
buf.WriteString(value)
|
|
}
|
|
buf.WriteString("\n")
|
|
|
|
if entry.Level == FatalLevel {
|
|
fmt.Fprint(os.Stderr, buf.String())
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
// NilFormatter prints no log. It disables logging.
|
|
type NilFormatter struct{}
|
|
|
|
func (f *NilFormatter) Format(entry *Entry) ([]byte, error) {
|
|
return []byte{}, nil
|
|
}
|