125 lines
3.7 KiB
Go
125 lines
3.7 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"errors"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
|
|
infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
|
|
)
|
|
|
|
func (s *OpsService) ListSystemLogs(ctx context.Context, filter *OpsSystemLogFilter) (*OpsSystemLogList, error) {
|
|
if err := s.RequireMonitoringEnabled(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
if s.opsRepo == nil {
|
|
return &OpsSystemLogList{
|
|
Logs: []*OpsSystemLog{},
|
|
Total: 0,
|
|
Page: 1,
|
|
PageSize: 50,
|
|
}, nil
|
|
}
|
|
if filter == nil {
|
|
filter = &OpsSystemLogFilter{}
|
|
}
|
|
if filter.Page <= 0 {
|
|
filter.Page = 1
|
|
}
|
|
if filter.PageSize <= 0 {
|
|
filter.PageSize = 50
|
|
}
|
|
if filter.PageSize > 200 {
|
|
filter.PageSize = 200
|
|
}
|
|
|
|
result, err := s.opsRepo.ListSystemLogs(ctx, filter)
|
|
if err != nil {
|
|
return nil, infraerrors.InternalServer("OPS_SYSTEM_LOG_LIST_FAILED", "Failed to list system logs").WithCause(err)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (s *OpsService) CleanupSystemLogs(ctx context.Context, filter *OpsSystemLogCleanupFilter, operatorID int64) (int64, error) {
|
|
if err := s.RequireMonitoringEnabled(ctx); err != nil {
|
|
return 0, err
|
|
}
|
|
if s.opsRepo == nil {
|
|
return 0, infraerrors.ServiceUnavailable("OPS_REPO_UNAVAILABLE", "Ops repository not available")
|
|
}
|
|
if operatorID <= 0 {
|
|
return 0, infraerrors.BadRequest("OPS_SYSTEM_LOG_CLEANUP_INVALID_OPERATOR", "invalid operator")
|
|
}
|
|
if filter == nil {
|
|
filter = &OpsSystemLogCleanupFilter{}
|
|
}
|
|
if filter.EndTime != nil && filter.StartTime != nil && filter.StartTime.After(*filter.EndTime) {
|
|
return 0, infraerrors.BadRequest("OPS_SYSTEM_LOG_CLEANUP_INVALID_RANGE", "invalid time range")
|
|
}
|
|
|
|
deletedRows, err := s.opsRepo.DeleteSystemLogs(ctx, filter)
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return 0, nil
|
|
}
|
|
if strings.Contains(strings.ToLower(err.Error()), "requires at least one filter") {
|
|
return 0, infraerrors.BadRequest("OPS_SYSTEM_LOG_CLEANUP_FILTER_REQUIRED", "cleanup requires at least one filter condition")
|
|
}
|
|
return 0, infraerrors.InternalServer("OPS_SYSTEM_LOG_CLEANUP_FAILED", "Failed to cleanup system logs").WithCause(err)
|
|
}
|
|
|
|
if auditErr := s.opsRepo.InsertSystemLogCleanupAudit(ctx, &OpsSystemLogCleanupAudit{
|
|
CreatedAt: time.Now().UTC(),
|
|
OperatorID: operatorID,
|
|
Conditions: marshalSystemLogCleanupConditions(filter),
|
|
DeletedRows: deletedRows,
|
|
}); auditErr != nil {
|
|
// 审计失败不影响主流程,避免运维清理被阻塞。
|
|
log.Printf("[OpsSystemLog] cleanup audit failed: %v", auditErr)
|
|
}
|
|
return deletedRows, nil
|
|
}
|
|
|
|
func marshalSystemLogCleanupConditions(filter *OpsSystemLogCleanupFilter) string {
|
|
if filter == nil {
|
|
return "{}"
|
|
}
|
|
payload := map[string]any{
|
|
"level": strings.TrimSpace(filter.Level),
|
|
"component": strings.TrimSpace(filter.Component),
|
|
"request_id": strings.TrimSpace(filter.RequestID),
|
|
"client_request_id": strings.TrimSpace(filter.ClientRequestID),
|
|
"platform": strings.TrimSpace(filter.Platform),
|
|
"model": strings.TrimSpace(filter.Model),
|
|
"query": strings.TrimSpace(filter.Query),
|
|
}
|
|
if filter.UserID != nil {
|
|
payload["user_id"] = *filter.UserID
|
|
}
|
|
if filter.AccountID != nil {
|
|
payload["account_id"] = *filter.AccountID
|
|
}
|
|
if filter.StartTime != nil && !filter.StartTime.IsZero() {
|
|
payload["start_time"] = filter.StartTime.UTC().Format(time.RFC3339Nano)
|
|
}
|
|
if filter.EndTime != nil && !filter.EndTime.IsZero() {
|
|
payload["end_time"] = filter.EndTime.UTC().Format(time.RFC3339Nano)
|
|
}
|
|
raw, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return "{}"
|
|
}
|
|
return string(raw)
|
|
}
|
|
|
|
func (s *OpsService) GetSystemLogSinkHealth() OpsSystemLogSinkHealth {
|
|
if s == nil || s.systemLogSink == nil {
|
|
return OpsSystemLogSinkHealth{}
|
|
}
|
|
return s.systemLogSink.Health()
|
|
}
|