Files
fscan/common/logging/logger.go
T
ZacharyZcR 5ebdbd3aa2 feat: 优化日志颜色方案,区分漏洞和普通信息
- 新增 LogVuln 级别(红色),用于漏洞和重要发现
- 密码爆破成功、未授权访问、POC漏洞等改用红色显示
- 普通信息(扫描统计等)改为白色
- Web指纹保持绿色
2026-01-17 13:21:43 +08:00

223 lines
5.3 KiB
Go

package logging
import (
"fmt"
"sync"
"time"
"github.com/fatih/color"
)
// LogEntry 日志条目
type LogEntry struct {
Level LogLevel `json:"level"`
Time time.Time `json:"time"`
Content string `json:"content"`
Source string `json:"source"`
Metadata map[string]interface{} `json:"metadata"`
}
// LoggerConfig 日志器配置
type LoggerConfig struct {
Level LogLevel `json:"level"`
EnableColor bool `json:"enable_color"`
SlowOutput bool `json:"slow_output"`
ShowProgress bool `json:"show_progress"`
StartTime time.Time `json:"start_time"`
LevelColors map[LogLevel]interface{} `json:"-"`
}
// DefaultLoggerConfig 默认日志器配置
func DefaultLoggerConfig() *LoggerConfig {
return &LoggerConfig{
Level: DefaultLevel,
EnableColor: DefaultEnableColor,
SlowOutput: DefaultSlowOutput,
ShowProgress: DefaultShowProgress,
StartTime: time.Now(),
LevelColors: GetDefaultLevelColors(),
}
}
// Logger 简化的日志管理器
type Logger struct {
mu sync.RWMutex
config *LoggerConfig
startTime time.Time
coordinatedOutput func(string)
initialized bool
}
// NewLogger 创建新的日志管理器
func NewLogger(config *LoggerConfig) *Logger {
if config == nil {
config = DefaultLoggerConfig()
}
return &Logger{
config: config,
startTime: config.StartTime,
initialized: true,
}
}
// Initialize 初始化日志器
func (l *Logger) Initialize() {
l.mu.Lock()
defer l.mu.Unlock()
l.initialized = true
}
// SetCoordinatedOutput 设置协调输出函数
func (l *Logger) SetCoordinatedOutput(outputFunc func(string)) {
l.mu.Lock()
defer l.mu.Unlock()
l.coordinatedOutput = outputFunc
}
// Debug 输出调试信息
func (l *Logger) Debug(msg string) {
l.log(LevelDebug, msg)
}
// Base 输出基础信息
func (l *Logger) Base(msg string) {
l.log(LevelBase, msg)
}
// Info 输出信息
func (l *Logger) Info(msg string) {
l.log(LevelInfo, msg)
}
// Success 输出成功信息
func (l *Logger) Success(msg string) {
l.log(LevelSuccess, msg)
}
// Vuln 输出漏洞/重要发现信息
func (l *Logger) Vuln(msg string) {
l.log(LevelVuln, msg)
}
// Error 输出错误信息
func (l *Logger) Error(msg string) {
l.log(LevelError, msg)
}
// log 内部日志处理方法
func (l *Logger) log(level LogLevel, content string) {
l.mu.Lock()
defer l.mu.Unlock()
if !l.shouldLog(level) {
return
}
// 格式化消息
timeStr := l.formatElapsedTime(time.Since(l.startTime))
prefix := l.getLevelPrefix(level)
logMsg := fmt.Sprintf("[%s] %s %s", timeStr, prefix, content)
// 输出消息
l.outputMessage(level, logMsg)
// 根据慢速输出设置决定是否添加延迟
if l.config.SlowOutput {
time.Sleep(SlowOutputDelay)
}
}
// shouldLog 检查是否应该记录该级别的日志
func (l *Logger) shouldLog(level LogLevel) bool {
switch l.config.Level {
case LevelAll:
return true
case LevelError:
return level == LevelError
case LevelVuln:
return level == LevelVuln
case LevelBase:
return level == LevelBase
case LevelInfo:
return level == LevelInfo
case LevelSuccess:
return level == LevelSuccess
case LevelDebug:
return level == LevelDebug
case LevelInfoSuccess:
return level == LevelInfo || level == LevelSuccess || level == LevelVuln
case LevelBaseInfoSuccess:
return level == LevelBase || level == LevelInfo || level == LevelSuccess || level == LevelVuln
default:
// 向后兼容:字符串"debug"显示所有
if string(l.config.Level) == "debug" {
return true
}
return level == LevelInfo || level == LevelSuccess || level == LevelVuln
}
}
// outputMessage 输出消息
func (l *Logger) outputMessage(level LogLevel, logMsg string) {
if l.coordinatedOutput != nil {
// 使用协调输出(与进度条配合)
if l.config.EnableColor {
if colorAttr, ok := l.config.LevelColors[level]; ok {
if attr, ok := colorAttr.(color.Attribute); ok {
coloredMsg := color.New(attr).Sprint(logMsg)
l.coordinatedOutput(coloredMsg)
return
}
}
}
l.coordinatedOutput(logMsg)
} else {
// 直接输出
if l.config.EnableColor {
if colorAttr, ok := l.config.LevelColors[level]; ok {
if attr, ok := colorAttr.(color.Attribute); ok {
_, _ = color.New(attr).Println(logMsg)
return
}
}
}
fmt.Println(logMsg)
}
}
// formatElapsedTime 格式化经过的时间
func (l *Logger) formatElapsedTime(elapsed time.Duration) string {
switch {
case elapsed < MaxMillisecondDisplay:
return fmt.Sprintf("%dms", elapsed.Milliseconds())
case elapsed < MaxSecondDisplay:
return fmt.Sprintf("%.1fs", elapsed.Seconds())
case elapsed < MaxMinuteDisplay:
minutes := int(elapsed.Minutes())
seconds := int(elapsed.Seconds()) % 60
return fmt.Sprintf("%dm%ds", minutes, seconds)
default:
hours := int(elapsed.Hours())
minutes := int(elapsed.Minutes()) % 60
seconds := int(elapsed.Seconds()) % 60
return fmt.Sprintf("%dh%dm%ds", hours, minutes, seconds)
}
}
// getLevelPrefix 获取日志级别前缀
func (l *Logger) getLevelPrefix(level LogLevel) string {
switch level {
case LevelVuln:
return PrefixVuln
case LevelSuccess:
return PrefixSuccess
case LevelInfo:
return PrefixInfo
case LevelError:
return PrefixError
default:
return PrefixDefault
}
}