uniugm/admin/lib/xlog/log.go

256 lines
6.2 KiB
Go
Raw Normal View History

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 {
return LogLevelDebug
}
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
}