feat: add -debug flag with file logging to fscan_debug.log

This commit is contained in:
ZacharyZcR
2026-05-12 15:37:12 +08:00
parent c1cd6289e8
commit 660e0574ef
7 changed files with 60 additions and 1 deletions
+6
View File
@@ -182,6 +182,7 @@ func Flag(Info *HostInfo) error {
flag.BoolVar(&fv.Silent, "silent", false, i18n.GetText("flag_silent_mode")) flag.BoolVar(&fv.Silent, "silent", false, i18n.GetText("flag_silent_mode"))
flag.BoolVar(&fv.NoColor, "nocolor", false, i18n.GetText("flag_no_color")) flag.BoolVar(&fv.NoColor, "nocolor", false, i18n.GetText("flag_no_color"))
flag.StringVar(&fv.LogLevel, "log", LogLevelBaseInfoSuccess, i18n.GetText("flag_log_level")) flag.StringVar(&fv.LogLevel, "log", LogLevelBaseInfoSuccess, i18n.GetText("flag_log_level"))
flag.BoolVar(&fv.Debug, "debug", false, i18n.GetText("flag_debug"))
flag.BoolVar(&fv.DisableProgress, "nopg", false, i18n.GetText("flag_disable_progress")) flag.BoolVar(&fv.DisableProgress, "nopg", false, i18n.GetText("flag_disable_progress"))
flag.BoolVar(&fv.PerfStats, "perf", false, "输出性能统计JSON") flag.BoolVar(&fv.PerfStats, "perf", false, "输出性能统计JSON")
@@ -285,6 +286,11 @@ func shouldShowHelp(Info *HostInfo, fv *FlagVars) bool {
func checkParameterConflicts() error { func checkParameterConflicts() error {
fv := flagVars fv := flagVars
// -debug 等价于 -log debug
if fv.Debug {
fv.LogLevel = LogLevelDebug
}
// 检查 -ao 和 -m icmp 同时指定的情况(向后兼容提示) // 检查 -ao 和 -m icmp 同时指定的情况(向后兼容提示)
if fv.AliveOnly && fv.ScanMode == "icmp" { if fv.AliveOnly && fv.ScanMode == "icmp" {
LogInfo(i18n.GetText("param_conflict_ao_icmp_both")) LogInfo(i18n.GetText("param_conflict_ao_icmp_both"))
+1
View File
@@ -95,6 +95,7 @@ type FlagVars struct {
Silent bool Silent bool
NoColor bool NoColor bool
LogLevel string LogLevel string
Debug bool
DisableProgress bool DisableProgress bool
PerfStats bool PerfStats bool
Language string Language string
+2
View File
@@ -30,6 +30,8 @@ flag_disable_ping:
other: "Disable ping detection" other: "Disable ping detection"
flag_disable_tcp_probe: flag_disable_tcp_probe:
other: "Disable TCP supplementary probe" other: "Disable TCP supplementary probe"
flag_debug:
other: "Enable debug mode, write logs to fscan_debug.log"
flag_alive_only: flag_alive_only:
other: "Alive detection only" other: "Alive detection only"
flag_username: flag_username:
+2
View File
@@ -30,6 +30,8 @@ flag_disable_ping:
other: "禁用ping探测" other: "禁用ping探测"
flag_disable_tcp_probe: flag_disable_tcp_probe:
other: "禁用TCP补充探测" other: "禁用TCP补充探测"
flag_debug:
other: "开启调试模式,日志写入fscan_debug.log"
flag_alive_only: flag_alive_only:
other: "仅进行存活探测" other: "仅进行存活探测"
flag_username: flag_username:
+10
View File
@@ -30,6 +30,9 @@ func getGlobalLogger() *logging.Logger {
Silent: fv.Silent, Silent: fv.Silent,
StartTime: GetGlobalState().GetStartTime(), StartTime: GetGlobalState().GetStartTime(),
} }
if fv.Debug {
config.DebugLogFile = "fscan_debug.log"
}
globalLogger = logging.NewLogger(config) globalLogger = logging.NewLogger(config)
globalLogger.SetCoordinatedOutput(LogWithProgress) globalLogger.SetCoordinatedOutput(LogWithProgress)
}) })
@@ -78,3 +81,10 @@ func LogVuln(result string) { getGlobalLogger().Vuln(result) }
// LogError 输出错误日志 // LogError 输出错误日志
func LogError(errMsg string) { getGlobalLogger().Error(errMsg) } func LogError(errMsg string) { getGlobalLogger().Error(errMsg) }
// CloseLogger 关闭日志系统,释放文件资源
func CloseLogger() {
if globalLogger != nil {
globalLogger.Close()
}
}
+38 -1
View File
@@ -2,6 +2,7 @@ package logging
import ( import (
"fmt" "fmt"
"os"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -27,6 +28,7 @@ type LoggerConfig struct {
Silent bool `json:"silent"` Silent bool `json:"silent"`
StartTime time.Time `json:"start_time"` StartTime time.Time `json:"start_time"`
LevelColors map[LogLevel]interface{} `json:"-"` LevelColors map[LogLevel]interface{} `json:"-"`
DebugLogFile string `json:"debug_log_file"`
} }
// DefaultLoggerConfig 默认日志器配置 // DefaultLoggerConfig 默认日志器配置
@@ -48,6 +50,7 @@ type Logger struct {
startTime time.Time startTime time.Time
coordinatedOutput func(string) coordinatedOutput func(string)
initialized bool initialized bool
debugFile *os.File
} }
// NewLogger 创建新的日志管理器 // NewLogger 创建新的日志管理器
@@ -56,11 +59,20 @@ func NewLogger(config *LoggerConfig) *Logger {
config = DefaultLoggerConfig() config = DefaultLoggerConfig()
} }
return &Logger{ l := &Logger{
config: config, config: config,
startTime: config.StartTime, startTime: config.StartTime,
initialized: true, initialized: true,
} }
if config.DebugLogFile != "" {
f, err := os.OpenFile(config.DebugLogFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err == nil {
l.debugFile = f
}
}
return l
} }
// Initialize 初始化日志器 // Initialize 初始化日志器
@@ -139,12 +151,37 @@ func (l *Logger) log(level LogLevel, content string) {
l.outputMessage(level, logMsg) l.outputMessage(level, logMsg)
} }
// 写入debug日志文件(纯文本,无颜色)
if l.debugFile != nil {
timestamp := time.Since(l.startTime).Truncate(time.Millisecond)
if strings.Contains(content, "\n") {
lines := strings.Split(content, "\n")
for _, line := range lines {
if line != "" {
fmt.Fprintf(l.debugFile, "[%s] %s %s\n", timestamp, prefix, line)
}
}
} else {
fmt.Fprintf(l.debugFile, "[%s] %s %s\n", timestamp, prefix, content)
}
}
// 根据慢速输出设置决定是否添加延迟 // 根据慢速输出设置决定是否添加延迟
if l.config.SlowOutput { if l.config.SlowOutput {
time.Sleep(SlowOutputDelay) time.Sleep(SlowOutputDelay)
} }
} }
// Close 关闭日志器,释放文件资源
func (l *Logger) Close() {
l.mu.Lock()
defer l.mu.Unlock()
if l.debugFile != nil {
_ = l.debugFile.Close()
l.debugFile = nil
}
}
// shouldLog 检查是否应该记录该级别的日志 // shouldLog 检查是否应该记录该级别的日志
// 层级过滤:消息级别 >= 配置级别 时显示,Error 始终显示 // 层级过滤:消息级别 >= 配置级别 时显示,Error 始终显示
func (l *Logger) shouldLog(level LogLevel) bool { func (l *Logger) shouldLog(level LogLevel) bool {
+1
View File
@@ -65,6 +65,7 @@ func main() {
os.Exit(130) // 128 + SIGINT(2) = 130,标准的中断退出码 os.Exit(130) // 128 + SIGINT(2) = 130,标准的中断退出码
}() }()
defer func() { _ = common.Cleanup() }() defer func() { _ = common.Cleanup() }()
defer common.CloseLogger()
// 执行扫描 // 执行扫描
core.RunScan(context.Background(), *result.Info, result.Session) core.RunScan(context.Background(), *result.Info, result.Session)