2 Star 0 Fork 0

TeamsHub/backend-gopkg

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
logger.go 11.53 KB
一键复制 编辑 原始数据 按行查看 历史
wuzheng0709 提交于 2024-08-04 19:14 . fix mod
package logger
import (
"fmt"
"gitee.com/wuzheng0709/backend-gopkg/infrastructure/config"
"gitee.com/wuzheng0709/backend-gopkg/infrastructure/connector/kafka"
"github.com/IBM/sarama"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
"io"
"os"
"strings"
"time"
)
// 日志并发执行
//var LogPushSls, _ = ants.NewPool(5000, ants.WithPreAlloc(true))
type Logger struct {
Config *Config
zapSugar *zap.SugaredLogger
}
func New(conf *Config) *Logger {
if conf == nil {
conf = defaultConfig()
//config.EnableFileOut()
conf.DisableFileOut() // 关闭日志文件输出
}
logger := &Logger{
Config: conf,
}
// 根据环境设置 输出格式
logger.Config.jsonFormat = true
logger.Config.consoleOut = true
// 设置 logger
logger.WithConfig(config.C.Debug, true)
return logger
}
func (l *Logger) getFileWriter() (infoWriter io.Writer, warnWriter io.Writer) {
// 获取 info、warn日志文件的io.Writer 抽象 getWriter() 在下方实现
loggerPath := l.Config.fileOut.path
appName := l.Config.name
if loggerPath == "" || strings.EqualFold(l.Config.envMode, "dev") {
address, _ := os.Getwd()
loggerPath = address + "/logs"
}
// 检查文件夹是否存在
isExist := CheckFileAndCreate(loggerPath)
if isExist != nil {
panic("[文件夹不存在] " + loggerPath)
}
warnWriterFileName := loggerPath + "/common-error.log"
if len(appName) > 0 {
warnWriterFileName = loggerPath + "/" + appName + "-common-error.log"
}
infoWriter = getWriter(loggerPath+"/"+appName+".log",
l.Config.fileOut.rotationTime,
l.Config.fileOut.maxAge)
warnWriter = getWriter(warnWriterFileName,
l.Config.fileOut.rotationTime,
l.Config.fileOut.maxAge)
return
}
func (l *Logger) generateEncoderConfig() zapcore.EncoderConfig {
// 自定义时间输出格式
customTimeEncoder := func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format(logTmFmtWithMS))
}
//// 自定义日志级别显示
//customLevelEncoder := func(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
// var levelStr = "[" + level.CapitalString() + "]"
// if l.Config.colorful {
// switch level.CapitalString() {
// case "INFO":
// levelStr = Green + levelStr + Reset
// break
// case "WARN", "DEBUG":
// levelStr = Magenta + levelStr + Reset
// break
// case "ERROR", "PANIC":
// levelStr = Red + levelStr + Reset
// break
// }
// }
// enc.AppendString(levelStr)
//}
//// 自定义文件:行号输出项
//encodeCaller := zapcore.FullCallerEncoder
//if !strings.EqualFold(l.Config.envMode, "prod") {
// encodeCaller = zapcore.ShortCallerEncoder // 只显示 package/file.go:line
//}
// 设置一些基本日志格式 具体含义还比较好理解,直接看zap源码也不难懂
return zapcore.EncoderConfig{
MessageKey: "msg",
LevelKey: "level",
TimeKey: "ts",
CallerKey: "file",
FunctionKey: zapcore.OmitKey,
NameKey: "logger",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding, // 默认换行符"\n"
EncodeLevel: zapcore.LowercaseLevelEncoder, // 日志等级序列为小写字符串,如:InfoLevel被序列化为 "info"
EncodeTime: customTimeEncoder, // 日志时间格式显示
EncodeDuration: zapcore.SecondsDurationEncoder, // 时间序列化,Duration为经过的浮点秒数
EncodeCaller: zapcore.ShortCallerEncoder, // 日志行号显示
EncodeName: zapcore.FullNameEncoder,
}
}
type LogKafka struct {
Topic string
Producer sarama.SyncProducer
Partition int32
}
func (lk *LogKafka) Write(p []byte) (n int, err error) {
// 构建消息
var envName string
if config.C.Debug {
envName = "测试环境"
} else {
envName = "生产环境"
}
msg := &sarama.ProducerMessage{
Key: sarama.StringEncoder(config.C.Service.Name + "_" + envName),
Topic: lk.Topic,
Value: sarama.ByteEncoder(p),
Partition: lk.Partition,
}
// 发现消息
_, _, err = lk.Producer.SendMessage(msg)
if err != nil {
return
}
return
}
// 根据配置文件更新 logger
func (l *Logger) WithConfig(isDebug bool, kafkaSwitch bool) {
var (
err error
allCore []zapcore.Core
)
// 生成 encoderConfig
encoderConfig := l.generateEncoderConfig()
var encoder zapcore.Encoder
if !l.Config.jsonFormat {
encoder = zapcore.NewConsoleEncoder(encoderConfig)
} else {
encoder = zapcore.NewJSONEncoder(encoderConfig)
}
// 设置级别
logLevel := convertLevel(l.Config.level)
// 实现两个判断日志等级的interface
infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl < zapcore.WarnLevel && lvl >= logLevel
})
warnLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl >= zapcore.WarnLevel && lvl >= logLevel
})
var infoWs []zapcore.WriteSyncer
var warnWs []zapcore.WriteSyncer
// 是否开启输出文件
if l.Config.fileOut != nil {
info, warn := enableFileOut(l.getFileWriter())
infoWs = append(infoWs, info)
warnWs = append(warnWs, warn)
}
// 控制台输出
if l.Config.consoleOut {
info, warn := enableConsoleOut()
infoWs = append(infoWs, info)
warnWs = append(warnWs, warn)
}
// 不能同时关闭两种输出方式,否则将开启控制台输出
if l.Config.fileOut == nil && !l.Config.consoleOut {
l.Warn("You cannot turn off both output modes at the same time!!!")
info, warn := enableConsoleOut()
infoWs = append(infoWs, info)
warnWs = append(warnWs, warn)
}
wsInfo := zapcore.NewMultiWriteSyncer(infoWs...)
wsWarn := zapcore.NewMultiWriteSyncer(warnWs...)
// 日志是输出终端
if isDebug {
consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
allCore = append(allCore, zapcore.NewCore(consoleEncoder, zapcore.Lock(os.Stdout), zapcore.DebugLevel))
}
if kafkaSwitch { // 日志输出kafka
// kafka连接
var kl LogKafka
kl.Topic = config.C.Service.Name // Topic(话题):Kafka中用于区分不同类别信息的类别名称。由producer指定
kl.Partition = 1 // Partition(分区):Topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)
kl.Producer, err = kafka.GetkafkaProduct()
if err != nil {
panic(fmt.Sprintf("connect kafka failed: %+v\n", err))
}
writeSyncer := zapcore.AddSync(&kl)
allCore = append(allCore, zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel))
} else { // 日志输出file
writeSyncer := getLumberJackWriter()
allCore = append(allCore, zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel))
}
allCore = append(allCore, zapcore.NewCore(encoder, wsInfo, infoLevel))
allCore = append(allCore, zapcore.NewCore(encoder, wsWarn, warnLevel))
core := zapcore.NewTee(allCore...)
// 开启开发模式,堆栈跟踪 需要传入 zap.AddCaller() 才会显示打日志点的文件名和行数, 有点小坑
caller := zap.AddCaller()
// 防止zap始终将包装器代码报告为调用者( 需要跳过一个级别,否则打印的文件名和行号 是封装的文件名)
skip := zap.AddCallerSkip(l.Config.skip)
zapLog := zap.New(core, caller, skip)
//var cfg = zapsentry.Configuration{
//
// Level: zapcore.ErrorLevel, // 发送日志级别
//
// EnableBreadcrumbs: true,
//
// BreadcrumbLevel: zapcore.ErrorLevel,
//}
//
//sentryDsn := config.C.Sentry // DSN:sentry创建golang项目会提供
//
//core, err := zapsentry.NewCore(cfg, zapsentry.NewSentryClientFromDSN(sentryDsn))
//zapLog = zapLog.With(zapsentry.NewScope())
//if err != nil {
//
// zapLog.Warn("failed to init zap", zap.Error(err))
//
//}
defer zapLog.Sync()
//l.zapSugar = zapsentry.AttachCoreToLogger(core, zapLog).Sugar()
l.zapSugar = zapLog.Sugar().With()
}
func getLumberJackWriter() zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{
Filename: "./test.log", // 日志文件位置
MaxSize: 1, // 进行切割之前,日志文件最大值(单位:MB),默认100MB
MaxBackups: 5, // 保留旧文件的最大个数
MaxAge: 1, // 保留旧文件的最大天数
Compress: false, // 是否压缩/归档旧文件
}
return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(lumberJackLogger))
}
// With adds a variadic number of fields to the logging context.
// see https://github.com/uber-go/zap/blob/v1.10.0/sugar.go#L91
func (l *Logger) With(args ...interface{}) *Logger {
l.zapSugar = l.zapSugar.With(args...)
return l
}
// Debug package sugar of zap
func (l *Logger) Debug(args ...interface{}) {
l.zapSugar.Debug(args...)
NewSlsLogFormPrint(zapcore.DebugLevel.String(), args...)
}
// Debugf package sugar of zap
func (l *Logger) Debugf(template string, args ...interface{}) {
l.zapSugar.Debugf(template, args...)
NewSlsLogFormPrintf(zapcore.DebugLevel.String(), template, args...)
}
// Info package sugar of zap
func (l *Logger) Info(args ...interface{}) {
l.zapSugar.Info(args...)
NewSlsLogFormPrint(zapcore.InfoLevel.String(), args...)
}
// Infof package sugar of zap
func (l *Logger) Infof(template string, args ...interface{}) {
l.zapSugar.Infof(template, args...)
NewSlsLogFormPrintf(zapcore.InfoLevel.String(), template, args...)
}
// Warn package sugar of zap
func (l *Logger) Warn(args ...interface{}) {
l.zapSugar.Warn(args...)
NewSlsLogFormPrint(zapcore.WarnLevel.String(), args...)
}
// Warnf package sugar of zap
func (l *Logger) Warnf(template string, args ...interface{}) {
l.zapSugar.Warnf(template, args...)
NewSlsLogFormPrintf(zapcore.WarnLevel.String(), template, args...)
}
// Error package sugar of zap
func (l *Logger) Error(args ...interface{}) {
l.zapSugar.Error(args...)
NewSlsLogFormPrint(zapcore.ErrorLevel.String(), args...)
}
// Errorf package sugar of zap
func (l *Logger) Errorf(template string, args ...interface{}) {
l.zapSugar.Errorf(template, args...)
NewSlsLogFormPrintf(zapcore.ErrorLevel.String(), template, args...)
}
// Fatal package sugar of zap
func (l *Logger) Fatal(args ...interface{}) {
l.zapSugar.Fatal(args...)
NewSlsLogFormPrint(zapcore.FatalLevel.String(), args...)
}
// Fatalf package sugar of zap
func (l *Logger) Fatalf(template string, args ...interface{}) {
l.zapSugar.Fatalf(template, args...)
NewSlsLogFormPrintf(zapcore.FatalLevel.String(), template, args...)
}
// Panic package sugar of zap
func (l *Logger) Panic(args ...interface{}) {
l.zapSugar.Panic(args...)
NewSlsLogFormPrint(zapcore.PanicLevel.String(), args...)
}
// Panicf package sugar of zap
func (l *Logger) Panicf(template string, args ...interface{}) {
l.zapSugar.Panicf(template, args...)
NewSlsLogFormPrintf(zapcore.PanicLevel.String(), template, args...)
}
func NewSlsLogFormPrint(logLevel string, args ...interface{}) {
//logC := fmt.Sprint(args...)
//nowTime := time.Now().Unix()
////if err := LogPushSls.Submit(publiPutLog(logLevel, logC, nowTime)); err != nil {
//// fmt.Println(err.Error())
////}
//publiPutLog(logLevel, logC, nowTime)
return
}
func NewSlsLogFormPrintf(logLevel, template string, args ...interface{}) {
//logC := fmt.Sprintf(template, args...)
//nowTime := time.Now().Unix()
////if err := LogPushSls.Submit(publiPutLog(logLevel, logC, nowTime)); err != nil {
//// fmt.Println(err.Error())
////}
//publiPutLog(logLevel, logC, nowTime)
return
}
//func publiPutLog(logLevel, logC string, nowTime int64) {
// var slsLog slsLog.SlsLogFormt
// slsLog.LogLevel = logLevel
// var resMap map[string]any
// json.Unmarshal([]byte(logC), &resMap)
// if len(resMap) != 0 {
// slsLog.LogContent = resMap
// } else {
// slsLog.LogContent = logC
// }
// slsLog.PrintLogToSls(nowTime)
//}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/wuzheng0709/backend-gopkg.git
git@gitee.com:wuzheng0709/backend-gopkg.git
wuzheng0709
backend-gopkg
backend-gopkg
v1.6.6

搜索帮助