mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-23 06:40:23 +00:00
226 lines
5.6 KiB
Go
226 lines
5.6 KiB
Go
|
package flume
|
||
|
|
||
|
import (
|
||
|
"encoding/hex"
|
||
|
"github.com/mgutz/ansi"
|
||
|
"go.uber.org/zap"
|
||
|
"go.uber.org/zap/buffer"
|
||
|
"go.uber.org/zap/zapcore"
|
||
|
)
|
||
|
|
||
|
//nolint:gochecknoinits
|
||
|
func init() {
|
||
|
_ = zap.RegisterEncoder("term", func(cfg zapcore.EncoderConfig) (zapcore.Encoder, error) {
|
||
|
return NewConsoleEncoder((*EncoderConfig)(&cfg)), nil
|
||
|
})
|
||
|
_ = zap.RegisterEncoder("term-color", func(cfg zapcore.EncoderConfig) (zapcore.Encoder, error) {
|
||
|
return NewColorizedConsoleEncoder((*EncoderConfig)(&cfg), nil), nil
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// Colorizer returns ansi escape sequences for the colors for each log level.
|
||
|
// See Colors for a default implementation.
|
||
|
type Colorizer interface {
|
||
|
Level(l Level) string
|
||
|
}
|
||
|
|
||
|
// Colors is an implementation of the Colorizer interface, which assigns colors
|
||
|
// to the default log levels.
|
||
|
type Colors struct {
|
||
|
Debug, Info, Warn, Error string
|
||
|
}
|
||
|
|
||
|
// Level implements Colorizer
|
||
|
func (c *Colors) Level(l Level) string {
|
||
|
if l < DebugLevel {
|
||
|
return Dim
|
||
|
}
|
||
|
switch l {
|
||
|
case DebugLevel:
|
||
|
return c.Debug
|
||
|
case InfoLevel:
|
||
|
return c.Info
|
||
|
case Level(zapcore.WarnLevel):
|
||
|
return c.Warn
|
||
|
default:
|
||
|
return c.Error
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// DefaultColors is the default instance of Colors, used as the default colors if
|
||
|
// a nil Colorizer is passed to NewColorizedConsoleEncoder.
|
||
|
var DefaultColors = Colors{
|
||
|
Debug: ansi.ColorCode("cyan"),
|
||
|
Info: ansi.ColorCode("green+h"),
|
||
|
Warn: ansi.ColorCode("yellow+bh"),
|
||
|
Error: ansi.ColorCode("red+bh"),
|
||
|
}
|
||
|
|
||
|
type consoleEncoder struct {
|
||
|
*ltsvEncoder
|
||
|
colorizer Colorizer
|
||
|
}
|
||
|
|
||
|
// NewConsoleEncoder creates an encoder whose output is designed for human -
|
||
|
// rather than machine - consumption. It serializes the core log entry data
|
||
|
// (message, level, timestamp, etc.) in a plain-text format. The context is
|
||
|
// encoded in LTSV.
|
||
|
//
|
||
|
// Note that although the console encoder doesn't use the keys specified in the
|
||
|
// encoder configuration, it will omit any element whose key is set to the empty
|
||
|
// string.
|
||
|
func NewConsoleEncoder(cfg *EncoderConfig) Encoder {
|
||
|
ltsvEncoder := NewLTSVEncoder(cfg).(*ltsvEncoder)
|
||
|
ltsvEncoder.allowNewLines = true
|
||
|
ltsvEncoder.allowTabs = true
|
||
|
ltsvEncoder.blankKey = "value"
|
||
|
ltsvEncoder.binaryEncoder = hex.Dump
|
||
|
|
||
|
return &consoleEncoder{ltsvEncoder: ltsvEncoder}
|
||
|
}
|
||
|
|
||
|
// NewColorizedConsoleEncoder creates a console encoder, like NewConsoleEncoder, but
|
||
|
// colors the text with ansi escape codes. `colorize` configures which colors to
|
||
|
// use for each level.
|
||
|
//
|
||
|
// If `colorizer` is nil, it will default to DefaultColors.
|
||
|
//
|
||
|
// `github.com/mgutz/ansi` is a convenient package for getting color codes, e.g.:
|
||
|
//
|
||
|
// ansi.ColorCode("red")
|
||
|
//
|
||
|
func NewColorizedConsoleEncoder(cfg *EncoderConfig, colorizer Colorizer) Encoder {
|
||
|
e := NewConsoleEncoder(cfg).(*consoleEncoder)
|
||
|
e.colorizer = colorizer
|
||
|
if e.colorizer == nil {
|
||
|
e.colorizer = &DefaultColors
|
||
|
}
|
||
|
return e
|
||
|
}
|
||
|
|
||
|
// Clone implements the Encoder interface
|
||
|
func (c *consoleEncoder) Clone() zapcore.Encoder {
|
||
|
return &consoleEncoder{
|
||
|
ltsvEncoder: c.ltsvEncoder.Clone().(*ltsvEncoder),
|
||
|
colorizer: c.colorizer,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Dim is the color used for context keys, time, and caller information
|
||
|
var Dim = ansi.ColorCode("240")
|
||
|
|
||
|
// Bright is the color used for the message
|
||
|
var Bright = ansi.ColorCode("default+b")
|
||
|
|
||
|
// EncodeEntry implements the Encoder interface
|
||
|
func (c *consoleEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
|
||
|
final := *c.ltsvEncoder
|
||
|
context := final.buf
|
||
|
final.buf = bufPool.Get()
|
||
|
|
||
|
origLen := final.buf.Len()
|
||
|
|
||
|
if c.TimeKey != "" {
|
||
|
c.colorDim(final.buf)
|
||
|
final.skipNextElementSeparator = true
|
||
|
c.EncodeTime(ent.Time, &final)
|
||
|
}
|
||
|
|
||
|
if c.LevelKey != "" {
|
||
|
c.colorLevel(final.buf, ent.Level)
|
||
|
if final.buf.Len() > origLen {
|
||
|
final.buf.AppendByte(' ')
|
||
|
}
|
||
|
final.skipNextElementSeparator = true
|
||
|
|
||
|
c.EncodeLevel(ent.Level, &final)
|
||
|
|
||
|
}
|
||
|
|
||
|
if final.buf.Len() > origLen {
|
||
|
c.colorDim(final.buf)
|
||
|
final.buf.AppendString(" | ")
|
||
|
} else {
|
||
|
final.buf.Reset()
|
||
|
}
|
||
|
|
||
|
// Add the message itself.
|
||
|
if c.MessageKey != "" {
|
||
|
c.colorReset(final.buf)
|
||
|
// c.colorBright(&final)
|
||
|
final.safeAddString(ent.Message, false)
|
||
|
// ensure a minimum of 2 spaces between the message and the fields,
|
||
|
// to improve readability
|
||
|
final.buf.AppendString(" ")
|
||
|
}
|
||
|
|
||
|
c.colorDim(final.buf)
|
||
|
|
||
|
// Add fields.
|
||
|
for _, f := range fields {
|
||
|
f.AddTo(&final)
|
||
|
}
|
||
|
|
||
|
// Add context
|
||
|
if context.Len() > 0 {
|
||
|
final.addFieldSeparator()
|
||
|
_, _ = final.buf.Write(context.Bytes())
|
||
|
}
|
||
|
|
||
|
// Add callsite
|
||
|
c.writeCallSite(&final, ent.LoggerName, ent.Caller)
|
||
|
|
||
|
// If there's no stacktrace key, honor that; this allows users to force
|
||
|
// single-line output.
|
||
|
if ent.Stack != "" && c.StacktraceKey != "" {
|
||
|
final.buf.AppendByte('\n')
|
||
|
final.buf.AppendString(ent.Stack)
|
||
|
}
|
||
|
c.colorReset(final.buf)
|
||
|
final.buf.AppendByte('\n')
|
||
|
|
||
|
return final.buf, nil
|
||
|
}
|
||
|
|
||
|
func (c *consoleEncoder) writeCallSite(final *ltsvEncoder, name string, caller zapcore.EntryCaller) {
|
||
|
shouldWriteName := name != "" && c.NameKey != ""
|
||
|
shouldWriteCaller := caller.Defined && c.CallerKey != ""
|
||
|
if !shouldWriteName && !shouldWriteCaller {
|
||
|
return
|
||
|
}
|
||
|
final.addKey("@")
|
||
|
if shouldWriteName {
|
||
|
final.buf.AppendString(name)
|
||
|
if shouldWriteCaller {
|
||
|
final.buf.AppendByte('@')
|
||
|
}
|
||
|
}
|
||
|
if shouldWriteCaller {
|
||
|
final.skipNextElementSeparator = true
|
||
|
final.EncodeCaller(caller, final)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *consoleEncoder) colorDim(buf *buffer.Buffer) {
|
||
|
c.applyColor(buf, Dim)
|
||
|
}
|
||
|
|
||
|
func (c *consoleEncoder) colorLevel(buf *buffer.Buffer, level zapcore.Level) {
|
||
|
if c.colorizer != nil {
|
||
|
c.applyColor(buf, c.colorizer.Level(Level(level)))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *consoleEncoder) applyColor(buf *buffer.Buffer, s string) {
|
||
|
if c.colorizer != nil {
|
||
|
buf.AppendString(ansi.Reset)
|
||
|
if s != "" {
|
||
|
buf.AppendString(s)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *consoleEncoder) colorReset(buf *buffer.Buffer) {
|
||
|
c.applyColor(buf, "")
|
||
|
}
|