修改log收集逻辑

This commit is contained in:
Alex Yang
2025-12-05 00:30:05 +08:00
parent baeece18ef
commit 8944fceeed
5 changed files with 362 additions and 7203 deletions

View File

@@ -8,6 +8,7 @@ import (
stdnet "net"
"net/http"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
@@ -738,108 +739,125 @@ func collectDiskDetails() ([]DiskDetailMetrics, error) {
// 采集系统日志
func collectLogs() ([]LogEntry, error) {
// 日志文件路径
logFile := "/var/log/messages"
log.Printf("Attempting to collect logs from %s", logFile)
// 日志目录
logDir := "/var/log"
log.Printf("Attempting to collect logs from %s", logDir)
// 检查文件是否存在和权限
fileInfo, err := os.Stat(logFile)
// 收集所有.log文件
logFiles, err := filepath.Glob(filepath.Join(logDir, "*.log"))
if err != nil {
log.Printf("Failed to stat log file %s: %v", logFile, err)
return nil, fmt.Errorf("failed to stat log file %s: %w", logFile, err)
log.Printf("Failed to match log files: %v", err)
return nil, err
}
log.Printf("Log file %s exists, size: %d bytes", logFile, fileInfo.Size())
// 打开日志文件
file, err := os.Open(logFile)
if err != nil {
log.Printf("Failed to open log file %s: %v", logFile, err)
return nil, fmt.Errorf("failed to open log file %s: %w", logFile, err)
// 过滤掉*.log.*文件
filteredFiles := make([]string, 0, len(logFiles))
for _, file := range logFiles {
base := filepath.Base(file)
// 只保留真正的*.log文件排除*.log.*文件
if ext := filepath.Ext(strings.TrimSuffix(base, ".log")); ext == "" {
filteredFiles = append(filteredFiles, file)
}
}
defer file.Close()
// 读取文件末尾内容
const maxReadSize = 1024 * 1024 // 最多读取1MB
readSize := maxReadSize
if fileInfo.Size() < int64(maxReadSize) {
readSize = int(fileInfo.Size())
}
log.Printf("Reading %d bytes from log file", readSize)
buf := make([]byte, readSize)
bytesRead, err := file.ReadAt(buf, fileInfo.Size()-int64(readSize))
if err != nil {
log.Printf("Failed to read log file: %v", err)
return nil, fmt.Errorf("failed to read log file: %w", err)
}
log.Printf("Successfully read %d bytes from log file", bytesRead)
// 分割日志行
lines := bytes.Split(buf[:bytesRead], []byte("\n"))
log.Printf("Found %d lines in log file", len(lines))
log.Printf("Found %d log files to process", len(filteredFiles))
// 创建日志条目切片
logs := make([]LogEntry, 0, 50) // 最多保存50条日志
// 从后往前解析日志行
for i := len(lines) - 1; i >= 0 && len(logs) < 50; i-- {
line := bytes.TrimSpace(lines[i])
if len(line) == 0 {
continue
}
// 处理每个日志文件
for _, logFile := range filteredFiles {
log.Printf("Processing log file: %s", logFile)
// 打印前5行日志行用于调试
if i >= len(lines)-5 {
log.Printf("Processing log line %d: %s", i, string(line))
}
// 使用字符串处理,更方便处理空格
lineStr := string(line)
// 使用strings.Fields分割日志行自动处理连续空格
fields := strings.Fields(lineStr)
log.Printf("Line %d fields: %v, length: %d", i, fields, len(fields))
if len(fields) < 6 {
log.Printf("Skipping line %d: not enough fields (%d) after splitting", i, len(fields))
continue
}
// 构建时间字符串:月份 日期 时间
timeStr := fmt.Sprintf("%s %s %s", fields[0], fields[1], fields[2])
log.Printf("Line %d timeStr: '%s'", i, timeStr)
// 解析时间
t, err := time.Parse("Jan 2 15:04:05", timeStr)
// 检查文件是否存在和权限
fileInfo, err := os.Stat(logFile)
if err != nil {
log.Printf("Skipping line %d: failed to parse time '%s': %v", i, timeStr, err)
log.Printf("Failed to stat log file %s: %v", logFile, err)
continue
}
// 设置当前年份
year, _, _ := time.Now().Date()
t = time.Date(year, t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, time.Local)
// 寻找第一个冒号用于分割source和message
colonIndex := strings.Index(lineStr, ": ")
if colonIndex == -1 {
log.Printf("Skipping line %d: no colon found to split source and message", i)
// 打开日志文件
file, err := os.Open(logFile)
if err != nil {
log.Printf("Failed to open log file %s: %v", logFile, err)
continue
}
// 解析source和message
source := lineStr[:colonIndex]
message := lineStr[colonIndex+2:]
// 创建日志条目
logEntry := LogEntry{
Sequence: len(logs) + 1,
Source: source,
Time: t,
Message: message,
// 读取文件末尾内容
const maxReadSize = 1024 * 1024 // 最多读取1MB
readSize := maxReadSize
if fileInfo.Size() < int64(maxReadSize) {
readSize = int(fileInfo.Size())
}
// 添加到日志切片(注意顺序,后面的日志先解析,所以需要插入到前面)
logs = append([]LogEntry{logEntry}, logs...)
buf := make([]byte, readSize)
bytesRead, err := file.ReadAt(buf, fileInfo.Size()-int64(readSize))
file.Close() // 关闭文件
if err != nil {
log.Printf("Failed to read log file %s: %v", logFile, err)
continue
}
// 分割日志行
lines := bytes.Split(buf[:bytesRead], []byte("\n"))
// 从后往前解析日志行
for i := len(lines) - 1; i >= 0 && len(logs) < 50; i-- {
line := bytes.TrimSpace(lines[i])
if len(line) == 0 {
continue
}
// 使用字符串处理,更方便处理空格
lineStr := string(line)
// 使用strings.Fields分割日志行自动处理连续空格
fields := strings.Fields(lineStr)
if len(fields) < 6 {
// 尝试其他时间格式或跳过
continue
}
// 构建时间字符串:月份 日期 时间
timeStr := fmt.Sprintf("%s %s %s", fields[0], fields[1], fields[2])
// 解析时间
t, err := time.Parse("Jan 2 15:04:05", timeStr)
if err != nil {
// 尝试其他时间格式
continue
}
// 设置当前年份
year, _, _ := time.Now().Date()
t = time.Date(year, t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, time.Local)
// 寻找第一个冒号用于分割source和message
colonIndex := strings.Index(lineStr, ": ")
if colonIndex == -1 {
continue
}
// 解析source和message添加文件名作为source的一部分
source := fmt.Sprintf("%s %s", filepath.Base(logFile), lineStr[:colonIndex])
message := lineStr[colonIndex+2:]
// 创建日志条目
logEntry := LogEntry{
Sequence: len(logs) + 1,
Source: source,
Time: t,
Message: message,
}
// 添加到日志切片(注意顺序,后面的日志先解析,所以需要插入到前面)
logs = append([]LogEntry{logEntry}, logs...)
}
if len(logs) >= 50 {
break // 达到最大日志数量,停止处理
}
}
log.Printf("Successfully collected %d logs", len(logs))