| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- package admin
- import (
- "net/http"
- "strconv"
- "strings"
- "time"
- "github.com/Wei-Shaw/sub2api/internal/pkg/response"
- "github.com/Wei-Shaw/sub2api/internal/server/middleware"
- "github.com/Wei-Shaw/sub2api/internal/service"
- "github.com/gin-gonic/gin"
- )
- type opsSystemLogCleanupRequest struct {
- StartTime string `json:"start_time"`
- EndTime string `json:"end_time"`
- Host string `json:"host"`
- Level string `json:"level"`
- Component string `json:"component"`
- RequestID string `json:"request_id"`
- ClientRequestID string `json:"client_request_id"`
- UserID *int64 `json:"user_id"`
- APIKeyID *int64 `json:"api_key_id"`
- AccountID *int64 `json:"account_id"`
- Platform string `json:"platform"`
- Model string `json:"model"`
- Query string `json:"q"`
- }
- // ListSystemLogs returns indexed system logs.
- // GET /api/v1/admin/ops/system-logs
- func (h *OpsHandler) ListSystemLogs(c *gin.Context) {
- if h.opsService == nil {
- response.Error(c, http.StatusServiceUnavailable, "Ops service not available")
- return
- }
- if err := h.opsService.RequireMonitoringEnabled(c.Request.Context()); err != nil {
- response.ErrorFrom(c, err)
- return
- }
- page, pageSize := response.ParsePagination(c)
- if pageSize > 200 {
- pageSize = 200
- }
- start, end, err := parseOpsTimeRange(c, "1h")
- if err != nil {
- response.BadRequest(c, err.Error())
- return
- }
- filter := &service.OpsSystemLogFilter{
- Page: page,
- PageSize: pageSize,
- StartTime: &start,
- EndTime: &end,
- Host: strings.TrimSpace(c.Query("host")),
- Level: strings.TrimSpace(c.Query("level")),
- Component: strings.TrimSpace(c.Query("component")),
- RequestID: strings.TrimSpace(c.Query("request_id")),
- ClientRequestID: strings.TrimSpace(c.Query("client_request_id")),
- Platform: strings.TrimSpace(c.Query("platform")),
- Model: strings.TrimSpace(c.Query("model")),
- Query: strings.TrimSpace(c.Query("q")),
- }
- if v := strings.TrimSpace(c.Query("user_id")); v != "" {
- id, parseErr := strconv.ParseInt(v, 10, 64)
- if parseErr != nil || id <= 0 {
- response.BadRequest(c, "Invalid user_id")
- return
- }
- filter.UserID = &id
- }
- if v := strings.TrimSpace(c.Query("api_key_id")); v != "" {
- id, parseErr := strconv.ParseInt(v, 10, 64)
- if parseErr != nil || id <= 0 {
- response.BadRequest(c, "Invalid api_key_id")
- return
- }
- filter.APIKeyID = &id
- }
- if v := strings.TrimSpace(c.Query("account_id")); v != "" {
- id, parseErr := strconv.ParseInt(v, 10, 64)
- if parseErr != nil || id <= 0 {
- response.BadRequest(c, "Invalid account_id")
- return
- }
- filter.AccountID = &id
- }
- result, err := h.opsService.ListSystemLogs(c.Request.Context(), filter)
- if err != nil {
- response.ErrorFrom(c, err)
- return
- }
- response.Paginated(c, result.Logs, int64(result.Total), result.Page, result.PageSize)
- }
- // CleanupSystemLogs deletes indexed system logs by filter.
- // POST /api/v1/admin/ops/system-logs/cleanup
- func (h *OpsHandler) CleanupSystemLogs(c *gin.Context) {
- if h.opsService == nil {
- response.Error(c, http.StatusServiceUnavailable, "Ops service not available")
- return
- }
- if err := h.opsService.RequireMonitoringEnabled(c.Request.Context()); err != nil {
- response.ErrorFrom(c, err)
- return
- }
- subject, ok := middleware.GetAuthSubjectFromContext(c)
- if !ok || subject.UserID <= 0 {
- response.Error(c, http.StatusUnauthorized, "Unauthorized")
- return
- }
- var req opsSystemLogCleanupRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- response.BadRequest(c, "Invalid request body")
- return
- }
- parseTS := func(raw string) (*time.Time, error) {
- raw = strings.TrimSpace(raw)
- if raw == "" {
- return nil, nil
- }
- if t, err := time.Parse(time.RFC3339Nano, raw); err == nil {
- return &t, nil
- }
- t, err := time.Parse(time.RFC3339, raw)
- if err != nil {
- return nil, err
- }
- return &t, nil
- }
- start, err := parseTS(req.StartTime)
- if err != nil {
- response.BadRequest(c, "Invalid start_time")
- return
- }
- end, err := parseTS(req.EndTime)
- if err != nil {
- response.BadRequest(c, "Invalid end_time")
- return
- }
- if req.APIKeyID != nil && *req.APIKeyID <= 0 {
- response.BadRequest(c, "Invalid api_key_id")
- return
- }
- filter := &service.OpsSystemLogCleanupFilter{
- StartTime: start,
- EndTime: end,
- Host: strings.TrimSpace(req.Host),
- Level: strings.TrimSpace(req.Level),
- Component: strings.TrimSpace(req.Component),
- RequestID: strings.TrimSpace(req.RequestID),
- ClientRequestID: strings.TrimSpace(req.ClientRequestID),
- UserID: req.UserID,
- APIKeyID: req.APIKeyID,
- AccountID: req.AccountID,
- Platform: strings.TrimSpace(req.Platform),
- Model: strings.TrimSpace(req.Model),
- Query: strings.TrimSpace(req.Query),
- }
- deleted, err := h.opsService.CleanupSystemLogs(c.Request.Context(), filter, subject.UserID)
- if err != nil {
- response.ErrorFrom(c, err)
- return
- }
- response.Success(c, gin.H{"deleted": deleted})
- }
- // GetSystemLogIngestionHealth returns sink health metrics.
- // GET /api/v1/admin/ops/system-logs/health
- func (h *OpsHandler) GetSystemLogIngestionHealth(c *gin.Context) {
- if h.opsService == nil {
- response.Error(c, http.StatusServiceUnavailable, "Ops service not available")
- return
- }
- if err := h.opsService.RequireMonitoringEnabled(c.Request.Context()); err != nil {
- response.ErrorFrom(c, err)
- return
- }
- response.Success(c, h.opsService.GetSystemLogSinkHealth())
- }
|