Conversation
|
我之前有一些待PR的分支提交(包括上次你PR里会导致部分unit test跑不过等)。估计会有一些冲突,辛苦解决冲突后再提一下呢。抱歉 |
|
done,再看看。每次开发,我会同步这个仓库的代码的,看样子就一个差异点 |
|
PR 方向正确,完成度高。86 个文件的迁移工作量大且机械替换部分无明显遗漏。以下是需要关注的优化点:
type bufferedWriteSyncer struct {
mu sync.Mutex
buffer *bufio.Writer
target zapcore.WriteSyncer
}问题:当 log.flush = false 时,日志写入 buffer 后只有在 Sync() 被调用时才刷盘。如果进程异常退出(SIGKILL / OOM)但不触发 panic 或正常 shutdown,buffer 中的日志将永久丢失。 &zapcore.BufferedWriteSyncer{
WS: fileSyncer,
Size: 32 * 1024,
FlushInterval: 3 * time.Second,
}
func (l *ZapLogger) Panicf(format string, args ...any) {
message := fmt.Sprintf(format, args...)
l.write(zapcore.PanicLevel, message)
_ = l.Sync()
panic(message) // panic value 是 string
}
func (l *ZapLogger) Panic(args ...any) {
message := formatArgs(args...)
l.write(zapcore.PanicLevel, message)
_ = l.Sync()
panic(args) // panic value 是 []any !
}问题:Panic(args ...any) 的 panic value 是 args(一个 slice),而原 log4go 的 Crash(args ...interface{}) 也是 panic(args)。但 Panicf panic 的是 string。这造成了上层 recover 时类型不一致。另外,调用方存在 l.Logger.Panicf("%v", err) 替代原来的 LOG.Crash(err) 的模式。原来 recover 到的是 []interface{}{err},现在是格式化后的 string。如果有地方做了 recover().(error) 类型断言,会 panic。
func (l *ZapLogger) Criticalf(format string, args ...any) {
l.write(zapcore.DPanicLevel, message)
}问题:DPanicLevel 在 zap 中的设计意图是"Development Panic"——开发环境下 panic,生产环境仅记录。但这里 Criticalf 被用作纯日志记录(不 panic),用 DPanicLevel 可能在某些 zap 配置下意外触发 panic(如果 logger 是 Development 模式创建的)。
_ = LOG.Critical("Connect to mongo cluster failed. %v", err)
新代码:
```go
l.Logger.Criticalf("Connect to mongo cluster failed. %v", err)问题:原 log4go 的 Warn/Error/Critical 返回 error,虽然绝大多数调用方都 _ = 忽略了,但如果有调用方依赖返回值(如 return LOG.Error(...)),迁移后会编译报错——这确实通过编译验证了。但 PR 描述中没有明确提及这一 API 差异,建议补充。
func InitialLogger(logDir, logFile, level string, logFlush bool, verbose int) error {
return InitialLoggerWithRotation(logDir, logFile, level, logFlush, verbose, 20, 7)
}
func InitialLoggerWithRotation(logDir, logFile, level string,
logFlush bool, verbose, maxSizeMB, maxAge int) error {
if logDir == "" {
logDir = "logs"
}
if verbose != 2 {
if _, err := os.Stat(logDir); err != nil && os.IsNotExist(err) {
if err := os.MkdirAll(logDir, os.ModeDir|os.ModePerm); err != nil {
return fmt.Errorf("create log.dir[%v] failed[%v]", logDir, err)
}
}
}
return l.New(level, logDir, logFile, logFlush, maxSizeMB, maxAge, verbose)
}问题:InitialLoggerWithRotation 中做了 MkdirAll,但 pkg/log.New() 内部也做了 os.MkdirAll(见 logger.go 中 if verbose == 0 || verbose == 1 分支)。目录创建逻辑被重复执行了两次。
问题:默认值逻辑散落三处。如果 sanitize 设置了默认值,pkg/log 的 normalize 就永远不会触发(冗余);如果 sanitize 没跑(比如 receiver 路径),则依赖 pkg/log 内部的 normalize。
func (l *ZapLogger) write(level zapcore.Level, message string) {
core := l.logger.Desugar().Core()
if !core.Enabled(level) {
return
}
_ = core.Write(zapcore.Entry{
Level: level,
Time: time.Now(),
Message: message,
}, nil)
}问题:
建议:
总结
|
背景
当前 MongoShake 仍大量直接依赖
third_party/log4go,日志调用方式分散,后续维护和统一演进成本较高。本 PR 在尽量保持现有外部日志行为稳定的前提下,将日志底座切换为基于
zap的pkg/log,并完成主流程调用收敛。本次改动
pkg/log,以zap作为新的日志实现底座third_party/log4goInfof/Debugf/Warnf/Errorf等格式化接口verbose三态语义0:仅文件1:文件 + stdout2:仅 stdoutlog.flush配置语义log.max_size_mb/log.max_age,将轮转策略收敛为按大小轮转、按天数清理third_party/log4go目录及相关直接引用pkg/log定点测试,覆盖输出格式、默认文件名、panic 前刷盘、初始化前安全调用等回归点兼容性处理
cmd/collector保持先SanitizeOptions()再初始化 logger,避免破坏log.file/log.level默认值语义Logger提供默认 nop logger,避免初始化前日志调用触发空指针Crash/Crashf相关关键路径保持critical -> flush -> panic的兼容方向,不直接退化为 zap 原生Fatal配置与文档
conf/collector.confconf/receiver.conf验证
git diff --check origin/develop...HEADgo test -count=1 ./pkg/loggo test -count=1 ./cmd/collector ./cmd/receivergo test -count=1 ./common -run TestBlockMongoUrlPasswordgo test -count=1 ./receiver ./receiver/configure ./modules ./quorumgo test -count=1 ./tunnel/kafka说明
go test ./...作为默认完成标准collector/filter等路径存在已知历史测试噪音和环境依赖,不属于本 PR 新引入问题关联ISSUE:#959