Files
Atlas/internal/store/request_logs.go
T
renjue 4bc1b8d2e3
CI / docker (push) Has been cancelled
实现 Atlas AI 平台一期能力并完成品牌化改造。
引入用户端对话/生图与管理端 Provider 配置,统一 invoke 编排、Gateway、请求日志与模型管理;前端按设计规范拆分布局,Go module 更名为 github.com/rose_cat707/Atlas;生图长任务 SSE 推送;管理端登录防爆破;协议与服务类型联动;Replicate 模型同步修复;用户端创作台 UI 重构;管理端创作历史替代请求日志。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 22:34:44 +08:00

102 lines
3.6 KiB
Go

package store
import "context"
type RequestLog struct {
ID int64 `json:"id"`
SessionID string `json:"session_id"`
Method string `json:"method"`
Path string `json:"path"`
Protocol string `json:"protocol"`
ProviderID *int64 `json:"provider_id"`
Model string `json:"model"`
StatusCode int `json:"status_code"`
LatencyMS int `json:"latency_ms"`
Error string `json:"error"`
RequestSummary string `json:"request_summary"`
ResponseSummary string `json:"response_summary"`
CreatedAt string `json:"created_at"`
}
func (s *Store) InsertRequestLog(ctx context.Context, l *RequestLog) (int64, error) {
res, err := s.db.ExecContext(ctx,
`INSERT INTO request_logs (session_id, method, path, protocol, provider_id, model, status_code, latency_ms, error, request_summary, response_summary) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
l.SessionID, l.Method, l.Path, l.Protocol, l.ProviderID, l.Model, l.StatusCode, l.LatencyMS, l.Error, l.RequestSummary, l.ResponseSummary,
)
if err != nil {
return 0, err
}
return res.LastInsertId()
}
func (s *Store) ListRequestLogs(ctx context.Context, filter RequestLogFilter, limit, offset int) ([]RequestLog, int, error) {
where := `WHERE 1=1`
args := []any{}
if filter.Path != "" {
where += ` AND path LIKE ?`
args = append(args, "%"+filter.Path+"%")
}
if filter.StatusCode > 0 {
where += ` AND status_code = ?`
args = append(args, filter.StatusCode)
}
if filter.ProviderID > 0 {
where += ` AND provider_id = ?`
args = append(args, filter.ProviderID)
}
var total int
if err := s.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM request_logs `+where, args...).Scan(&total); err != nil {
return nil, 0, err
}
q := `SELECT id, session_id, method, path, protocol, provider_id, model, status_code, latency_ms, error, request_summary, response_summary, created_at FROM request_logs ` + where + ` ORDER BY id DESC LIMIT ? OFFSET ?`
qArgs := append(args, limit, offset)
rows, err := s.db.QueryContext(ctx, q, qArgs...)
if err != nil {
return nil, 0, err
}
defer rows.Close()
var items []RequestLog
for rows.Next() {
var l RequestLog
if err := rows.Scan(&l.ID, &l.SessionID, &l.Method, &l.Path, &l.Protocol, &l.ProviderID, &l.Model, &l.StatusCode, &l.LatencyMS, &l.Error, &l.RequestSummary, &l.ResponseSummary, &l.CreatedAt); err != nil {
return nil, 0, err
}
items = append(items, l)
}
return items, total, rows.Err()
}
type RequestLogFilter struct {
Path string
StatusCode int
ProviderID int64
}
type DashboardStats struct {
TotalRequests int `json:"total_requests"`
SuccessRate float64 `json:"success_rate"`
AvgLatencyMS float64 `json:"avg_latency_ms"`
P50LatencyMS float64 `json:"p50_latency_ms"`
P95LatencyMS float64 `json:"p95_latency_ms"`
ByServiceType map[string]int `json:"by_service_type"`
ByProvider map[string]int `json:"by_provider"`
FileCount int `json:"file_count"`
FileBytes int64 `json:"file_bytes"`
}
func (s *Store) DashboardStats(ctx context.Context) (*DashboardStats, error) {
stats := &DashboardStats{ByServiceType: map[string]int{}, ByProvider: map[string]int{}}
var success int
err := s.db.QueryRowContext(ctx,
`SELECT COUNT(*), COALESCE(AVG(latency_ms),0), SUM(CASE WHEN status_code >= 200 AND status_code < 400 THEN 1 ELSE 0 END) FROM request_logs WHERE created_at >= datetime('now','-7 days')`,
).Scan(&stats.TotalRequests, &stats.AvgLatencyMS, &success)
if err != nil {
return nil, err
}
if stats.TotalRequests > 0 {
stats.SuccessRate = float64(success) / float64(stats.TotalRequests)
}
stats.FileCount, stats.FileBytes, _ = s.CountFiles(ctx)
return stats, nil
}