首页 > 其他分享 >go封装zap日志

go封装zap日志

时间:2024-05-13 16:19:26浏览次数:17  
标签:... field fields constructs Field go 日志 zap

log.go

package xlog
import (
	"context"
	"fmt"
	"os"
	"runtime/debug"
	"time"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
   rotatelogs "github.com/lestrrat-go/file-rotatelogs"
)

const (
	DefaultLinkName         = "latest.log"
	DefaultFileMaxAge       = 7 * 86400
	DefaultFileRotationTime = 86400
	DefaultTimeFormat       = "2006-01-02T15:04:05Z07:00"
	DefaultTextEncoder      = "json"

	DefaultMessageKey    = "msg"
	DefaultLevelKey      = "log.level"
	DefaultTimeKey       = "@timestamp"
	DefaultNameKey       = "log.logger"
	DefaultCallerKey     = "log.caller"
	DefaultStacktraceKey = "stacktrace"
	DefaultServiceIdKey  = "service.id"
	DefaultTraceKey      = "traceID"
)

const (
	// DebugLevel logs are typically voluminous, and are usually disabled in
	// production.
	DebugLevel = "debug"
	// InfoLevel is the default logging priority.
	InfoLevel = "info"
	// WarnLevel logs are more important than Info, but don't need individual
	// human review.
	WarnLevel = "warn"
	// ErrorLevel logs are high-priority. If an application is running smoothly,
	// it shouldn't generate any error-level logs.
	ErrorLevel = "error"
	// DPanicLevel logs are particularly important errors. In development the
	// logger panics after writing the message.
	DPanicLevel = "dpanic"
	// PanicLevel logs a message, then panics.
	PanicLevel = "panic"
	// FatalLevel logs a message, then calls os.Exit(1).
	FatalLevel = "fatal"

	// LowercaseLevelEncoder serializes a Level to a lowercase string. For example,
	// InfoLevel is serialized to "info".
	LowercaseLevelEncoder = "LowercaseLevelEncoder"
	// LowercaseColorLevelEncoder serializes a Level to a lowercase string and adds coloring.
	// For example, InfoLevel is serialized to "info" and colored blue.
	LowercaseColorLevelEncoder = "LowercaseColorLevelEncoder"
	// CapitalLevelEncoder serializes a Level to an all-caps string. For example,
	// InfoLevel is serialized to "INFO".
	CapitalLevelEncoder = "CapitalLevelEncoder"
	// CapitalColorLevelEncoder serializes a Level to an all-caps string and adds color.
	// For example, InfoLevel is serialized to "INFO" and colored blue.
	CapitalColorLevelEncoder = "CapitalColorLevelEncoder"
)
// Field is an alias for Field.
// Aliasing this type dramatically improves the navigability of this package's API documentation.
type Field = zap.Field

var (
	// Skip constructs a no-op field, which is often useful when handling invalid inputs in other Field constructors
	Skip = zap.Skip

	// 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.
	Binary = zap.Binary

	// Bool constructs a field that carries a bool.
	Bool = zap.Bool

	// Boolp constructs a field that carries a *bool.
	// The returned Field will safely and explicitly represent `nil` when appropriate.
	Boolp = zap.Boolp

	// 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.
	ByteString = zap.ByteString

	// ByteStrings constructs a field that carries a slice of []byte, each of which
	// must be UTF-8 encoded text.
	ByteStrings = zap.ByteStrings

	// Complex128 constructs a field that carries a complex number.
	// Unlike most numeric fields, this costs an allocation (to convert the complex128 to interface{}).
	Complex128 = zap.Complex128

	// Complex128p constructs a field that carries a *complex128.
	// The returned Field will safely and explicitly represent `nil` when appropriate.
	Complex128p = zap.Complex128p

	// Complex64 constructs a field that carries a complex number.
	// Unlike most numeric fields, this costs an allocation (to convert the complex64 to interface{}).
	Complex64 = zap.Complex64

	// Complex64p constructs a field that carries a *complex64.
	// The returned Field will safely and explicitly represent `nil` when appropriate.
	Complex64p = zap.Complex64p

	// Float64 constructs a field that carries a float64.
	// The way the floating-point value is represented is encoder-dependent, so marshaling is necessarily lazy.
	Float64 = zap.Float64

	// Float64p constructs a field that carries a *float64. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Float64p = zap.Float64p

	// Float32 constructs a field that carries a float32. The way the
	// floating-point value is represented is encoder-dependent, so marshaling is
	// necessarily lazy.
	Float32 = zap.Float32

	// Float32p constructs a field that carries a *float32. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Float32p = zap.Float32p

	// Int constructs a field with the given key and value.
	Int = zap.Int

	// Intp constructs a field that carries a *int. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Intp = zap.Intp

	// Int64 constructs a field with the given key and value.
	Int64 = zap.Int64

	// Int64p constructs a field that carries a *int64. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Int64p = zap.Int64p

	// Int32 constructs a field with the given key and value.
	Int32 = zap.Int32

	// Int32p constructs a field that carries a *int32. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Int32p = zap.Int32p

	// Int16 constructs a field with the given key and value.
	Int16 = zap.Int16

	// Int16p constructs a field that carries a *int16. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Int16p = zap.Int16p

	// Int8 constructs a field with the given key and value.
	Int8 = zap.Int8

	// Int8p constructs a field that carries a *int8. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Int8p = zap.Int8p

	// String constructs a field with the given key and value.
	String = zap.String

	// Stringp constructs a field that carries a *string. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Stringp = zap.Stringp

	// Uint constructs a field with the given key and value.
	Uint = zap.Uint

	// Uintp constructs a field that carries a *uint. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Uintp = zap.Uintp

	// Uint64 constructs a field with the given key and value.
	Uint64 = zap.Uint64

	// Uint64p constructs a field that carries a *uint64. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Uint64p = zap.Uint64p

	// Uint32 constructs a field with the given key and value.
	Uint32 = zap.Uint32

	// Uint32p constructs a field that carries a *uint32. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Uint32p = zap.Uint32p

	// Uint16 constructs a field with the given key and value.
	Uint16 = zap.Uint16

	// Uint16p constructs a field that carries a *uint16. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Uint16p = zap.Uint16p

	// Uint8 constructs a field with the given key and value.
	Uint8 = zap.Uint8

	// Uint8p constructs a field that carries a *uint8. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Uint8p = zap.Uint8p

	// Uintptr constructs a field with the given key and value.
	Uintptr = zap.Uintptr

	// Uintptrp constructs a field that carries a *uintptr. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Uintptrp = zap.Uintptrp

	// 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.
	Reflect = zap.Reflect

	// 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.
	Namespace = zap.Namespace

	// 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.
	Stringer = zap.Stringer

	// Time constructs a Field with the given key and value. The encoder
	// controls how the time is serialized.
	Time = zap.Time

	// Timep constructs a field that carries a *time.Time. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Timep = zap.Timep

	// 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.
	Stack = zap.Stack

	// StackSkip constructs a field similarly to Stack, but also skips the given
	// number of frames from the top of the stacktrace.
	StackSkip = zap.StackSkip

	// Duration constructs a field with the given key and value. The encoder
	// controls how the duration is serialized.
	Duration = zap.Duration

	// Durationp constructs a field that carries a *time.Duration. The returned Field will safely
	// and explicitly represent `nil` when appropriate.
	Durationp = zap.Durationp

	// 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.
	Object = zap.Object

	// Inline constructs a Field that is similar to Object, but it
	// will add the elements of the provided ObjectMarshaler to the
	// current namespace.
	Inline = zap.Inline

	// 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.
	Any = zap.Any
)
var id, _ = os.Hostname()

type Config struct {
	Path       string `json:"path" toml:"path"`
	FileFormat string `json:"fileFormat" toml:"fileFormat"`
	Level      string `json:"level" toml:"level"`
	TimeZone   string `json:"timezone" toml:"timezone"`

	FilePrefix  string `json:"filePrefix" toml:"filePrefix"`
	TextEncoder string `json:"textEncoder" toml:"textEncoder"`
	ShowLine    bool   `json:"showLine" toml:"showLine"`
	// Configure the primitive representations of common complex types. For
	// example, some users may want all time.Times serialized as floating-point
	// seconds since epoch, while others may prefer ISO8601 strings.
	EncodeLevel      string `json:"encodeLevel" toml:"encodeLevel"`
	StacktraceKey    string `json:"stacktraceKey" toml:"stacktraceKey"`
	LogInConsole     bool   `json:"logInConsole" toml:"logInConsole"`
	TimeFormat       string `json:"timeFormat" toml:"timeFormat"`
	FileMaxAge       int64  `json:"fileMaxAge" toml:"fileMaxAge"`
	FileRotationTime int64  `json:"fileRotationTime" toml:"fileRotationTime"`
	// Set the keys used for each log entry. If any key is empty, that portion
	// of the entry is omitted.
	MessageKey string `json:"messageKey" toml:"messageKey"`
	LevelKey   string `json:"levelKey" toml:"levelKey"`
	TimeKey    string `json:"timeKey" toml:"timeKey"`
	NameKey    string `json:"nameKey" toml:"nameKey"`
	CallerKey  string `json:"callerKey" toml:"callerKey"`

	level    zapcore.Level
	timezone *time.Location
}

func (c *Config) Copy() *Config {
	config := *c
	return &config
}

func (c *Config) initOptions() error {
	if c.TimeZone != "" {
		loc, err := time.LoadLocation(c.TimeZone)
		if err != nil {
			return fmt.Errorf("Fail to loadLocation: %s, err: %v.\n", c.TimeZone, err)
		}
		c.timezone = loc
	} else {
		c.timezone = time.UTC
	}
	if c.FileMaxAge == 0 {
		c.FileMaxAge = DefaultFileMaxAge
	}
	if c.FileRotationTime == 0 {
		c.FileRotationTime = DefaultFileRotationTime
	}
	if c.TimeFormat == "" {
		c.TimeFormat = DefaultTimeFormat
	}
	if c.MessageKey == "" {
		c.MessageKey = DefaultMessageKey
	}
	if c.LevelKey == "" {
		c.LevelKey = DefaultLevelKey
	}
	if c.TimeKey == "" {
		c.TimeKey = DefaultTimeKey
	}
	if c.NameKey == "" {
		c.NameKey = DefaultNameKey
	}
	if c.CallerKey == "" {
		c.CallerKey = DefaultCallerKey
	}
	if c.StacktraceKey == "" {
		c.StacktraceKey = DefaultStacktraceKey
	}
	if c.TextEncoder == "" {
		c.TextEncoder = DefaultTextEncoder
	}
	switch c.Level {
	case DebugLevel:
		c.level = zap.DebugLevel
	case InfoLevel:
		c.level = zap.InfoLevel
	case WarnLevel:
		c.level = zap.WarnLevel
	case ErrorLevel:
		c.level = zap.ErrorLevel
	case DPanicLevel:
		c.level = zap.DPanicLevel
	case PanicLevel:
		c.level = zap.PanicLevel
	case FatalLevel:
		c.level = zap.FatalLevel
	default:
		c.level = zap.InfoLevel
	}
	return nil
}

type logger struct {
	c         *Config
	zapLogger *zap.Logger
	prefix    []Field
}

var xlogger *logger

func init() {
	defaultConfig := &Config{}
	_ = defaultConfig.initOptions()
	Init(defaultConfig)
}

// Init init xlog.
func Init(c *Config) {
	err := c.initOptions()
	if err != nil {
		panic(fmt.Errorf("fail to init log config, err: %v", err))
	}

	var zapLogger *zap.Logger

	if c.level == zap.DebugLevel || c.level == zap.ErrorLevel {
		zapLogger = zap.New(getEncoderCore(c), zap.AddStacktrace(c.level))
	} else {
		zapLogger = zap.New(getEncoderCore(c))
	}

	if c.ShowLine {
		zapLogger = zapLogger.WithOptions(zap.AddCaller())
	}

	xlogger = &logger{c: c, zapLogger: zapLogger}
}

func Default() Logger {
	return xlogger
}

func WithFields(fields ...Field) {
	xlogger = Default().WithFields(fields...).(*logger)
}

// Debug logs a message at DebugLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func Debug(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, xlogger.prefix...)
	xlogger.zapLogger.Debug(msg, fields...)
}

// Info logs a message at InfoLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func Info(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, xlogger.prefix...)
	xlogger.zapLogger.Info(msg, fields...)
}

// Warn logs a message at WarnLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func Warn(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, xlogger.prefix...)
	xlogger.zapLogger.Warn(msg, fields...)
}

// Error logs a message at ErrorLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func Error(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, ByteString("stack", debug.Stack()))
	fields = append(fields, xlogger.prefix...)
	xlogger.zapLogger.Error(msg, fields...)
}

// DPanic logs a message at DPanicLevel. The message includes any fields
// passed at the log site, as well as any fields accumulated on the logger.
//
// If the logger is in development mode, it then panics (DPanic means
// "development panic"). This is useful for catching errors that are
// recoverable, but shouldn't ever happen.
func DPanic(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, ByteString("stack", debug.Stack()))
	fields = append(fields, xlogger.prefix...)
	xlogger.zapLogger.DPanic(msg, fields...)
}

// Panic logs a message at PanicLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then panics, even if logging at PanicLevel is disabled.
func Panic(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, ByteString("stack", debug.Stack()))
	fields = append(fields, xlogger.prefix...)
	xlogger.zapLogger.Panic(msg, fields...)
}

// Fatal logs a message at FatalLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then calls os.Exit(1), even if logging at FatalLevel is
// disabled.
func Fatal(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, ByteString("stack", debug.Stack()))
	fields = append(fields, xlogger.prefix...)
	xlogger.zapLogger.Fatal(msg, fields...)
}

// Sync calls the underlying Core's Sync method, flushing any buffered log
// entries. Applications should take care to call Sync before exiting.
func Sync() error {
	return xlogger.zapLogger.Sync()
}

type Logger interface {
	WithFields(fields ...Field) Logger

	Debug(ctx context.Context, msg string, fields ...Field)
	Info(ctx context.Context, msg string, fields ...Field)
	Warn(ctx context.Context, msg string, fields ...Field)
	Error(ctx context.Context, msg string, fields ...Field)
	DPanic(ctx context.Context, msg string, fields ...Field)
	Panic(ctx context.Context, msg string, fields ...Field)
	Fatal(ctx context.Context, msg string, fields ...Field)

	Sync() error
}

// New create a new logger by zap.
func New(c *Config) Logger {
	err := c.initOptions()
	if err != nil {
		panic(fmt.Errorf("fail to init config: %v", err))
	}

	var zapLogger *zap.Logger
	if c.level == zap.DebugLevel || c.level == zap.ErrorLevel {
		zapLogger = zap.New(getEncoderCore(c), zap.AddStacktrace(c.level))
	} else {
		zapLogger = zap.New(getEncoderCore(c))
	}

	if c.ShowLine {
		zapLogger = zapLogger.WithOptions(zap.AddCaller())
	}

	return &logger{c: c, zapLogger: zapLogger}
}

func (l *logger) WithFields(fields ...Field) Logger {
	merged := make([]Field, 0, len(l.prefix)+len(fields))
	merged = append(merged, l.prefix...)
	merged = append(merged, fields...)
	return &logger{
		c:         l.c,
		zapLogger: l.zapLogger,
		prefix:    merged,
	}
}

// Debug logs a message at DebugLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (l *logger) Debug(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, l.prefix...)
	l.zapLogger.Debug(msg, fields...)
}

// Info logs a message at InfoLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (l *logger) Info(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, l.prefix...)
	l.zapLogger.Info(msg, fields...)
}

// Warn logs a message at WarnLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (l *logger) Warn(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, l.prefix...)
	l.zapLogger.Warn(msg, fields...)
}

// Error logs a message at ErrorLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (l *logger) Error(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, l.prefix...)
	l.zapLogger.Error(msg, fields...)
}

// DPanic logs a message at DPanicLevel. The message includes any fields
// passed at the log site, as well as any fields accumulated on the logger.
//
// If the logger is in development mode, it then panics (DPanic means
// "development panic"). This is useful for catching errors that are
// recoverable, but shouldn't ever happen.
func (l *logger) DPanic(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, l.prefix...)
	l.zapLogger.DPanic(msg, fields...)
}

// Panic logs a message at PanicLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then panics, even if logging at PanicLevel is disabled.
func (l *logger) Panic(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, l.prefix...)
	l.zapLogger.Panic(msg, fields...)
}

// Fatal logs a message at FatalLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then calls os.Exit(1), even if logging at FatalLevel is
// disabled.
func (l *logger) Fatal(ctx context.Context, msg string, fields ...Field) {
	fields = initTraceField(ctx, fields)
	fields = append(fields, l.prefix...)
	l.zapLogger.Fatal(msg, fields...)
}

// Sync calls the underlying Core's Sync method, flushing any buffered log
// entries. Applications should take care to call Sync before exiting.
func (l *logger) Sync() error {
	return l.zapLogger.Sync()
}
// getEncoderCore
func getEncoderCore(c *Config) (core zapcore.Core) {
	writer, err := GetWriteSyncer(c) // add file-rotatelogs hook
	if err != nil {
		panic(fmt.Errorf("get Write Syncer Failed err:%v", err.Error()))
	}
	return zapcore.NewCore(getEncoder(c), writer, c.level)
}

// getEncoder get text encoder.
func getEncoder(c *Config) zapcore.Encoder {
	if c.TextEncoder == "json" {
		return zapcore.NewJSONEncoder(getEncoderConfig(c))
	}
	return zapcore.NewConsoleEncoder(getEncoderConfig(c))
}

// getEncoderConfig get zapcore.EncoderConfig.
func getEncoderConfig(c *Config) (encoderConfig zapcore.EncoderConfig) {
	// custom time format
	var CustomTimeEncoder = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
		enc.AppendString(t.Format(c.TimeFormat))
	}

	encoderConfig = zapcore.EncoderConfig{
		MessageKey:     c.MessageKey,
		LevelKey:       c.LevelKey,
		TimeKey:        c.TimeKey,
		NameKey:        c.NameKey,
		CallerKey:      c.CallerKey,
		StacktraceKey:  c.StacktraceKey,
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     CustomTimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.FullCallerEncoder,
	}
	switch {
	case c.EncodeLevel == LowercaseLevelEncoder:
		encoderConfig.EncodeLevel = zapcore.LowercaseLevelEncoder
	case c.EncodeLevel == LowercaseColorLevelEncoder:
		encoderConfig.EncodeLevel = zapcore.LowercaseColorLevelEncoder
	case c.EncodeLevel == CapitalLevelEncoder:
		encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	case c.EncodeLevel == CapitalColorLevelEncoder:
		encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
	default:
		encoderConfig.EncodeLevel = zapcore.LowercaseLevelEncoder
	}
	return encoderConfig
}
// GetWriteSyncer add file-rotatelogs hook
func GetWriteSyncer(c *Config) (zapcore.WriteSyncer, error) {
	if c.Path != "" {
		var bathLogPath, bathLinkPath string
		if c.FilePrefix != "" {
			bathLogPath = path.Join(c.Path, fmt.Sprintf("%v.%v", c.FilePrefix, c.FileFormat))
			bathLinkPath = path.Join(c.Path, fmt.Sprintf("%v.log", c.FilePrefix))
		} else {
			bathLogPath = path.Join(c.Path, c.FileFormat)
			bathLinkPath = path.Join(c.Path, DefaultLinkName)
		}

		fileWriter, err := rotatelogs.New(
			bathLogPath,
			rotatelogs.WithLinkName(bathLinkPath),
			rotatelogs.WithMaxAge(toDuration(c.FileMaxAge)),
			rotatelogs.WithRotationTime(toDuration(c.FileRotationTime)),
			rotatelogs.WithLocation(c.timezone),
		)
		if err != nil {
			return nil, err
		}

		if c.LogInConsole {
			return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(fileWriter)), nil
		}
		return zapcore.AddSync(fileWriter), nil
	} else {
		return zapcore.AddSync(zapcore.AddSync(os.Stdout)), nil
	}
}
type traceIDKey struct{}

func NewTraceIDContext(ctx context.Context, traceID string) context.Context {
	return context.WithValue(ctx, traceIDKey{}, traceID)
}

func FromTraceID(ctx context.Context) (string, bool) {
	v := ctx.Value(traceIDKey{})
	if v != nil {
		if s, ok := v.(string); ok {
			return s, s != ""
		}
	}
	return "", false
}

type CustomerIdKey struct{}

func NewCustomerIdContext(ctx context.Context, customerId int64) context.Context {
	return context.WithValue(ctx, CustomerIdKey{}, customerId)
}

func FromCustomerId(ctx context.Context) (int64, bool) {
	v := ctx.Value(CustomerIdKey{})
	if v != nil {
		if s, ok := v.(int64); ok {
			return s, s != 0
		}
	}
	return 0, false
}
func toDuration(s int64) time.Duration {
	return time.Duration(s) * time.Second
}

func initTraceField(ctx context.Context, fields []Field) []Field {
	traceID, ok := FromTraceID(ctx)
	if ok {
		fields = append(fields, String(DefaultTraceKey, traceID))
	}
	fields = append(fields, String(DefaultServiceIdKey, id))
	return fields
}

调用 main.go

// init log
xlog.Init(conf.Conf.Log) //配置读取根据自己情况
xlog.WithFields(xlog.String("log.index", "app")) //自定义 

配置toml文件,根据自己情况

[log]
    path = "runtime/logs/"
    fileFormat = "log.%Y%m%d.%H"
    textEncoder = "json"
    fileMaxAge = 604800
    fileRotationTime = 3600
    timezone = "UTC"

标签:...,field,fields,constructs,Field,go,日志,zap
From: https://www.cnblogs.com/qcy-blog/p/18189460

相关文章

  • Go-X1
    Go语言Let`sGo... 1.下载安装Go安装包下载地址为:https://go.dev/dl/。如果打不开可以使用这个地址:https://golang.google.cn/dl/。各个系统对应的包名操作系统包名Windowsgo1.4.windows-amd64.msiLinuxgo1.4.linux-amd64.tar.gzMacgo1.4.darwin-amd64-os......
  • 配置cisco asa 5525k9防火墙的日志保存到服务器
    配置ciscoasa5525k9防火墙的日志信息日志信息可以输出到LogBuffer(日志缓冲区)、ASDM和日志服务器。1.配置Logbuffer: loggingenable #启用日志功能 loggingbufferedinformational  #Cisco日志等级一共分为8级,0级最高,7级最低 showlogging  #查看LogBuff......
  • PyAlgoTrade-0-20-中文文档-一-
    PyAlgoTrade0.20中文文档(一)介绍原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/intro.htmlPyAlgoTrade是一个支持事件驱动的算法交易Python库,支持:使用来自CSV文件的历史数据进行回测。使用Bitstamp实时数据进行模拟交易。在Bitstamp上进行真实交易。......
  • PyAlgoTrade-0-20-中文文档-四-
    PyAlgoTrade0.20中文文档(四)SMA交叉原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/sample_sma_crossover.html将此代码保存为sma_crossover.py:frompyalgotradeimportstrategyfrompyalgotrade.technicalimportmafrompyalgotrade.technicalimportcrosscl......
  • PyAlgoTrade-0-20-中文文档-三-
    PyAlgoTrade0.20中文文档(三)工具原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/tools.htmlQuandlpyalgotrade.tools.quandl.``build_feed(sourceCode,tableCodes,fromYear,toYear,storage,frequency=86400,timezone=None,skipErrors=False,authToken=None,columnNames={......
  • PyAlgoTrade-0-20-中文文档-二-
    PyAlgoTrade0.20中文文档(二)经纪人-订单管理类原文:gbeced.github.io/pyalgotrade/docs/v0.20/html/broker.html基础模块和类类pyalgotrade.broker.``Order(type_,action,instrument,quantity,instrumentTraits)基类:object订单的基类。参数:type(Order.Type)–订单类......
  • 探索Django:从项目创建到图片上传的全方位指南
    Django是什么Django是一个流行的PythonWeb开发框架,它提供了一系列工具和库,用于帮助开发人员构建高效、可扩展的Web应用程序。Django的目标是让开发者能够以快速和简单的方式构建复杂的Web应用,通过提供许多预构建的组件和功能,如ORM(对象关系映射)、表单处理、认证系统、管......
  • Dockerfile - build zgrpc-go-professionals:client
     FROM--platform=$BUILDPLATFORMalpineasprotocARGBUILDPLATFORM=linux/amd64TARGETOS=linuxTARGETARCH=amd64#downloadtheprotocbinaryfromgithub#Weunzipthefileinto/usr/local.Noticethatweareextractingboththeprotoc#binary(/bin/pr......
  • Go语言异常处理:自定义错误【errors.New+panic】
    程序本身抛出的异常信息不是太友好,我们可以自定义错误或者异常的信息,需要使用errors包中的New函数来包装一下异常或错误信息;在使用内置函数panic(err),把异常信息后面的程序执行终止掉,因为再执行后面的程序也没有意义了。 packagemainimport"fmt"import"errors"funcma......
  • ubuntu安装go
    获取安装包,wget后面的下载链接请去golang官网(https://golang.google.cn/dl/)获取你想下载的对应go版本sudowgethttps://golang.google.cn/dl/go1.18.5.linux-amd64.tar.gz#解压文件sudotarxfzgo1.18.5.linux-amd64.tar.gz-C/usr/local修改~/.profile或~/.bashrc......