fscan/Common/Log.go

347 lines
6.6 KiB
Go
Raw Normal View History

2024-12-19 14:52:11 +08:00
package Common
import (
"bufio"
2024-12-19 14:52:11 +08:00
"encoding/json"
"fmt"
"io"
"log"
"os"
"path/filepath"
"runtime"
2024-12-19 14:52:11 +08:00
"strings"
"sync"
"time"
"github.com/fatih/color"
)
var (
// 全局变量
status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()}
// 扫描计数
Num int64 // 总任务数
End int64 // 已完成任务数
2024-12-19 14:52:11 +08:00
// 文件写入器
fileWriter *bufferedFileWriter
2024-12-19 14:52:11 +08:00
)
// ScanStatus 记录扫描状态
type ScanStatus struct {
mu sync.RWMutex
total int64
completed int64
lastSuccess time.Time
lastError time.Time
}
// LogEntry 日志条目
type LogEntry struct {
Level string // "ERROR", "INFO", "SUCCESS", "DEBUG"
Time time.Time
Content string
}
// LogLevel 定义日志等级常量
const (
LogLevelAll = "ALL" // 输出所有日志
LogLevelError = "ERROR" // 错误日志
LogLevelInfo = "INFO" // 信息日志
LogLevelSuccess = "SUCCESS" // 成功日志
LogLevelDebug = "DEBUG" // 调试日志
)
// 定义日志颜色映射
var logColors = map[string]color.Attribute{
LogLevelError: color.FgRed,
LogLevelInfo: color.FgYellow,
LogLevelSuccess: color.FgGreen,
LogLevelDebug: color.FgBlue,
}
// JsonOutput JSON输出的结构体
type JsonOutput struct {
Level string `json:"level"`
Timestamp time.Time `json:"timestamp"`
Message string `json:"message"`
2024-12-19 14:52:11 +08:00
}
func InitLogger() {
2024-12-19 14:52:11 +08:00
log.SetOutput(io.Discard)
if !DisableSave {
fileWriter = newBufferedFileWriter()
}
}
// formatLogMessage 格式化日志消息
func formatLogMessage(entry *LogEntry) string {
timeStr := entry.Time.Format("2006-01-02 15:04:05")
return fmt.Sprintf("[%s] [%s] %s", timeStr, entry.Level, entry.Content)
}
2025-01-01 08:27:13 +08:00
// 修改 printLog 函数
func printLog(entry *LogEntry) {
// 默认情况(LogLevelInfo)下打印 INFO、SUCCESS、ERROR
if LogLevel == LogLevelInfo {
if entry.Level != LogLevelInfo &&
entry.Level != LogLevelSuccess &&
entry.Level != LogLevelError {
return
}
} else if LogLevel == LogLevelDebug || LogLevel == LogLevelAll {
// Debug或ALL模式打印所有日志
} else if entry.Level != LogLevel {
// 其他情况只打印指定等级的日志
return
}
OutputMutex.Lock()
defer OutputMutex.Unlock()
2025-01-01 08:27:13 +08:00
// 确保清除当前进度条
if ProgressBar != nil {
ProgressBar.Clear()
time.Sleep(10 * time.Millisecond)
}
// 打印日志
logMsg := formatLogMessage(entry)
if !NoColor {
if colorAttr, ok := logColors[entry.Level]; ok {
color.New(colorAttr).Println(logMsg)
} else {
fmt.Println(logMsg)
}
} else {
fmt.Println(logMsg)
}
2025-01-01 08:27:13 +08:00
// 确保日志完全输出
time.Sleep(50 * time.Millisecond)
// 重新渲染进度条
if ProgressBar != nil {
ProgressBar.RenderBlank()
}
}
func LogError(errMsg string) {
_, file, line, ok := runtime.Caller(1)
if !ok {
file = "unknown"
line = 0
}
file = filepath.Base(file)
errorMsg := fmt.Sprintf("%s:%d - %s", file, line, errMsg)
if ProgressBar != nil {
ProgressBar.Clear()
}
entry := &LogEntry{
Level: LogLevelError,
Time: time.Now(),
Content: errorMsg,
}
printLog(entry)
if fileWriter != nil {
fileWriter.write(entry)
}
if ProgressBar != nil {
ProgressBar.RenderBlank()
}
}
func LogInfo(msg string) {
if ProgressBar != nil {
ProgressBar.Clear()
}
entry := &LogEntry{
Level: LogLevelInfo,
Time: time.Now(),
Content: msg,
}
printLog(entry)
if fileWriter != nil {
fileWriter.write(entry)
}
if ProgressBar != nil {
ProgressBar.RenderBlank()
}
2024-12-19 14:52:11 +08:00
}
func LogSuccess(result string) {
if ProgressBar != nil {
ProgressBar.Clear()
}
entry := &LogEntry{
Level: LogLevelSuccess,
Time: time.Now(),
Content: result,
}
2024-12-19 14:52:11 +08:00
printLog(entry)
if fileWriter != nil {
fileWriter.write(entry)
}
2024-12-19 14:52:11 +08:00
status.mu.Lock()
status.lastSuccess = time.Now()
status.mu.Unlock()
if ProgressBar != nil {
ProgressBar.RenderBlank()
2024-12-19 14:52:11 +08:00
}
}
func LogDebug(msg string) {
if ProgressBar != nil {
ProgressBar.Clear()
}
entry := &LogEntry{
Level: LogLevelDebug,
Time: time.Now(),
Content: msg,
}
printLog(entry)
if fileWriter != nil {
fileWriter.write(entry)
}
if ProgressBar != nil {
ProgressBar.RenderBlank()
}
}
func newBufferedFileWriter() *bufferedFileWriter {
file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
2024-12-19 14:52:11 +08:00
if err != nil {
fmt.Printf("[ERROR] 打开输出文件失败 %s: %v\n", Outputfile, err)
return nil
}
writer := bufio.NewWriter(file)
return &bufferedFileWriter{
file: file,
writer: writer,
jsonEnc: json.NewEncoder(writer),
}
}
type bufferedFileWriter struct {
file *os.File
writer *bufio.Writer
jsonEnc *json.Encoder
mu sync.Mutex // 添加互斥锁保护写入
}
func (w *bufferedFileWriter) write(entry *LogEntry) {
if w == nil {
2024-12-19 14:52:11 +08:00
return
}
w.mu.Lock()
defer w.mu.Unlock()
var err error
if JsonFormat {
output := JsonOutput{
Level: entry.Level,
Timestamp: entry.Time,
Message: entry.Content,
2024-12-19 14:52:11 +08:00
}
err = w.jsonEnc.Encode(output)
2024-12-19 14:52:11 +08:00
} else {
logMsg := formatLogMessage(entry) + "\n"
_, err = w.writer.WriteString(logMsg)
}
if err != nil {
fmt.Printf("[ERROR] 写入日志失败: %v\n", err)
// 尝试重新打开文件
if err := w.reopen(); err != nil {
fmt.Printf("[ERROR] 重新打开文件失败: %v\n", err)
return
}
return
}
// 每隔一定数量的写入才进行一次Flush
if err := w.writer.Flush(); err != nil {
fmt.Printf("[ERROR] 刷新缓冲区失败: %v\n", err)
if err := w.reopen(); err != nil {
fmt.Printf("[ERROR] 重新打开文件失败: %v\n", err)
}
}
}
func (w *bufferedFileWriter) reopen() error {
if w.file != nil {
w.file.Close()
}
file, err := os.OpenFile(Outputfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
return err
2024-12-19 14:52:11 +08:00
}
w.file = file
w.writer = bufio.NewWriter(file)
w.jsonEnc = json.NewEncoder(w.writer)
return nil
2024-12-19 14:52:11 +08:00
}
func (w *bufferedFileWriter) close() {
if w != nil {
w.writer.Flush()
w.file.Close()
2024-12-19 14:52:11 +08:00
}
}
func CloseLogger() {
if fileWriter != nil {
fileWriter.close()
}
}
2024-12-31 20:25:54 +08:00
// CheckErrs 检查是否为需要重试的错误
func CheckErrs(err error) error {
2024-12-19 14:52:11 +08:00
if err == nil {
2024-12-31 20:25:54 +08:00
return nil
2024-12-19 14:52:11 +08:00
}
2024-12-31 20:25:54 +08:00
// 已知需要重试的错误列表
2024-12-19 14:52:11 +08:00
errs := []string{
2024-12-19 16:11:04 +08:00
"closed by the remote host", "too many connections",
2024-12-20 21:01:56 +08:00
"EOF", "A connection attempt failed",
2024-12-19 16:11:04 +08:00
"established connection failed", "connection attempt failed",
"Unable to read", "is not allowed to connect to this",
"no pg_hba.conf entry",
"No connection could be made",
"invalid packet size",
"bad connection",
2024-12-19 14:52:11 +08:00
}
// 检查错误是否匹配
errLower := strings.ToLower(err.Error())
for _, key := range errs {
if strings.Contains(errLower, strings.ToLower(key)) {
2024-12-31 20:25:54 +08:00
time.Sleep(3 * time.Second)
return err
2024-12-19 14:52:11 +08:00
}
}
2024-12-31 20:25:54 +08:00
return nil
2024-12-19 14:52:11 +08:00
}