system_log_controller.go 3.1 KB

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