feat(service): 实现运维监控业务逻辑层
- 新增 ops 主服务(ops_service.go)和端口定义(ops_port.go) - 实现账号可用性检查服务(ops_account_availability.go) - 实现数据聚合服务(ops_aggregation_service.go) - 实现告警评估服务(ops_alert_evaluator_service.go) - 实现告警管理服务(ops_alerts.go) - 实现数据清理服务(ops_cleanup_service.go) - 实现并发控制服务(ops_concurrency.go) - 实现仪表板服务(ops_dashboard.go) - 实现错误处理服务(ops_errors.go) - 实现直方图服务(ops_histograms.go) - 实现指标采集服务(ops_metrics_collector.go) - 实现查询模式服务(ops_query_mode.go) - 实现实时监控服务(ops_realtime.go) - 实现请求详情服务(ops_request_details.go) - 实现重试机制服务(ops_retry.go) - 实现配置管理服务(ops_settings.go) - 实现趋势分析服务(ops_trends.go) - 实现窗口统计服务(ops_window_stats.go) - 添加 ops 相关领域常量 - 注册 service 依赖注入
This commit is contained in:
152
backend/internal/service/ops_request_details.go
Normal file
152
backend/internal/service/ops_request_details.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type OpsRequestKind string
|
||||
|
||||
const (
|
||||
OpsRequestKindSuccess OpsRequestKind = "success"
|
||||
OpsRequestKindError OpsRequestKind = "error"
|
||||
)
|
||||
|
||||
// OpsRequestDetail is a request-level view across success (usage_logs) and error (ops_error_logs).
|
||||
// It powers "request drilldown" UIs without exposing full request bodies for successful requests.
|
||||
type OpsRequestDetail struct {
|
||||
Kind OpsRequestKind `json:"kind"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
RequestID string `json:"request_id"`
|
||||
|
||||
Platform string `json:"platform,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
|
||||
DurationMs *int `json:"duration_ms,omitempty"`
|
||||
StatusCode *int `json:"status_code,omitempty"`
|
||||
|
||||
// When Kind == "error", ErrorID links to /admin/ops/errors/:id.
|
||||
ErrorID *int64 `json:"error_id,omitempty"`
|
||||
|
||||
Phase string `json:"phase,omitempty"`
|
||||
Severity string `json:"severity,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
|
||||
UserID *int64 `json:"user_id,omitempty"`
|
||||
APIKeyID *int64 `json:"api_key_id,omitempty"`
|
||||
AccountID *int64 `json:"account_id,omitempty"`
|
||||
GroupID *int64 `json:"group_id,omitempty"`
|
||||
|
||||
Stream bool `json:"stream"`
|
||||
}
|
||||
|
||||
type OpsRequestDetailFilter struct {
|
||||
StartTime *time.Time
|
||||
EndTime *time.Time
|
||||
|
||||
// kind: success|error|all
|
||||
Kind string
|
||||
|
||||
Platform string
|
||||
GroupID *int64
|
||||
|
||||
UserID *int64
|
||||
APIKeyID *int64
|
||||
AccountID *int64
|
||||
|
||||
Model string
|
||||
RequestID string
|
||||
Query string
|
||||
|
||||
MinDurationMs *int
|
||||
MaxDurationMs *int
|
||||
|
||||
// Sort: created_at_desc (default) or duration_desc.
|
||||
Sort string
|
||||
|
||||
Page int
|
||||
PageSize int
|
||||
}
|
||||
|
||||
func (f *OpsRequestDetailFilter) Normalize() (page, pageSize int, startTime, endTime time.Time) {
|
||||
page = 1
|
||||
pageSize = 50
|
||||
endTime = time.Now()
|
||||
startTime = endTime.Add(-1 * time.Hour)
|
||||
|
||||
if f == nil {
|
||||
return page, pageSize, startTime, endTime
|
||||
}
|
||||
|
||||
if f.Page > 0 {
|
||||
page = f.Page
|
||||
}
|
||||
if f.PageSize > 0 {
|
||||
pageSize = f.PageSize
|
||||
}
|
||||
if pageSize > 100 {
|
||||
pageSize = 100
|
||||
}
|
||||
|
||||
if f.EndTime != nil {
|
||||
endTime = *f.EndTime
|
||||
}
|
||||
if f.StartTime != nil {
|
||||
startTime = *f.StartTime
|
||||
} else if f.EndTime != nil {
|
||||
startTime = endTime.Add(-1 * time.Hour)
|
||||
}
|
||||
|
||||
if startTime.After(endTime) {
|
||||
startTime, endTime = endTime, startTime
|
||||
}
|
||||
|
||||
return page, pageSize, startTime, endTime
|
||||
}
|
||||
|
||||
type OpsRequestDetailList struct {
|
||||
Items []*OpsRequestDetail `json:"items"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
func (s *OpsService) ListRequestDetails(ctx context.Context, filter *OpsRequestDetailFilter) (*OpsRequestDetailList, error) {
|
||||
if err := s.RequireMonitoringEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.opsRepo == nil {
|
||||
return &OpsRequestDetailList{
|
||||
Items: []*OpsRequestDetail{},
|
||||
Total: 0,
|
||||
Page: 1,
|
||||
PageSize: 50,
|
||||
}, nil
|
||||
}
|
||||
|
||||
page, pageSize, startTime, endTime := filter.Normalize()
|
||||
filterCopy := &OpsRequestDetailFilter{}
|
||||
if filter != nil {
|
||||
*filterCopy = *filter
|
||||
}
|
||||
filterCopy.Page = page
|
||||
filterCopy.PageSize = pageSize
|
||||
filterCopy.StartTime = &startTime
|
||||
filterCopy.EndTime = &endTime
|
||||
|
||||
items, total, err := s.opsRepo.ListRequestDetails(ctx, filterCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if items == nil {
|
||||
items = []*OpsRequestDetail{}
|
||||
}
|
||||
|
||||
return &OpsRequestDetailList{
|
||||
Items: items,
|
||||
Total: total,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user