log.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. package controller
  2. import (
  3. "net/http"
  4. "strconv"
  5. "time"
  6. "github.com/gin-gonic/gin"
  7. "github.com/labring/aiproxy/core/middleware"
  8. "github.com/labring/aiproxy/core/model"
  9. )
  10. func parseTimeRange(c *gin.Context) (startTime, endTime time.Time) {
  11. startTimestamp, _ := strconv.ParseInt(c.Query("start_timestamp"), 10, 64)
  12. endTimestamp, _ := strconv.ParseInt(c.Query("end_timestamp"), 10, 64)
  13. if startTimestamp != 0 {
  14. startTime = time.UnixMilli(startTimestamp)
  15. }
  16. sevenDaysAgo := time.Now().AddDate(0, 0, -7)
  17. if startTime.IsZero() || startTime.Before(sevenDaysAgo) {
  18. startTime = sevenDaysAgo
  19. }
  20. if endTimestamp != 0 {
  21. endTime = time.UnixMilli(endTimestamp)
  22. }
  23. return
  24. }
  25. func parseCommonParams(c *gin.Context) (params struct {
  26. tokenName string
  27. modelName string
  28. channelID int
  29. tokenID int
  30. order string
  31. requestID string
  32. codeType string
  33. code int
  34. withBody bool
  35. ip string
  36. user string
  37. },
  38. ) {
  39. params.tokenName = c.Query("token_name")
  40. params.modelName = c.Query("model_name")
  41. params.channelID, _ = strconv.Atoi(c.Query("channel"))
  42. params.tokenID, _ = strconv.Atoi(c.Query("token_id"))
  43. params.order = c.Query("order")
  44. params.requestID = c.Query("request_id")
  45. params.codeType = c.Query("code_type")
  46. params.code, _ = strconv.Atoi(c.Query("code"))
  47. params.withBody, _ = strconv.ParseBool(c.Query("with_body"))
  48. params.ip = c.Query("ip")
  49. params.user = c.Query("user")
  50. return
  51. }
  52. // GetLogs godoc
  53. //
  54. // @Summary Get all logs
  55. // @Description Returns a paginated list of all logs with optional filters
  56. // @Tags logs
  57. // @Produce json
  58. // @Security ApiKeyAuth
  59. // @Param group query string false "Group or *"
  60. // @Param page query int false "Page number"
  61. // @Param per_page query int false "Items per page"
  62. // @Param start_timestamp query int false "Start timestamp (milliseconds)"
  63. // @Param end_timestamp query int false "End timestamp (milliseconds)"
  64. // @Param token_name query string false "Token name"
  65. // @Param model_name query string false "Model name"
  66. // @Param channel query int false "Channel ID"
  67. // @Param token_id query int false "Token ID"
  68. // @Param order query string false "Order"
  69. // @Param request_id query string false "Request ID"
  70. // @Param code_type query string false "Status code type"
  71. // @Param code query int false "Status code"
  72. // @Param with_body query bool false "With body"
  73. // @Param ip query string false "IP"
  74. // @Param user query string false "User"
  75. // @Success 200 {object} middleware.APIResponse{data=model.GetLogsResult}
  76. // @Router /api/logs [get]
  77. func GetLogs(c *gin.Context) {
  78. page, perPage := parsePageParams(c)
  79. startTime, endTime := parseTimeRange(c)
  80. params := parseCommonParams(c)
  81. group := c.Query("group")
  82. result, err := model.GetLogs(
  83. group,
  84. startTime,
  85. endTime,
  86. params.modelName,
  87. params.requestID,
  88. params.tokenID,
  89. params.tokenName,
  90. params.channelID,
  91. params.order,
  92. model.CodeType(params.codeType),
  93. params.code,
  94. params.withBody,
  95. params.ip,
  96. params.user,
  97. page,
  98. perPage,
  99. )
  100. if err != nil {
  101. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  102. return
  103. }
  104. middleware.SuccessResponse(c, result)
  105. }
  106. // GetGroupLogs godoc
  107. //
  108. // @Summary Get group logs
  109. // @Description Get logs for a specific group
  110. // @Tags log
  111. // @Produce json
  112. // @Security ApiKeyAuth
  113. // @Param group path string true "Group name"
  114. // @Param page query int false "Page number"
  115. // @Param per_page query int false "Items per page"
  116. // @Param start_timestamp query int false "Start timestamp (milliseconds)"
  117. // @Param end_timestamp query int false "End timestamp (milliseconds)"
  118. // @Param token_name query string false "Token name"
  119. // @Param model_name query string false "Model name"
  120. // @Param channel query int false "Channel ID"
  121. // @Param token_id query int false "Token ID"
  122. // @Param order query string false "Order"
  123. // @Param request_id query string false "Request ID"
  124. // @Param code_type query string false "Status code type"
  125. // @Param code query int false "Status code"
  126. // @Param with_body query bool false "With body"
  127. // @Param ip query string false "IP"
  128. // @Param user query string false "User"
  129. // @Success 200 {object} middleware.APIResponse{data=model.GetGroupLogsResult}
  130. // @Router /api/log/{group} [get]
  131. func GetGroupLogs(c *gin.Context) {
  132. group := c.Param("group")
  133. if group == "" || group == "*" {
  134. middleware.ErrorResponse(c, http.StatusOK, "invalid group parameter")
  135. return
  136. }
  137. page, perPage := parsePageParams(c)
  138. startTime, endTime := parseTimeRange(c)
  139. params := parseCommonParams(c)
  140. result, err := model.GetGroupLogs(
  141. group,
  142. startTime,
  143. endTime,
  144. params.modelName,
  145. params.requestID,
  146. params.tokenID,
  147. params.tokenName,
  148. params.channelID,
  149. params.order,
  150. model.CodeType(params.codeType),
  151. params.code,
  152. params.withBody,
  153. params.ip,
  154. params.user,
  155. page,
  156. perPage,
  157. )
  158. if err != nil {
  159. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  160. return
  161. }
  162. middleware.SuccessResponse(c, result)
  163. }
  164. // SearchLogs godoc
  165. //
  166. // @Summary Search logs
  167. // @Description Search logs with various filters
  168. // @Tags logs
  169. // @Produce json
  170. // @Security ApiKeyAuth
  171. // @Param group query string false "Group or *"
  172. // @Param keyword query string true "Keyword"
  173. // @Param page query int false "Page number"
  174. // @Param per_page query int false "Items per page"
  175. // @Param start_timestamp query int false "Start timestamp (milliseconds)"
  176. // @Param end_timestamp query int false "End timestamp (milliseconds)"
  177. // @Param token_name query string false "Filter by token name"
  178. // @Param model_name query string false "Filter by model name"
  179. // @Param channel query int false "Filter by channel"
  180. // @Param token_id query int false "Filter by token id"
  181. // @Param order query string false "Order"
  182. // @Param request_id query string false "Request ID"
  183. // @Param code_type query string false "Status code type"
  184. // @Param code query int false "Status code"
  185. // @Param with_body query bool false "With body"
  186. // @Param ip query string false "IP"
  187. // @Param user query string false "User"
  188. // @Success 200 {object} middleware.APIResponse{data=model.GetLogsResult}
  189. // @Router /api/logs/search [get]
  190. func SearchLogs(c *gin.Context) {
  191. page, perPage := parsePageParams(c)
  192. startTime, endTime := parseTimeRange(c)
  193. params := parseCommonParams(c)
  194. keyword := c.Query("keyword")
  195. group := c.Query("group")
  196. result, err := model.SearchLogs(
  197. group,
  198. keyword,
  199. params.requestID,
  200. params.tokenID,
  201. params.tokenName,
  202. params.modelName,
  203. startTime,
  204. endTime,
  205. params.channelID,
  206. params.order,
  207. model.CodeType(params.codeType),
  208. params.code,
  209. params.withBody,
  210. params.ip,
  211. params.user,
  212. page,
  213. perPage,
  214. )
  215. if err != nil {
  216. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  217. return
  218. }
  219. middleware.SuccessResponse(c, result)
  220. }
  221. // SearchGroupLogs godoc
  222. //
  223. // @Summary Search group logs
  224. // @Description Search logs for a specific group with filters
  225. // @Tags log
  226. // @Produce json
  227. // @Security ApiKeyAuth
  228. // @Param group path string true "Group name"
  229. // @Param keyword query string true "Keyword"
  230. // @Param page query int false "Page number"
  231. // @Param per_page query int false "Items per page"
  232. // @Param start_timestamp query int false "Start timestamp (milliseconds)"
  233. // @Param end_timestamp query int false "End timestamp (milliseconds)"
  234. // @Param token_name query string false "Filter by token name"
  235. // @Param model_name query string false "Filter by model name"
  236. // @Param channel query int false "Filter by channel"
  237. // @Param token_id query int false "Filter by token id"
  238. // @Param order query string false "Order"
  239. // @Param request_id query string false "Request ID"
  240. // @Param code_type query string false "Status code type"
  241. // @Param code query int false "Status code"
  242. // @Param with_body query bool false "With body"
  243. // @Param ip query string false "IP"
  244. // @Param user query string false "User"
  245. // @Success 200 {object} middleware.APIResponse{data=model.GetGroupLogsResult}
  246. // @Router /api/log/{group}/search [get]
  247. func SearchGroupLogs(c *gin.Context) {
  248. group := c.Param("group")
  249. if group == "" || group == "*" {
  250. middleware.ErrorResponse(c, http.StatusOK, "invalid group parameter")
  251. return
  252. }
  253. page, perPage := parsePageParams(c)
  254. startTime, endTime := parseTimeRange(c)
  255. params := parseCommonParams(c)
  256. keyword := c.Query("keyword")
  257. result, err := model.SearchGroupLogs(
  258. group,
  259. keyword,
  260. params.requestID,
  261. params.tokenID,
  262. params.tokenName,
  263. params.modelName,
  264. startTime,
  265. endTime,
  266. params.channelID,
  267. params.order,
  268. model.CodeType(params.codeType),
  269. params.code,
  270. params.withBody,
  271. params.ip,
  272. params.user,
  273. page,
  274. perPage,
  275. )
  276. if err != nil {
  277. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  278. return
  279. }
  280. middleware.SuccessResponse(c, result)
  281. }
  282. // GetUsedModels godoc
  283. //
  284. // @Summary Get used models
  285. // @Description Get a list of models that have been used in logs
  286. // @Tags logs
  287. // @Produce json
  288. // @Security ApiKeyAuth
  289. // @Param group query string false "Group or *"
  290. // @Success 200 {object} middleware.APIResponse{data=[]string}
  291. // @Router /api/logs/used/models [get]
  292. func GetUsedModels(c *gin.Context) {
  293. group := c.Query("group")
  294. startTime, endTime := parseTimeRange(c)
  295. models, err := model.GetUsedModelsFromLog(group, startTime, endTime)
  296. if err != nil {
  297. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  298. return
  299. }
  300. middleware.SuccessResponse(c, models)
  301. }
  302. // GetGroupUsedModels godoc
  303. //
  304. // @Summary Get group used models
  305. // @Description Get a list of models that have been used in a specific group's logs
  306. // @Tags log
  307. // @Produce json
  308. // @Security ApiKeyAuth
  309. // @Param group path string true "Group name"
  310. // @Success 200 {object} middleware.APIResponse{data=[]string}
  311. // @Router /api/log/{group}/used/models [get]
  312. func GetGroupUsedModels(c *gin.Context) {
  313. group := c.Param("group")
  314. if group == "" || group == "*" {
  315. middleware.ErrorResponse(c, http.StatusOK, "invalid group parameter")
  316. return
  317. }
  318. startTime, endTime := parseTimeRange(c)
  319. models, err := model.GetUsedModelsFromLog(group, startTime, endTime)
  320. if err != nil {
  321. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  322. return
  323. }
  324. middleware.SuccessResponse(c, models)
  325. }
  326. // GetLogDetail godoc
  327. //
  328. // @Summary Get log detail
  329. // @Description Get detailed information about a specific log entry
  330. // @Tags logs
  331. // @Produce json
  332. // @Security ApiKeyAuth
  333. // @Param log_id path string true "Log ID"
  334. // @Success 200 {object} middleware.APIResponse{data=model.RequestDetail}
  335. // @Router /api/logs/detail/{log_id} [get]
  336. func GetLogDetail(c *gin.Context) {
  337. logID, _ := strconv.Atoi(c.Param("log_id"))
  338. log, err := model.GetLogDetail(logID)
  339. if err != nil {
  340. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  341. return
  342. }
  343. middleware.SuccessResponse(c, log)
  344. }
  345. // GetGroupLogDetail godoc
  346. //
  347. // @Summary Get group log detail
  348. // @Description Get detailed information about a specific log entry in a group
  349. // @Tags log
  350. // @Produce json
  351. // @Security ApiKeyAuth
  352. // @Param group path string true "Group name"
  353. // @Param log_id path string true "Log ID"
  354. // @Success 200 {object} middleware.APIResponse{data=model.RequestDetail}
  355. // @Router /api/log/{group}/detail/{log_id} [get]
  356. func GetGroupLogDetail(c *gin.Context) {
  357. group := c.Param("group")
  358. if group == "" || group == "*" {
  359. middleware.ErrorResponse(c, http.StatusOK, "invalid group parameter")
  360. return
  361. }
  362. logID, _ := strconv.Atoi(c.Param("log_id"))
  363. log, err := model.GetGroupLogDetail(logID, group)
  364. if err != nil {
  365. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  366. return
  367. }
  368. middleware.SuccessResponse(c, log)
  369. }
  370. // GetUsedTokenNames godoc
  371. //
  372. // @Summary Get used token names
  373. // @Description Get a list of token names that have been used in logs
  374. // @Tags logs
  375. // @Produce json
  376. // @Security ApiKeyAuth
  377. // @Param group query string false "Group or *"
  378. // @Success 200 {object} middleware.APIResponse{data=[]string}
  379. // @Router /api/logs/used/token_names [get]
  380. func GetUsedTokenNames(c *gin.Context) {
  381. group := c.Query("group")
  382. startTime, endTime := parseTimeRange(c)
  383. tokenNames, err := model.GetUsedTokenNamesFromLog(group, startTime, endTime)
  384. if err != nil {
  385. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  386. return
  387. }
  388. middleware.SuccessResponse(c, tokenNames)
  389. }
  390. // GetGroupUsedTokenNames godoc
  391. //
  392. // @Summary Get group used token names
  393. // @Description Get a list of token names that have been used in a specific group's logs
  394. // @Tags log
  395. // @Produce json
  396. // @Security ApiKeyAuth
  397. // @Param group path string true "Group name"
  398. // @Success 200 {object} middleware.APIResponse{data=[]string}
  399. // @Router /api/log/{group}/used/token_names [get]
  400. func GetGroupUsedTokenNames(c *gin.Context) {
  401. group := c.Param("group")
  402. if group == "" || group == "*" {
  403. middleware.ErrorResponse(c, http.StatusOK, "invalid group parameter")
  404. return
  405. }
  406. startTime, endTime := parseTimeRange(c)
  407. tokenNames, err := model.GetUsedTokenNamesFromLog(group, startTime, endTime)
  408. if err != nil {
  409. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  410. return
  411. }
  412. middleware.SuccessResponse(c, tokenNames)
  413. }
  414. // DeleteHistoryLogs godoc
  415. //
  416. // @Summary Delete historical logs
  417. // @Description Deletes logs older than the specified retention period
  418. // @Tags logs
  419. // @Produce json
  420. // @Security ApiKeyAuth
  421. // @Param timestamp query int true "Timestamp (milliseconds)"
  422. // @Success 200 {object} middleware.APIResponse{data=int}
  423. // @Router /api/logs [delete]
  424. func DeleteHistoryLogs(c *gin.Context) {
  425. timestamp, _ := strconv.ParseInt(c.Query("timestamp"), 10, 64)
  426. if timestamp == 0 {
  427. middleware.ErrorResponse(c, http.StatusOK, "timestamp is required")
  428. return
  429. }
  430. count, err := model.DeleteOldLog(time.UnixMilli(timestamp))
  431. if err != nil {
  432. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  433. return
  434. }
  435. middleware.SuccessResponse(c, count)
  436. }
  437. // SearchConsumeError godoc
  438. //
  439. // @Summary Search consumption errors
  440. // @Description Search for logs with consumption errors
  441. // @Tags logs
  442. // @Produce json
  443. // @Security ApiKeyAuth
  444. // @Param page query int false "Page number"
  445. // @Param per_page query int false "Items per page"
  446. // @Param start_timestamp query int false "Start timestamp (milliseconds)"
  447. // @Param end_timestamp query int false "End timestamp (milliseconds)"
  448. // @Param keyword query string false "Keyword"
  449. // @Param group query string false "Group"
  450. // @Param token_name query string false "Token name"
  451. // @Param model_name query string false "Model name"
  452. // @Param content query string false "Content"
  453. // @Param token_id query int false "Token ID"
  454. // @Param order query string false "Order"
  455. // @Param request_id query string false "Request ID"
  456. // @Success 200 {object} middleware.APIResponse{data=map[string]any{logs=[]model.RequestDetail,total=int}}
  457. // @Router /api/logs/consume_error [get]
  458. func SearchConsumeError(c *gin.Context) {
  459. keyword := c.Query("keyword")
  460. group := c.Query("group")
  461. tokenName := c.Query("token_name")
  462. modelName := c.Query("model_name")
  463. tokenID, _ := strconv.Atoi(c.Query("token_id"))
  464. page, perPage := parsePageParams(c)
  465. order := c.Query("order")
  466. requestID := c.Query("request_id")
  467. logs, total, err := model.SearchConsumeError(
  468. keyword,
  469. requestID,
  470. group,
  471. tokenName,
  472. modelName,
  473. tokenID,
  474. page,
  475. perPage,
  476. order,
  477. )
  478. if err != nil {
  479. middleware.ErrorResponse(c, http.StatusOK, err.Error())
  480. return
  481. }
  482. middleware.SuccessResponse(c, gin.H{
  483. "logs": logs,
  484. "total": total,
  485. })
  486. }