fscan/Common/output/Manager.go
ZacharyZcR e095f376f9 refactor: 重构日志和输出系统,优化日志级别和时间显示
主要更改:
- 重构Log.go和Output.go为模块化架构
- 创建独立的logging和output模块
- 新增LevelBaseInfoSuccess默认日志级别(显示BASE、INFO、SUCCESS)
- 添加运行时间显示到每条日志前面
- 保持完全向后兼容的API接口
- 支持多种输出格式(TXT、JSON、CSV)
- 优化日志格式化和颜色显示

技术改进:
- 模块化设计便于扩展和维护
- 智能时间格式化(毫秒→秒→分钟→小时)
- 支持缓冲和批量输出
- 线程安全的并发处理
2025-08-05 02:14:25 +08:00

379 lines
7.7 KiB
Go

package output
import (
"fmt"
"os"
"path/filepath"
"sync"
"time"
)
// Manager 输出管理器
type Manager struct {
mu sync.RWMutex
config *ManagerConfig
writer OutputWriter
reader OutputReader
statistics *Statistics
buffer []*ScanResult
bufferMutex sync.Mutex
flushTicker *time.Ticker
stopChan chan struct{}
initialized bool
closed bool
}
// NewManager 创建新的输出管理器
func NewManager(config *ManagerConfig) (*Manager, error) {
if config == nil {
return nil, fmt.Errorf("配置不能为空")
}
// 验证输出格式
if err := validateFormat(config.Format); err != nil {
return nil, err
}
// 创建输出目录
if err := createOutputDir(config.OutputPath); err != nil {
return nil, err
}
manager := &Manager{
config: config,
statistics: NewStatistics(),
stopChan: make(chan struct{}),
}
// 初始化写入器
if err := manager.initializeWriter(); err != nil {
return nil, err
}
// 初始化读取器
manager.initializeReader()
// 如果启用缓冲,初始化缓冲区
if config.EnableBuffer {
manager.buffer = make([]*ScanResult, 0, config.BufferSize)
// 如果启用自动刷新,启动定时器
if config.AutoFlush {
manager.startAutoFlush()
}
}
manager.initialized = true
return manager, nil
}
// validateFormat 验证输出格式
func validateFormat(format OutputFormat) error {
switch format {
case FormatTXT, FormatJSON, FormatCSV:
return nil
default:
return fmt.Errorf("不支持的输出格式: %s", format)
}
}
// createOutputDir 创建输出目录
func createOutputDir(outputPath string) error {
dir := filepath.Dir(outputPath)
return os.MkdirAll(dir, 0755)
}
// initializeWriter 初始化写入器
func (m *Manager) initializeWriter() error {
var writer OutputWriter
var err error
switch m.config.Format {
case FormatTXT:
writer, err = NewTXTWriter(m.config.OutputPath)
case FormatJSON:
writer, err = NewJSONWriter(m.config.OutputPath)
case FormatCSV:
writer, err = NewCSVWriter(m.config.OutputPath)
default:
return fmt.Errorf("不支持的输出格式: %s", m.config.Format)
}
if err != nil {
return fmt.Errorf("初始化写入器失败: %v", err)
}
m.writer = writer
// 写入头部(如果需要)
return m.writer.WriteHeader()
}
// initializeReader 初始化读取器
func (m *Manager) initializeReader() {
// 目前只有CSV格式支持读取
if m.config.Format == FormatCSV {
m.reader = NewCSVReader(m.config.OutputPath)
}
}
// startAutoFlush 启动自动刷新
func (m *Manager) startAutoFlush() {
m.flushTicker = time.NewTicker(m.config.FlushInterval)
go func() {
for {
select {
case <-m.flushTicker.C:
m.flushBuffer()
case <-m.stopChan:
return
}
}
}()
}
// SaveResult 保存扫描结果
func (m *Manager) SaveResult(result *ScanResult) error {
m.mu.RLock()
defer m.mu.RUnlock()
if !m.initialized {
return fmt.Errorf("输出管理器未初始化")
}
if m.closed {
return fmt.Errorf("输出管理器已关闭")
}
// 更新统计信息
m.statistics.AddResult(result.Type)
// 如果启用缓冲,先添加到缓冲区
if m.config.EnableBuffer {
return m.addToBuffer(result)
}
// 直接写入
return m.writer.Write(result)
}
// addToBuffer 添加结果到缓冲区
func (m *Manager) addToBuffer(result *ScanResult) error {
m.bufferMutex.Lock()
defer m.bufferMutex.Unlock()
m.buffer = append(m.buffer, result)
// 如果缓冲区已满,立即刷新
if len(m.buffer) >= m.config.BufferSize {
return m.flushBufferUnsafe()
}
return nil
}
// flushBuffer 刷新缓冲区(加锁版本)
func (m *Manager) flushBuffer() error {
m.bufferMutex.Lock()
defer m.bufferMutex.Unlock()
return m.flushBufferUnsafe()
}
// flushBufferUnsafe 刷新缓冲区(无锁版本,内部使用)
func (m *Manager) flushBufferUnsafe() error {
if len(m.buffer) == 0 {
return nil
}
// 批量写入
for _, result := range m.buffer {
if err := m.writer.Write(result); err != nil {
return fmt.Errorf("写入结果失败: %v", err)
}
}
// 刷新写入器
if err := m.writer.Flush(); err != nil {
return fmt.Errorf("刷新写入器失败: %v", err)
}
// 清空缓冲区
m.buffer = m.buffer[:0]
return nil
}
// GetResults 获取扫描结果
func (m *Manager) GetResults() ([]*ScanResult, error) {
return m.GetResultsWithFilter(nil)
}
// GetResultsWithFilter 获取过滤后的扫描结果
func (m *Manager) GetResultsWithFilter(filter *ResultFilter) ([]*ScanResult, error) {
m.mu.RLock()
defer m.mu.RUnlock()
if m.reader == nil {
return nil, fmt.Errorf("当前输出格式不支持读取")
}
return m.reader.ReadWithFilter(filter)
}
// GetStatistics 获取统计信息
func (m *Manager) GetStatistics() *Statistics {
return m.statistics
}
// Flush 刷新所有缓冲区
func (m *Manager) Flush() error {
m.mu.RLock()
defer m.mu.RUnlock()
if !m.initialized || m.closed {
return nil
}
// 刷新缓冲区
if m.config.EnableBuffer {
if err := m.flushBuffer(); err != nil {
return err
}
}
// 刷新写入器
return m.writer.Flush()
}
// Close 关闭输出管理器
func (m *Manager) Close() error {
m.mu.Lock()
defer m.mu.Unlock()
if m.closed {
return nil
}
// 停止自动刷新
if m.flushTicker != nil {
m.flushTicker.Stop()
close(m.stopChan)
}
// 最后一次刷新缓冲区
if m.config.EnableBuffer {
m.flushBufferUnsafe()
}
// 关闭写入器
var err error
if m.writer != nil {
err = m.writer.Close()
}
// 关闭读取器
if m.reader != nil {
if closeErr := m.reader.Close(); closeErr != nil && err == nil {
err = closeErr
}
}
m.closed = true
return err
}
// IsInitialized 检查是否已初始化
func (m *Manager) IsInitialized() bool {
m.mu.RLock()
defer m.mu.RUnlock()
return m.initialized
}
// IsClosed 检查是否已关闭
func (m *Manager) IsClosed() bool {
m.mu.RLock()
defer m.mu.RUnlock()
return m.closed
}
// GetConfig 获取配置
func (m *Manager) GetConfig() *ManagerConfig {
m.mu.RLock()
defer m.mu.RUnlock()
// 返回配置副本
config := *m.config
return &config
}
// UpdateConfig 更新配置(部分配置可以动态更新)
func (m *Manager) UpdateConfig(updates map[string]interface{}) error {
m.mu.Lock()
defer m.mu.Unlock()
if m.closed {
return fmt.Errorf("输出管理器已关闭")
}
// 只允许更新部分配置
for key, value := range updates {
switch key {
case "enable_buffer":
if enableBuffer, ok := value.(bool); ok {
m.config.EnableBuffer = enableBuffer
}
case "buffer_size":
if bufferSize, ok := value.(int); ok && bufferSize > 0 {
m.config.BufferSize = bufferSize
}
case "auto_flush":
if autoFlush, ok := value.(bool); ok {
m.config.AutoFlush = autoFlush
if autoFlush && m.flushTicker == nil {
m.startAutoFlush()
} else if !autoFlush && m.flushTicker != nil {
m.flushTicker.Stop()
m.flushTicker = nil
}
}
case "flush_interval":
if flushInterval, ok := value.(time.Duration); ok && flushInterval > 0 {
m.config.FlushInterval = flushInterval
if m.flushTicker != nil {
m.flushTicker.Stop()
m.startAutoFlush()
}
}
default:
return fmt.Errorf("不支持更新的配置项: %s", key)
}
}
return nil
}
// 全局输出管理器实例
var (
globalManager *Manager
managerOnce sync.Once
)
// GetGlobalManager 获取全局输出管理器
func GetGlobalManager() *Manager {
return globalManager
}
// SetGlobalManager 设置全局输出管理器
func SetGlobalManager(manager *Manager) {
globalManager = manager
}
// InitGlobalManager 初始化全局输出管理器
func InitGlobalManager(config *ManagerConfig) error {
manager, err := NewManager(config)
if err != nil {
return err
}
SetGlobalManager(manager)
return nil
}