Files
ai-ops/internal/service/log_service.go
2026-05-12 17:48:22 +08:00

106 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"context"
"encoding/csv"
"fmt"
"io"
"time"
"github.com/company/ai-ops/internal/domain/model"
"github.com/company/ai-ops/internal/domain/repository"
"github.com/company/ai-ops/internal/redis"
goredis "github.com/redis/go-redis/v9"
)
// LogService 是日志业务逻辑层
type LogService struct {
logRepo repository.LogRepository
}
func NewLogService(lr repository.LogRepository) *LogService {
return &LogService{logRepo: lr}
}
// QueryLogs 查询日志
func (s *LogService) QueryLogs(ctx context.Context, filter model.LogQueryFilter) ([]model.RequestLog, int, error) {
// Redis 缓存键:基于筛选条件构建
cacheKey := s.buildCacheKey(filter)
// 尝试从缓存获取
if redis.Client != nil {
var cached []model.RequestLog
var total int
err := redis.Client.Get(ctx, cacheKey+":items").Scan(&cached)
if err == nil {
redis.Client.Get(ctx, cacheKey+":total").Scan(&total)
return cached, total, nil
}
if err != goredis.Nil {
// 缓存错误不阻断业务,继续查数据库
}
}
// 超时控制
queryCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
logs, total, err := s.logRepo.Query(queryCtx, filter)
if err != nil {
return nil, 0, fmt.Errorf("query logs: %w", err)
}
// 写入缓存5分钟 TTL
if redis.Client != nil {
redis.Client.Set(ctx, cacheKey+":items", logs, 5*time.Minute)
redis.Client.Set(ctx, cacheKey+":total", total, 5*time.Minute)
}
return logs, total, nil
}
// ExportLogsCSV 导出日志为 CSV
func (s *LogService) ExportLogsCSV(ctx context.Context, filter model.LogQueryFilter, w io.Writer) error {
filter.Page = 1
filter.PageSize = 10000 // 导出上限
logs, _, err := s.logRepo.Query(ctx, filter)
if err != nil {
return fmt.Errorf("query logs for export: %w", err)
}
csvWriter := csv.NewWriter(w)
defer csvWriter.Flush()
// 写入表头
if err := csvWriter.Write([]string{"时间", "服务名", "路径", "方法", "状态码", "延迟(ms)", "用户ID", "供应商ID", "错误码"}); err != nil {
return fmt.Errorf("write csv header: %w", err)
}
// 写入数据
for _, l := range logs {
row := []string{
l.Timestamp.Format(time.RFC3339),
l.Service,
l.Path,
l.Method,
fmt.Sprintf("%d", l.StatusCode),
fmt.Sprintf("%.2f", l.LatencyMs),
l.UserID,
l.SupplierID,
l.ErrorCode,
}
if err := csvWriter.Write(row); err != nil {
return fmt.Errorf("write csv row: %w", err)
}
}
return nil
}
func (s *LogService) buildCacheKey(filter model.LogQueryFilter) string {
return fmt.Sprintf("ai-ops:logs:%s:%s:%d:%s:%s:%d:%d",
filter.Service, filter.Path, filter.StatusCode,
filter.UserID, filter.SupplierID, filter.Page, filter.PageSize)
}