|
| 1 | +package logger |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "os" |
| 6 | + "path/filepath" |
| 7 | + "time" |
| 8 | + |
| 9 | + "github.com/natefinch/lumberjack" |
| 10 | + "go.uber.org/zap" |
| 11 | + "go.uber.org/zap/zapcore" |
| 12 | + "google.golang.org/grpc" |
| 13 | + "google.golang.org/grpc/connectivity" |
| 14 | +) |
| 15 | + |
| 16 | +const DefaultLogPath = "/var/agent/" // 默认输出日志文件路径 |
| 17 | +const DefaultLogName = "default.log" |
| 18 | + |
| 19 | +type LogConfigs struct { |
| 20 | + LogLevel string // 日志打印级别 debug info warning error |
| 21 | + LogFormat string // 输出日志格式 logfmt, json |
| 22 | + LogPath string // 输出日志文件路径 |
| 23 | + LogFileName string // 输出日志文件名称 |
| 24 | + LogFileMaxSize int // 【日志分割】单个日志文件最多存储量 单位(mb) |
| 25 | + LogFileMaxBackups int // 【日志分割】日志备份文件最多数量 |
| 26 | + LogMaxAge int // 日志保留时间,单位: 天 (day) |
| 27 | + LogCompress bool // 是否压缩日志 |
| 28 | + LogStdout bool // 是否输出到控制台 |
| 29 | +} |
| 30 | + |
| 31 | +// InitLogger 初始化 log |
| 32 | +func InitLogger(conf LogConfigs) error { |
| 33 | + logLevel := map[string]zapcore.Level{ |
| 34 | + "debug": zapcore.DebugLevel, |
| 35 | + "info": zapcore.InfoLevel, |
| 36 | + "warn": zapcore.WarnLevel, |
| 37 | + "error": zapcore.ErrorLevel, |
| 38 | + } |
| 39 | + |
| 40 | + // init log channel |
| 41 | + logCh = make(chan []byte, 2048) |
| 42 | + |
| 43 | + writeSyncer, err := getLogWriter(conf) // 日志文件配置 文件位置和切割 |
| 44 | + if err != nil { |
| 45 | + return err |
| 46 | + } |
| 47 | + encoder := getEncoder(conf) // 获取日志输出编码 |
| 48 | + level, ok := logLevel[conf.LogLevel] // 日志打印级别 |
| 49 | + if !ok { |
| 50 | + level = logLevel["info"] |
| 51 | + } |
| 52 | + core := zapcore.NewCore(encoder, writeSyncer, level) |
| 53 | + logger := zap.New(core, zap.AddCaller()) // zap.Addcaller() 输出日志打印文件和行数如: logger/logger_test.go:33 |
| 54 | + // 1. zap.ReplaceGlobals 函数将当前初始化的 logger 替换到全局的 logger, |
| 55 | + // 2. 使用 logger 的时候 直接通过 zap.S().Debugf("xxx") or zap.L().Debug("xxx") |
| 56 | + // 3. 使用 zap.S() 和 zap.L() 提供全局锁,保证一个全局的安全访问logger的方式 |
| 57 | + zap.ReplaceGlobals(logger) |
| 58 | + //zap.L().Debug("") |
| 59 | + //zap.S().Debugf("") |
| 60 | + return nil |
| 61 | +} |
| 62 | + |
| 63 | +// getEncoder 编码器(如何写入日志) |
| 64 | +func getEncoder(conf LogConfigs) zapcore.Encoder { |
| 65 | + |
| 66 | + encoderConfig := zap.NewProductionEncoderConfig() |
| 67 | + |
| 68 | + customTimeEncoder := func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { |
| 69 | + enc.AppendString(t.Format("2006-01-02 15:04:05.000")) |
| 70 | + } |
| 71 | + encoderConfig.EncodeTime = customTimeEncoder // log 时间格式 例如: 2021-09-11t20:05:54.852+0800 |
| 72 | + encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // 输出level序列化为全大写字符串,如 INFO DEBUG ERROR |
| 73 | + //encoderConfig.EncodeCaller = zapcore.FullCallerEncoder |
| 74 | + //encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder |
| 75 | + if conf.LogFormat == "json" { |
| 76 | + return zapcore.NewJSONEncoder(encoderConfig) // 以json格式写入 |
| 77 | + } |
| 78 | + return zapcore.NewConsoleEncoder(encoderConfig) // 以logfmt格式写入 |
| 79 | +} |
| 80 | + |
| 81 | +// getLogWriter 获取日志输出方式 日志文件 控制台 |
| 82 | +func getLogWriter(conf LogConfigs) (zapcore.WriteSyncer, error) { |
| 83 | + |
| 84 | + // 判断日志路径是否存在,如果不存在就创建 |
| 85 | + if exist := IsExist(conf.LogPath); !exist { |
| 86 | + if conf.LogPath == "" { |
| 87 | + conf.LogPath = DefaultLogPath |
| 88 | + } |
| 89 | + if conf.LogFileName == "" { |
| 90 | + conf.LogFileName = DefaultLogName |
| 91 | + } |
| 92 | + if err := os.MkdirAll(conf.LogPath, os.ModePerm); err != nil { |
| 93 | + conf.LogPath = DefaultLogPath |
| 94 | + if err := os.MkdirAll(conf.LogPath, os.ModePerm); err != nil { |
| 95 | + return nil, err |
| 96 | + } |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + // 日志文件 与 日志切割 配置 |
| 101 | + lumberJackLogger := &lumberjack.Logger{ |
| 102 | + Filename: filepath.Join(conf.LogPath, conf.LogFileName), // 日志文件路径 |
| 103 | + MaxSize: conf.LogFileMaxSize, // 单个日志文件最大多少 mb |
| 104 | + MaxBackups: conf.LogFileMaxBackups, // 日志备份数量 |
| 105 | + MaxAge: conf.LogMaxAge, // 日志最长保留时间 |
| 106 | + Compress: conf.LogCompress, // 是否压缩日志 |
| 107 | + } |
| 108 | + |
| 109 | + // 日志同时输出到控制台、日志文件和grpc log中 |
| 110 | + var writeSyncers []zapcore.WriteSyncer |
| 111 | + writeSyncers = append(writeSyncers, zapcore.AddSync(os.Stdout)) |
| 112 | + writeSyncers = append(writeSyncers, zapcore.AddSync(lumberJackLogger)) |
| 113 | + |
| 114 | + grpcWrite := zapcore.AddSync(&GrpcLogChan{}) |
| 115 | + writeSyncers = append(writeSyncers, grpcWrite) |
| 116 | + return zapcore.NewMultiWriteSyncer(writeSyncers...), nil |
| 117 | + |
| 118 | + // if conf.LogStdout { |
| 119 | + // // 日志同时输出到控制台和日志文件中 |
| 120 | + // return zapcore.NewMultiWriteSyncer(zapcore.AddSync(lumberJackLogger), zapcore.AddSync(os.Stdout)), nil |
| 121 | + // } else { |
| 122 | + // // 日志只输出到日志文件 |
| 123 | + // return zapcore.AddSync(lumberJackLogger), nil |
| 124 | + // } |
| 125 | +} |
| 126 | + |
| 127 | +// IsExist 判断文件或者目录是否存在 |
| 128 | +func IsExist(path string) bool { |
| 129 | + _, err := os.Stat(path) |
| 130 | + return err == nil || os.IsExist(err) |
| 131 | +} |
| 132 | + |
| 133 | +type GrpcLogChan struct { |
| 134 | +} |
| 135 | + |
| 136 | +var logCh chan []byte |
| 137 | + |
| 138 | +func (w *GrpcLogChan) Write(p []byte) (n int, err error) { |
| 139 | + d := make([]byte, len(p)) |
| 140 | + copy(d, p) |
| 141 | + select { |
| 142 | + case logCh <- d: |
| 143 | + default: |
| 144 | + } |
| 145 | + |
| 146 | + return |
| 147 | +} |
| 148 | + |
| 149 | +func (w *GrpcLogChan) Sync() error { |
| 150 | + return nil |
| 151 | +} |
| 152 | + |
| 153 | +func SendLogToServerTask(ctx context.Context, grpcConn *grpc.ClientConn) error { |
| 154 | + // log server client |
| 155 | + //client := pb.NewServicesClient(grpcConn) |
| 156 | + |
| 157 | + for { |
| 158 | + select { |
| 159 | + case <-ctx.Done(): |
| 160 | + zap.S().Warn("send log to server task ctx done, Bye...") |
| 161 | + return nil |
| 162 | + case v := <-logCh: |
| 163 | + /* |
| 164 | + if grpcConn.GetState() == connectivity.Ready { |
| 165 | + msgHdr := pb.ReqHeader{ |
| 166 | + Time: common.GetCurrUnixTimestamp(), |
| 167 | + HostId: common.HostAgent.HostId, |
| 168 | + AgentId: common.HostAgent.AgentId, |
| 169 | + AgentVersion: common.HostAgent.AgentVersion, |
| 170 | + AgentToken: common.HostAgent.AgentToken, |
| 171 | + } |
| 172 | + msg := pb.ReportLogReq{ |
| 173 | + ReqHdr: &msgHdr, |
| 174 | + LogData: string(v), |
| 175 | + } |
| 176 | + client.ReportLog(ctx, &msg) |
| 177 | + } |
| 178 | + */ |
| 179 | + } |
| 180 | + } |
| 181 | + return nil |
| 182 | + |
| 183 | +} |
0 commit comments