package initialize
import (
"encoding/json"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"golang.org/x/net/context"
"gopkg.in/natefinch/lumberjack.v2"
"notification_service/global"
"os"
"time"
)
func InitLogger() {
development := os.Getenv("DEVELOPMENT")
if development == "1" { // 如果是开发环境
initDevelopmentLogger()
} else {
initProductionLogger()
}
}
func initDevelopmentLogger() {
config := zap.NewDevelopmentConfig()
logger, err := config.Build(zap.AddCaller())
if err != nil {
panic(err)
}
zap.ReplaceGlobals(logger)
}
func initProductionLogger() {
encoderConfig := zap.NewProductionEncoderConfig() // 获取编码器
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder // 使用 ISO-8601 时间格式
encoderConfig.TimeKey = "time"
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // 日志级别记为大写
encoder := zapcore.NewJSONEncoder(encoderConfig) // NewJSONEncoder:json 格式输出。如果是 NewConsoleEncoder,则以字符串格式输出
infoLogLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { // 该日志等级函数记录 INFO 及以上级别的日志
return lvl >= zap.InfoLevel
})
errorLogLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { // 该日志等级函数记录 ERROR 及以上级别的日志
return lvl >= zap.ErrorLevel
})
infoFileSyncer := zapcore.AddSync(&lumberjack.Logger{
Filename: "./log/info.log", // 日志文件存放目录,如果目录不存在会自动创建
MaxSize: 50, // 文件大小限制,单位:MB
MaxBackups: 200, // 最大保留日志文件数量
MaxAge: 180, // 日志文件保留天数
Compress: false, // 是否压缩处理
})
errorFileSyncer := zapcore.AddSync(&lumberjack.Logger{
Filename: "./log/error.log",
MaxSize: 50,
MaxBackups: 200,
MaxAge: 180,
Compress: false,
})
redisSyncer := zapcore.AddSync(&RedisLogger{}) // 日志存入 Redis
infoCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(infoFileSyncer, redisSyncer), infoLogLevel)
errorCore := zapcore.NewCore(encoder, errorFileSyncer, errorLogLevel)
logger := zap.New(zapcore.NewTee(infoCore, errorCore), zap.AddCaller()) // zap.AddCaller():显示文件名和行号
zap.ReplaceGlobals(logger) // 替换全局 logger
}
type RedisLogger struct{} // 需要实现 io.Writer 接口
func (*RedisLogger) Write(p []byte) (n int, err error) { // 实现 io.Writer 接口即实现 Write 方法
log := string(p)
if gjson.Get(log, "trace_id").String() == "" { // 如果日志中不包含 trace_id
return
}
var redisLog string
if gjson.Get(log, "log_type").String() == "access_log" {
type AccessLog struct {
TraceID string `json:"trace_id,omitempty"`
Time string `json:"time,omitempty"`
Timestamp int64 `json:"timestamp,omitempty"`
LogType string `json:"log_type,omitempty"`
ClientID string `json:"client_id,omitempty"`
RequestURI string `json:"request_uri,omitempty"`
RequestMethod string `json:"request_method,omitempty"`
RequestHeaders string `json:"request_headers,omitempty"`
RequestBody string `json:"request_body,omitempty"`
ResponseBody string `json:"response_body,omitempty"`
NotificationType string `json:"notification_type,omitempty"`
Receivers []string `json:"receivers,omitempty"`
}
accessLog := AccessLog{}
_ = json.Unmarshal(p, &accessLog)
t, _ := time.ParseInLocation("2006-01-02T15:04:05+0800", accessLog.Time, time.Local)
accessLog.Time = ""
accessLog.Timestamp = t.UnixMilli()
redisLogBytes, _ := json.Marshal(accessLog)
redisLog = string(redisLogBytes)
} else {
redisLog, _ = sjson.Set(redisLog, "trace_id", gjson.Get(log, "trace_id").String())
t, _ := time.ParseInLocation("2006-01-02T15:04:05+0800", gjson.Get(log, "time").String(), time.Local)
redisLog, _ = sjson.Set(redisLog, "timestamp", t.UnixMilli())
redisLog, _ = sjson.Set(redisLog, "log_type", "exec_log")
log, _ = sjson.Delete(log, "level")
log, _ = sjson.Delete(log, "time")
log, _ = sjson.Delete(log, "caller")
log, _ = sjson.Delete(log, "msg")
log, _ = sjson.Delete(log, "trace_id")
redisLog, _ = sjson.Set(redisLog, "log_content", log)
}
global.Redis.RPush(context.Background(), "notification_service_log", redisLog)
return
}