feat: -silent 模式输出 NDJSON 到 stdout,支持 AI agent 管道消费
测试构建 / 代码检查 (push) Has been cancelled
测试构建 / 单元测试和构建 (push) Has been cancelled
测试构建 / 构建验证 (push) Has been cancelled

- 新增 StdoutNDJSONWriter,silent 模式下每条扫描结果实时输出一行 JSON
- LogWithProgress 层拦截人类可读日志,绕过 logger sync.Once 初始化时序问题
- 支持 fscan -h xxx -silent | jq 管道用法
This commit is contained in:
ZacharyZcR
2026-05-07 06:39:53 +08:00
parent 189e17d439
commit 22039d3d21
5 changed files with 66 additions and 0 deletions
+1
View File
@@ -27,6 +27,7 @@ func getGlobalLogger() *logging.Logger {
EnableColor: !fv.NoColor,
SlowOutput: false,
ShowProgress: !fv.DisableProgress,
Silent: fv.Silent,
StartTime: GetGlobalState().GetStartTime(),
}
globalLogger = logging.NewLogger(config)
+5
View File
@@ -24,6 +24,7 @@ type LoggerConfig struct {
EnableColor bool `json:"enable_color"`
SlowOutput bool `json:"slow_output"`
ShowProgress bool `json:"show_progress"`
Silent bool `json:"silent"`
StartTime time.Time `json:"start_time"`
LevelColors map[LogLevel]interface{} `json:"-"`
}
@@ -111,6 +112,10 @@ func (l *Logger) log(level LogLevel, content string) {
l.mu.Lock()
defer l.mu.Unlock()
if l.config.Silent {
return
}
if !l.shouldLog(level) {
return
}
+40
View File
@@ -0,0 +1,40 @@
package output
import (
"bufio"
"encoding/json"
"os"
"sync"
)
type StdoutNDJSONWriter struct {
mu sync.Mutex
writer *bufio.Writer
}
func NewStdoutNDJSONWriter() *StdoutNDJSONWriter {
return &StdoutNDJSONWriter{
writer: bufio.NewWriter(os.Stdout),
}
}
func (w *StdoutNDJSONWriter) WriteResult(result *ScanResult) error {
w.mu.Lock()
defer w.mu.Unlock()
data, err := json.Marshal(result)
if err != nil {
return err
}
data = append(data, '\n')
if _, err := w.writer.Write(data); err != nil {
return err
}
return w.writer.Flush()
}
func (w *StdoutNDJSONWriter) Close() error {
w.mu.Lock()
defer w.mu.Unlock()
return w.writer.Flush()
}
+16
View File
@@ -15,10 +15,18 @@ import (
// ResultOutput 全局输出管理器
var ResultOutput *output.Manager
// StdoutWriter silent模式下的NDJSON stdout写入器
var StdoutWriter *output.StdoutNDJSONWriter
// InitOutput 初始化输出系统
func InitOutput() error {
fv := GetFlagVars()
// silent模式:初始化NDJSON stdout写入器(独立于文件输出)
if fv.Silent {
StdoutWriter = output.NewStdoutNDJSONWriter()
}
// 用户通过-no flag禁用保存时,跳过文件初始化避免不必要的资源开销
if fv.DisableSave {
return nil
@@ -59,6 +67,9 @@ func InitOutput() error {
// CloseOutput 关闭输出系统
func CloseOutput() error {
if StdoutWriter != nil {
_ = StdoutWriter.Close()
}
if ResultOutput == nil {
return nil
}
@@ -80,6 +91,11 @@ func SaveResult(result *output.ScanResult) error {
"details": result.Details,
})
// silent模式:NDJSON实时输出到stdout
if StdoutWriter != nil {
_ = StdoutWriter.WriteResult(result)
}
// 用户禁用保存或输出未初始化时,跳过文件保存
if GetGlobalConfig().Output.DisableSave || ResultOutput == nil {
return nil
+4
View File
@@ -479,6 +479,10 @@ func (pm *ProgressManager) GetPercent() float64 {
// LogWithProgress 在进度条活跃时协调日志输出
func LogWithProgress(message string) {
if cfg := GetGlobalConfig(); cfg != nil && cfg.Output.Silent {
return
}
pm := GetProgressManager()
if !pm.IsActive() {
// 如果进度条不活跃,直接输出