2025-04-18 17:17:23 +08:00
|
|
|
|
package xlog
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"os"
|
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
|
|
"github.com/rs/zerolog"
|
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type LogLevel = zerolog.Level
|
|
|
|
|
type LogEvent = zerolog.Event
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
LogLevelTrace = zerolog.TraceLevel // 追踪日志,调试完毕需要删除
|
|
|
|
|
LogLevelDebug = zerolog.DebugLevel // 调试日志,可以放在代码中,线上出问题调成这个级别
|
|
|
|
|
LogLevelInfo = zerolog.InfoLevel // 正常关键逻辑记录信息,线上日常设置为这个级别
|
|
|
|
|
LogLevelNotice = zerolog.Level(99) // 系统关键节点时输出的留意日志
|
|
|
|
|
LogLevelWarn = zerolog.WarnLevel // 警告,某些逻辑出现意向不到的情况,输出告警,例如配置表错误、rpc错误
|
|
|
|
|
LogLevelError = zerolog.ErrorLevel // 错误,服务器重要组件出现意向不到的情况,输出错误,例如数据库、redis错误
|
|
|
|
|
LogLevelCriti = zerolog.Level(100) // 危急,用于需要开发注意的信息,例如崩溃但不影响服务器运行的栈日志,一般接上sms、im告警
|
|
|
|
|
LogLevelFatal = zerolog.FatalLevel // 致命,核心组建出问题,无法运行,输出告警,并以1的错误码退出
|
|
|
|
|
LogLevelPanic = zerolog.PanicLevel // 崩溃,核心组建出问题,无法运行,崩溃退出
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var LogLevelStr2Enum = map[string]LogLevel{
|
|
|
|
|
"trace": LogLevelTrace,
|
|
|
|
|
"debug": LogLevelDebug,
|
|
|
|
|
"info": LogLevelInfo,
|
|
|
|
|
"notice": LogLevelNotice,
|
|
|
|
|
"warn": LogLevelWarn,
|
|
|
|
|
"error": LogLevelError,
|
|
|
|
|
"criti": LogLevelCriti,
|
|
|
|
|
"fatal": LogLevelFatal,
|
|
|
|
|
"panic": LogLevelPanic,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
// 设置时间格式
|
|
|
|
|
zerolog.TimeFieldFormat = "06/01/02 15:04:05.000"
|
|
|
|
|
// 修改level字段key,防止跟调用方的key一样
|
|
|
|
|
zerolog.LevelFieldName = "log_level"
|
|
|
|
|
// 修改时间key
|
|
|
|
|
zerolog.TimestampFieldName = "log_time"
|
|
|
|
|
// 设置调用文件名路径深度
|
|
|
|
|
zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
|
|
|
|
|
depth := 1
|
|
|
|
|
for i := len(file) - 1; i > 0; i-- {
|
|
|
|
|
if file[i] == '/' {
|
|
|
|
|
if depth == FileReversedDepth {
|
|
|
|
|
file = file[i+1:]
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
depth++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return file + ":" + strconv.Itoa(line)
|
|
|
|
|
}
|
|
|
|
|
// 设置全局日志等级
|
|
|
|
|
zerolog.SetGlobalLevel(LogLevelTrace)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 文件路径保留深度
|
|
|
|
|
var FileReversedDepth = 3
|
|
|
|
|
|
|
|
|
|
func NewGlobalLogger(writers []io.Writer, level LogLevel, initFun func(logger zerolog.Logger) zerolog.Logger) {
|
|
|
|
|
// 设置全局日志等级
|
|
|
|
|
zerolog.SetGlobalLevel(level)
|
|
|
|
|
var parentLogger zerolog.Logger
|
|
|
|
|
|
|
|
|
|
if len(writers) == 0 {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "NewGlobalLogger but write is nil, default give os.Stdout\n")
|
|
|
|
|
writers = append(writers, os.Stdout)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
multi := zerolog.MultiLevelWriter(writers...)
|
|
|
|
|
|
|
|
|
|
// 创建全局日志
|
|
|
|
|
parentLogger = zerolog.New(multi).With().Logger()
|
|
|
|
|
|
|
|
|
|
if initFun != nil {
|
|
|
|
|
log.Logger = initFun(parentLogger)
|
|
|
|
|
} else {
|
|
|
|
|
log.Logger = parentLogger
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Logger = log.Hook(new(PrefixHook))
|
|
|
|
|
globalWriter = multi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewCustomLogger(writer Handler, initFun func(logger *zerolog.Logger) *zerolog.Logger) *zerolog.Logger {
|
|
|
|
|
if writer == nil {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "NewGlobalLogger but write is nil, default give os.Stdout\n")
|
|
|
|
|
writer = os.Stdout
|
|
|
|
|
}
|
|
|
|
|
parentLogger := zerolog.New(writer).With().Logger()
|
|
|
|
|
initFun(&parentLogger)
|
|
|
|
|
return &parentLogger
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var globalWriter io.Writer
|
|
|
|
|
|
|
|
|
|
func GetGlobalWriter() io.Writer {
|
|
|
|
|
if globalWriter == nil {
|
|
|
|
|
return os.Stdout
|
|
|
|
|
}
|
|
|
|
|
return globalWriter
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetSubLogger 获取全局logger的子logger,可以设置子logger的输出格式
|
|
|
|
|
func GetSubLogger() zerolog.Context {
|
|
|
|
|
return log.Logger.With()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func GetLogLevel() LogLevel {
|
|
|
|
|
return zerolog.GlobalLevel()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func SetLogLevel(level LogLevel) {
|
|
|
|
|
zerolog.SetGlobalLevel(level)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ParseLogLevelString(level string) LogLevel {
|
|
|
|
|
lvEnum, find := LogLevelStr2Enum[level]
|
|
|
|
|
if !find {
|
2025-04-22 15:46:48 +08:00
|
|
|
|
return LogLevelTrace
|
2025-04-18 17:17:23 +08:00
|
|
|
|
}
|
|
|
|
|
return lvEnum
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// transFormat
|
|
|
|
|
func transFormat(v ...interface{}) (string, []interface{}) {
|
|
|
|
|
if len(v) == 0 {
|
|
|
|
|
return "empty content", v
|
|
|
|
|
} else {
|
|
|
|
|
formatStr, ok := v[0].(string)
|
|
|
|
|
if ok {
|
|
|
|
|
return formatStr, v[1:]
|
|
|
|
|
}
|
|
|
|
|
formatStr = fmt.Sprint(v...)
|
|
|
|
|
return formatStr, []interface{}{}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Tracef(v ...interface{}) {
|
|
|
|
|
format, v := transFormat(v...)
|
|
|
|
|
output(LogLevelTrace, format, v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Debugf(v ...interface{}) {
|
|
|
|
|
format, v := transFormat(v...)
|
|
|
|
|
output(LogLevelDebug, format, v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Infof(v ...interface{}) {
|
|
|
|
|
format, v := transFormat(v...)
|
|
|
|
|
output(LogLevelInfo, format, v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Noticef(v ...interface{}) {
|
|
|
|
|
format, v := transFormat(v...)
|
|
|
|
|
output(LogLevelNotice, format, v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Warnf(v ...interface{}) {
|
|
|
|
|
format, v := transFormat(v...)
|
|
|
|
|
output(LogLevelWarn, format, v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Errorf(v ...interface{}) {
|
|
|
|
|
format, v := transFormat(v...)
|
|
|
|
|
output(LogLevelError, format, v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Critif(v ...interface{}) {
|
|
|
|
|
format, v := transFormat(v...)
|
|
|
|
|
output(LogLevelCriti, format, v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Fatalf(v ...interface{}) {
|
|
|
|
|
format, v := transFormat(v...)
|
|
|
|
|
output(LogLevelFatal, format, v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func WithLevelEvent(level LogLevel) *LogEvent {
|
|
|
|
|
e := log.WithLevel(level)
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func WithEventMsgF(e *LogEvent, v ...interface{}) {
|
|
|
|
|
format, v := transFormat(v...)
|
|
|
|
|
e.Timestamp().Caller(2).Msgf(format, v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func output(level LogLevel, format string, v ...interface{}) {
|
|
|
|
|
var e *zerolog.Event
|
|
|
|
|
switch level {
|
|
|
|
|
case LogLevelTrace:
|
|
|
|
|
e = log.Trace()
|
|
|
|
|
case LogLevelDebug:
|
|
|
|
|
e = log.Debug()
|
|
|
|
|
case LogLevelInfo:
|
|
|
|
|
e = log.Info()
|
|
|
|
|
case LogLevelNotice:
|
|
|
|
|
e = log.WithLevel(zerolog.NoLevel)
|
|
|
|
|
e.Str("log_level", "notice")
|
|
|
|
|
case LogLevelWarn:
|
|
|
|
|
e = log.Warn()
|
|
|
|
|
case LogLevelError:
|
|
|
|
|
e = log.Error()
|
|
|
|
|
case LogLevelCriti:
|
|
|
|
|
e = log.WithLevel(zerolog.NoLevel)
|
|
|
|
|
e.Str("log_level", "criti")
|
|
|
|
|
case LogLevelFatal:
|
|
|
|
|
e = log.Fatal()
|
|
|
|
|
case LogLevelPanic:
|
|
|
|
|
e = log.Panic()
|
|
|
|
|
default:
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e.Timestamp().Caller(2).Msgf(format, v...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Output(level LogLevel) *zerolog.Event {
|
|
|
|
|
var e *zerolog.Event
|
|
|
|
|
switch level {
|
|
|
|
|
case LogLevelTrace:
|
|
|
|
|
e = log.Trace()
|
|
|
|
|
case LogLevelDebug:
|
|
|
|
|
e = log.Debug()
|
|
|
|
|
case LogLevelInfo:
|
|
|
|
|
e = log.Info()
|
|
|
|
|
case LogLevelNotice:
|
|
|
|
|
e = log.WithLevel(zerolog.NoLevel)
|
|
|
|
|
e.Str("log_level", "notice")
|
|
|
|
|
case LogLevelWarn:
|
|
|
|
|
e = log.Warn()
|
|
|
|
|
case LogLevelError:
|
|
|
|
|
e = log.Error()
|
|
|
|
|
case LogLevelCriti:
|
|
|
|
|
e = log.WithLevel(zerolog.NoLevel)
|
|
|
|
|
e.Str("log_level", "criti")
|
|
|
|
|
case LogLevelFatal:
|
|
|
|
|
e = log.Fatal()
|
|
|
|
|
case LogLevelPanic:
|
|
|
|
|
e = log.Panic()
|
|
|
|
|
default:
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return e
|
|
|
|
|
}
|