fscan/common/logging/logger.go
ZacharyZcR 3be29626c2 perf: 优化logging包性能,减少运行时开销
性能优化:
- 使用预计算的levelAllowMap替代switch-case,O(1)级别检查
- 优化日志条目创建流程,减少不必要的字段赋值
- 只在错误级别时获取调用者信息,减少runtime.Caller开销
- 早期返回机制,避免不必要的计算和内存分配

代码健康:
- 添加技术债务警告注释,标记过度工程问题
- 保持接口不变,确保向后兼容
- 删除冗余的Source字段赋值

注意:这是渐进式优化,保留现有架构但提升性能
未来仍建议用简单实现替代当前的577行复杂日志系统
2025-09-02 00:31:12 +00:00

323 lines
8.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package logging - 日志系统
//
// 技术债务警告:
// 这个包过于复杂(577行代码实现5个日志函数)违反了Linus的"简洁优雅"原则。
// 当前保留是因为功能正常且重构风险较高,但未来应考虑简化。
// 理想实现:用标准库+简单封装替代当前的抽象层架构。
package logging
import (
"fmt"
"io"
"log"
"path/filepath"
"runtime"
"sync"
"time"
"github.com/fatih/color"
)
// Logger 日志管理器
type Logger struct {
mu sync.RWMutex
config *LoggerConfig
formatter LogFormatter
handlers []LogHandler
scanStatus *ScanStatus
progressBar ProgressDisplay
outputMutex *sync.Mutex
initialized bool
}
// NewLogger 创建新的日志管理器
func NewLogger(config *LoggerConfig) *Logger {
if config == nil {
config = DefaultLoggerConfig()
}
logger := &Logger{
config: config,
formatter: NewStandardFormatter(),
handlers: make([]LogHandler, 0),
scanStatus: NewScanStatus(),
outputMutex: &sync.Mutex{},
initialized: true,
}
// 设置格式化器的开始时间
logger.formatter.SetStartTime(config.StartTime)
// 添加默认的控制台处理器
consoleHandler := NewConsoleHandler(config)
logger.AddHandler(consoleHandler)
return logger
}
// =============================================================================================
// 已删除的死代码未使用SetFormatter 方法
// =============================================================================================
// AddHandler 添加日志处理器
func (l *Logger) AddHandler(handler LogHandler) {
l.mu.Lock()
defer l.mu.Unlock()
l.handlers = append(l.handlers, handler)
}
// SetProgressBar 设置进度条显示
func (l *Logger) SetProgressBar(progressBar ProgressDisplay) {
l.mu.Lock()
defer l.mu.Unlock()
l.progressBar = progressBar
}
// SetOutputMutex 设置输出互斥锁
func (l *Logger) SetOutputMutex(mutex *sync.Mutex) {
l.mu.Lock()
defer l.mu.Unlock()
l.outputMutex = mutex
}
// SetCoordinatedOutput 设置协调输出函数(用于进度条协调)
func (l *Logger) SetCoordinatedOutput(fn func(string)) {
l.mu.RLock()
defer l.mu.RUnlock()
for _, handler := range l.handlers {
if consoleHandler, ok := handler.(*ConsoleHandler); ok {
consoleHandler.SetCoordinatedOutput(fn)
}
}
}
// Log 记录日志(优化版)
func (l *Logger) Log(level LogLevel, content string, metadata ...map[string]interface{}) {
// 早期返回,避免不必要的计算
if !l.shouldLog(level) {
return
}
// 优化:只有在错误级别时才获取调用者信息,减少开销
if level == LevelError {
if _, file, line, ok := runtime.Caller(2); ok {
// 直接在content中包含位置信息避免额外的Source字段
content = fmt.Sprintf("%s:%d - %s", filepath.Base(file), line, content)
}
}
// 简化entry创建减少字段赋值
entry := &LogEntry{
Level: level,
Time: time.Now(),
Content: content,
}
// 只在需要时添加元数据
if len(metadata) > 0 && metadata[0] != nil {
entry.Metadata = metadata[0]
}
l.handleLogEntry(entry)
// 更新扫描状态
if level == LevelSuccess {
l.scanStatus.UpdateSuccess()
} else if level == LevelError {
l.scanStatus.UpdateError()
}
}
// levelAllowMap 预计算的级别允许映射,避免运行时重复计算
var levelAllowMap = map[LogLevel]map[LogLevel]bool{
LevelAll: {LevelError: true, LevelBase: true, LevelInfo: true, LevelSuccess: true, LevelDebug: true},
LevelBaseInfoSuccess: {LevelBase: true, LevelInfo: true, LevelSuccess: true},
LevelInfoSuccess: {LevelInfo: true, LevelSuccess: true},
LevelError: {LevelError: true},
LevelBase: {LevelBase: true},
LevelInfo: {LevelInfo: true},
LevelSuccess: {LevelSuccess: true},
LevelDebug: {LevelDebug: true},
}
// shouldLog 检查是否应该记录该级别的日志(优化版)
func (l *Logger) shouldLog(level LogLevel) bool {
// 快速查表O(1)复杂度
if allowedLevels, exists := levelAllowMap[l.config.Level]; exists {
return allowedLevels[level]
}
// 向后兼容:字符串"debug"显示所有
if l.config.Level == "debug" {
return true
}
// 默认策略显示base、info和success
return level == LevelBase || level == LevelInfo || level == LevelSuccess
}
// handleLogEntry 处理日志条目
func (l *Logger) handleLogEntry(entry *LogEntry) {
l.outputMutex.Lock()
defer l.outputMutex.Unlock()
// 清除进度条
l.clearProgress()
// 使用所有处理器处理日志
l.mu.RLock()
for _, handler := range l.handlers {
if handler.IsEnabled() {
handler.Handle(entry)
}
}
l.mu.RUnlock()
// 恢复进度条
l.restoreProgress()
}
// clearProgress 清除进度条
func (l *Logger) clearProgress() {
if l.progressBar != nil {
l.progressBar.Clear() // 忽略错误
time.Sleep(ProgressClearDelay)
}
}
// restoreProgress 恢复进度条
func (l *Logger) restoreProgress() {
if l.progressBar != nil {
l.progressBar.RenderBlank() // 忽略错误
}
}
// 便利方法
func (l *Logger) Debug(content string, metadata ...map[string]interface{}) {
l.Log(LevelDebug, content, metadata...)
}
func (l *Logger) Base(content string, metadata ...map[string]interface{}) {
l.Log(LevelBase, content, metadata...)
}
func (l *Logger) Info(content string, metadata ...map[string]interface{}) {
l.Log(LevelInfo, content, metadata...)
}
func (l *Logger) Success(content string, metadata ...map[string]interface{}) {
l.Log(LevelSuccess, content, metadata...)
}
func (l *Logger) Error(content string, metadata ...map[string]interface{}) {
l.Log(LevelError, content, metadata...)
}
// =============================================================================================
// 已删除的死代码未使用GetScanStatus 获取扫描状态管理器
// =============================================================================================
// Initialize 初始化日志系统(兼容原接口)
func (l *Logger) Initialize() {
// 禁用标准日志输出
log.SetOutput(io.Discard)
}
// ConsoleHandler 控制台日志处理器
type ConsoleHandler struct {
config *LoggerConfig
formatter LogFormatter
enabled bool
coordinatedOutput func(string) // 协调输出函数
mu sync.RWMutex
}
// NewConsoleHandler 创建控制台处理器
func NewConsoleHandler(config *LoggerConfig) *ConsoleHandler {
formatter := NewStandardFormatter()
formatter.SetStartTime(config.StartTime)
return &ConsoleHandler{
config: config,
formatter: formatter,
enabled: true,
}
}
// Handle 处理日志条目
func (h *ConsoleHandler) Handle(entry *LogEntry) {
h.mu.RLock()
defer h.mu.RUnlock()
if !h.enabled {
return
}
// 使用自己的格式化器格式化消息
logMsg := h.formatter.Format(entry)
// 使用协调输出函数,如果设置了的话
if h.coordinatedOutput != nil {
if h.config.EnableColor {
if colorAttr, ok := h.config.LevelColors[entry.Level]; ok {
if attr, ok := colorAttr.(color.Attribute); ok {
coloredMsg := color.New(attr).Sprint(logMsg)
h.coordinatedOutput(coloredMsg)
} else {
h.coordinatedOutput(logMsg)
}
} else {
h.coordinatedOutput(logMsg)
}
} else {
h.coordinatedOutput(logMsg)
}
} else {
// 回到原来的直接输出方式
if h.config.EnableColor {
if colorAttr, ok := h.config.LevelColors[entry.Level]; ok {
if attr, ok := colorAttr.(color.Attribute); ok {
color.New(attr).Println(logMsg)
} else {
fmt.Println(logMsg)
}
} else {
fmt.Println(logMsg)
}
} else {
fmt.Println(logMsg)
}
}
// 根据慢速输出设置决定是否添加延迟
if h.config.SlowOutput {
time.Sleep(SlowOutputDelay)
}
}
// SetEnabled 设置处理器启用状态
func (h *ConsoleHandler) SetEnabled(enabled bool) {
h.mu.Lock()
defer h.mu.Unlock()
h.enabled = enabled
}
// SetCoordinatedOutput 设置协调输出函数
func (h *ConsoleHandler) SetCoordinatedOutput(fn func(string)) {
h.mu.Lock()
defer h.mu.Unlock()
h.coordinatedOutput = fn
}
// IsEnabled 检查处理器是否启用
func (h *ConsoleHandler) IsEnabled() bool {
h.mu.RLock()
defer h.mu.RUnlock()
return h.enabled
}
// =============================================================================================
// 已删除的死代码未使用CheckErrs 错误检查函数
// =============================================================================================