ops_system_log_service.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package service
  2. import (
  3. "context"
  4. "database/sql"
  5. "encoding/json"
  6. "errors"
  7. "log"
  8. "strings"
  9. "time"
  10. infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
  11. )
  12. func (s *OpsService) ListSystemLogs(ctx context.Context, filter *OpsSystemLogFilter) (*OpsSystemLogList, error) {
  13. if err := s.RequireMonitoringEnabled(ctx); err != nil {
  14. return nil, err
  15. }
  16. if s.opsRepo == nil {
  17. return &OpsSystemLogList{
  18. Logs: []*OpsSystemLog{},
  19. Total: 0,
  20. Page: 1,
  21. PageSize: 50,
  22. }, nil
  23. }
  24. if filter == nil {
  25. filter = &OpsSystemLogFilter{}
  26. }
  27. if filter.Page <= 0 {
  28. filter.Page = 1
  29. }
  30. if filter.PageSize <= 0 {
  31. filter.PageSize = 50
  32. }
  33. if filter.PageSize > 200 {
  34. filter.PageSize = 200
  35. }
  36. result, err := s.opsRepo.ListSystemLogs(ctx, filter)
  37. if err != nil {
  38. return nil, infraerrors.InternalServer("OPS_SYSTEM_LOG_LIST_FAILED", "Failed to list system logs").WithCause(err)
  39. }
  40. return result, nil
  41. }
  42. func (s *OpsService) CleanupSystemLogs(ctx context.Context, filter *OpsSystemLogCleanupFilter, operatorID int64) (int64, error) {
  43. if err := s.RequireMonitoringEnabled(ctx); err != nil {
  44. return 0, err
  45. }
  46. if s.opsRepo == nil {
  47. return 0, infraerrors.ServiceUnavailable("OPS_REPO_UNAVAILABLE", "Ops repository not available")
  48. }
  49. if operatorID <= 0 {
  50. return 0, infraerrors.BadRequest("OPS_SYSTEM_LOG_CLEANUP_INVALID_OPERATOR", "invalid operator")
  51. }
  52. if filter == nil {
  53. filter = &OpsSystemLogCleanupFilter{}
  54. }
  55. if filter.EndTime != nil && filter.StartTime != nil && filter.StartTime.After(*filter.EndTime) {
  56. return 0, infraerrors.BadRequest("OPS_SYSTEM_LOG_CLEANUP_INVALID_RANGE", "invalid time range")
  57. }
  58. deletedRows, err := s.opsRepo.DeleteSystemLogs(ctx, filter)
  59. if err != nil {
  60. if errors.Is(err, sql.ErrNoRows) {
  61. return 0, nil
  62. }
  63. if strings.Contains(strings.ToLower(err.Error()), "requires at least one filter") {
  64. return 0, infraerrors.BadRequest("OPS_SYSTEM_LOG_CLEANUP_FILTER_REQUIRED", "cleanup requires at least one filter condition")
  65. }
  66. return 0, infraerrors.InternalServer("OPS_SYSTEM_LOG_CLEANUP_FAILED", "Failed to cleanup system logs").WithCause(err)
  67. }
  68. if auditErr := s.opsRepo.InsertSystemLogCleanupAudit(ctx, &OpsSystemLogCleanupAudit{
  69. CreatedAt: time.Now().UTC(),
  70. OperatorID: operatorID,
  71. Conditions: marshalSystemLogCleanupConditions(filter),
  72. DeletedRows: deletedRows,
  73. }); auditErr != nil {
  74. // 审计失败不影响主流程,避免运维清理被阻塞。
  75. log.Printf("[OpsSystemLog] cleanup audit failed: %v", auditErr)
  76. }
  77. return deletedRows, nil
  78. }
  79. func marshalSystemLogCleanupConditions(filter *OpsSystemLogCleanupFilter) string {
  80. if filter == nil {
  81. return "{}"
  82. }
  83. payload := map[string]any{
  84. "host": strings.TrimSpace(filter.Host),
  85. "level": strings.TrimSpace(filter.Level),
  86. "component": strings.TrimSpace(filter.Component),
  87. "request_id": strings.TrimSpace(filter.RequestID),
  88. "client_request_id": strings.TrimSpace(filter.ClientRequestID),
  89. "platform": strings.TrimSpace(filter.Platform),
  90. "model": strings.TrimSpace(filter.Model),
  91. "query": strings.TrimSpace(filter.Query),
  92. }
  93. if filter.UserID != nil {
  94. payload["user_id"] = *filter.UserID
  95. }
  96. if filter.APIKeyID != nil {
  97. payload["api_key_id"] = *filter.APIKeyID
  98. }
  99. if filter.AccountID != nil {
  100. payload["account_id"] = *filter.AccountID
  101. }
  102. if filter.StartTime != nil && !filter.StartTime.IsZero() {
  103. payload["start_time"] = filter.StartTime.UTC().Format(time.RFC3339Nano)
  104. }
  105. if filter.EndTime != nil && !filter.EndTime.IsZero() {
  106. payload["end_time"] = filter.EndTime.UTC().Format(time.RFC3339Nano)
  107. }
  108. raw, err := json.Marshal(payload)
  109. if err != nil {
  110. return "{}"
  111. }
  112. return string(raw)
  113. }
  114. func (s *OpsService) GetSystemLogSinkHealth() OpsSystemLogSinkHealth {
  115. if s == nil || s.systemLogSink == nil {
  116. return OpsSystemLogSinkHealth{}
  117. }
  118. return s.systemLogSink.Health()
  119. }