system_log_service.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package service
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strings"
  6. "time"
  7. "github.com/2930134478/AI-CS/backend/models"
  8. "github.com/2930134478/AI-CS/backend/repository"
  9. )
  10. type CreateSystemLogInput struct {
  11. Level string
  12. Category string
  13. Event string
  14. Source string
  15. TraceID string
  16. ConversationID *uint
  17. UserID *uint
  18. VisitorID *uint
  19. Message string
  20. Meta map[string]interface{}
  21. Timestamp *time.Time
  22. }
  23. type QuerySystemLogsInput struct {
  24. From string
  25. To string
  26. Level string
  27. Category string
  28. Event string
  29. Source string
  30. ConversationID *uint
  31. Keyword string
  32. Page int
  33. PageSize int
  34. }
  35. type QuerySystemLogsResult struct {
  36. Items []models.SystemLog `json:"items"`
  37. Total int64 `json:"total"`
  38. Page int `json:"page"`
  39. PageSize int `json:"page_size"`
  40. }
  41. // SystemLogService 结构化日志服务(查询 + 写入)。
  42. type SystemLogService struct {
  43. repo *repository.SystemLogRepository
  44. }
  45. func NewSystemLogService(repo *repository.SystemLogRepository) *SystemLogService {
  46. return &SystemLogService{repo: repo}
  47. }
  48. func (s *SystemLogService) Create(input CreateSystemLogInput) error {
  49. level := strings.ToLower(strings.TrimSpace(input.Level))
  50. if level == "" {
  51. level = "info"
  52. }
  53. category := strings.ToLower(strings.TrimSpace(input.Category))
  54. if category == "" {
  55. category = "system"
  56. }
  57. source := strings.ToLower(strings.TrimSpace(input.Source))
  58. if source == "" {
  59. source = "backend"
  60. }
  61. event := strings.TrimSpace(input.Event)
  62. if event == "" {
  63. event = "general"
  64. }
  65. message := strings.TrimSpace(input.Message)
  66. if message == "" {
  67. return fmt.Errorf("message 不能为空")
  68. }
  69. metaJSON := ""
  70. if input.Meta != nil {
  71. if b, err := json.Marshal(input.Meta); err == nil {
  72. metaJSON = string(b)
  73. }
  74. }
  75. ts := time.Now()
  76. if input.Timestamp != nil {
  77. ts = *input.Timestamp
  78. }
  79. item := &models.SystemLog{
  80. Timestamp: ts,
  81. Level: level,
  82. Category: category,
  83. Event: event,
  84. Source: source,
  85. TraceID: strings.TrimSpace(input.TraceID),
  86. ConversationID: input.ConversationID,
  87. UserID: input.UserID,
  88. VisitorID: input.VisitorID,
  89. Message: message,
  90. MetaJSON: metaJSON,
  91. }
  92. return s.repo.Create(item)
  93. }
  94. func (s *SystemLogService) Query(input QuerySystemLogsInput) (*QuerySystemLogsResult, error) {
  95. page := input.Page
  96. if page <= 0 {
  97. page = 1
  98. }
  99. pageSize := input.PageSize
  100. if pageSize <= 0 {
  101. pageSize = 50
  102. }
  103. if pageSize > 200 {
  104. pageSize = 200
  105. }
  106. db := s.repo.DB().Model(&models.SystemLog{})
  107. if input.From != "" {
  108. if t, err := time.Parse("2006-01-02", input.From); err == nil {
  109. db = db.Where("timestamp >= ?", t)
  110. }
  111. }
  112. if input.To != "" {
  113. if t, err := time.Parse("2006-01-02", input.To); err == nil {
  114. db = db.Where("timestamp < ?", t.AddDate(0, 0, 1))
  115. }
  116. }
  117. if v := strings.TrimSpace(input.Level); v != "" {
  118. db = db.Where("level = ?", strings.ToLower(v))
  119. }
  120. if v := strings.TrimSpace(input.Category); v != "" {
  121. db = db.Where("category = ?", strings.ToLower(v))
  122. }
  123. if v := strings.TrimSpace(input.Event); v != "" {
  124. db = db.Where("event = ?", v)
  125. }
  126. if v := strings.TrimSpace(input.Source); v != "" {
  127. db = db.Where("source = ?", strings.ToLower(v))
  128. }
  129. if input.ConversationID != nil {
  130. db = db.Where("conversation_id = ?", *input.ConversationID)
  131. }
  132. if v := strings.TrimSpace(input.Keyword); v != "" {
  133. like := "%" + v + "%"
  134. db = db.Where("(message LIKE ? OR meta_json LIKE ? OR trace_id LIKE ?)", like, like, like)
  135. }
  136. var total int64
  137. if err := db.Count(&total).Error; err != nil {
  138. return nil, err
  139. }
  140. items := make([]models.SystemLog, 0, pageSize)
  141. if err := db.Order("timestamp DESC").Offset((page-1)*pageSize).Limit(pageSize).Find(&items).Error; err != nil {
  142. return nil, err
  143. }
  144. return &QuerySystemLogsResult{
  145. Items: items,
  146. Total: total,
  147. Page: page,
  148. PageSize: pageSize,
  149. }, nil
  150. }