system_log_controller.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package controller
  2. import (
  3. "net/http"
  4. "strconv"
  5. "strings"
  6. "github.com/2930134478/AI-CS/backend/service"
  7. "github.com/gin-gonic/gin"
  8. )
  9. type SystemLogController struct {
  10. logs *service.SystemLogService
  11. }
  12. func NewSystemLogController(logs *service.SystemLogService) *SystemLogController {
  13. return &SystemLogController{logs: logs}
  14. }
  15. // GetLogs 查询日志(客服端)。
  16. func (lc *SystemLogController) GetLogs(c *gin.Context) {
  17. userID := getUserIDFromHeader(c)
  18. if userID == 0 {
  19. c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权,请提供 X-User-Id"})
  20. return
  21. }
  22. var convID *uint
  23. if v := strings.TrimSpace(c.Query("conversation_id")); v != "" {
  24. if id, err := strconv.ParseUint(v, 10, 64); err == nil {
  25. t := uint(id)
  26. convID = &t
  27. }
  28. }
  29. page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
  30. pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "50"))
  31. res, err := lc.logs.Query(service.QuerySystemLogsInput{
  32. From: c.Query("from"),
  33. To: c.Query("to"),
  34. Level: c.Query("level"),
  35. Category: c.Query("category"),
  36. Event: c.Query("event"),
  37. Source: c.Query("source"),
  38. ConversationID: convID,
  39. Keyword: c.Query("keyword"),
  40. Page: page,
  41. PageSize: pageSize,
  42. })
  43. if err != nil {
  44. c.JSON(http.StatusInternalServerError, gin.H{"error": "查询日志失败"})
  45. return
  46. }
  47. c.JSON(http.StatusOK, res)
  48. }
  49. type reportFrontendLogRequest struct {
  50. Level string `json:"level"`
  51. Category string `json:"category"`
  52. Event string `json:"event"`
  53. TraceID string `json:"trace_id"`
  54. ConversationID *uint `json:"conversation_id"`
  55. VisitorID *uint `json:"visitor_id"`
  56. Message string `json:"message"`
  57. Meta map[string]interface{} `json:"meta"`
  58. }
  59. // ReportFrontendLog 前端上报日志(用于捕获页面异常与关键请求失败)。
  60. func (lc *SystemLogController) ReportFrontendLog(c *gin.Context) {
  61. var req reportFrontendLogRequest
  62. if err := c.ShouldBindJSON(&req); err != nil || strings.TrimSpace(req.Message) == "" {
  63. c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"})
  64. return
  65. }
  66. userID := getUserIDFromHeader(c)
  67. var pUserID *uint
  68. if userID > 0 {
  69. pUserID = &userID
  70. }
  71. // 基础防护:限制 message/meta 体量,避免日志接口被刷爆。
  72. if len(req.Message) > 2000 {
  73. req.Message = req.Message[:2000]
  74. }
  75. traceID := strings.TrimSpace(req.TraceID)
  76. if traceID == "" {
  77. traceID = getTraceID(c)
  78. }
  79. if req.Meta != nil {
  80. req.Meta["truncated"] = false
  81. }
  82. if err := lc.logs.Create(service.CreateSystemLogInput{
  83. Level: req.Level,
  84. Category: req.Category,
  85. Event: req.Event,
  86. Source: "frontend",
  87. TraceID: traceID,
  88. ConversationID: req.ConversationID,
  89. UserID: pUserID,
  90. VisitorID: req.VisitorID,
  91. Message: req.Message,
  92. Meta: req.Meta,
  93. }); err != nil {
  94. c.JSON(http.StatusInternalServerError, gin.H{"error": "写入日志失败"})
  95. return
  96. }
  97. c.JSON(http.StatusOK, gin.H{"ok": true})
  98. }