110 lines
2.9 KiB
Go
110 lines
2.9 KiB
Go
|
|
package handler
|
||
|
|
|
||
|
|
import (
|
||
|
|
"net/http"
|
||
|
|
"strconv"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/company/ai-ops/internal/domain/model"
|
||
|
|
"github.com/company/ai-ops/internal/service"
|
||
|
|
"github.com/company/ai-ops/pkg/errors"
|
||
|
|
"github.com/company/ai-ops/pkg/response"
|
||
|
|
)
|
||
|
|
|
||
|
|
// LogHandler 是日志 HTTP 处理器
|
||
|
|
type LogHandler struct {
|
||
|
|
service *service.LogService
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewLogHandler(s *service.LogService) *LogHandler {
|
||
|
|
return &LogHandler{service: s}
|
||
|
|
}
|
||
|
|
|
||
|
|
// RegisterRoutes 注册日志相关路由
|
||
|
|
func (h *LogHandler) RegisterRoutes(mux *http.ServeMux) {
|
||
|
|
mux.HandleFunc("GET /api/v1/ai-ops/logs", h.QueryLogs)
|
||
|
|
mux.HandleFunc("GET /api/v1/ai-ops/logs/export", h.ExportLogs)
|
||
|
|
}
|
||
|
|
|
||
|
|
// QueryLogs 日志查询
|
||
|
|
func (h *LogHandler) QueryLogs(w http.ResponseWriter, r *http.Request) {
|
||
|
|
query := r.URL.Query()
|
||
|
|
|
||
|
|
filter := model.LogQueryFilter{
|
||
|
|
Service: query.Get("service"),
|
||
|
|
Path: query.Get("path"),
|
||
|
|
UserID: query.Get("user_id"),
|
||
|
|
SupplierID: query.Get("supplier_id"),
|
||
|
|
}
|
||
|
|
|
||
|
|
if startStr := query.Get("start"); startStr != "" {
|
||
|
|
if t, err := time.Parse(time.RFC3339, startStr); err == nil {
|
||
|
|
filter.StartTime = &t
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if endStr := query.Get("end"); endStr != "" {
|
||
|
|
if t, err := time.Parse(time.RFC3339, endStr); err == nil {
|
||
|
|
filter.EndTime = &t
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if codeStr := query.Get("status_code"); codeStr != "" {
|
||
|
|
if code, err := strconv.Atoi(codeStr); err == nil {
|
||
|
|
filter.StatusCode = &code
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if page, err := strconv.Atoi(query.Get("page")); err == nil && page > 0 {
|
||
|
|
filter.Page = page
|
||
|
|
} else {
|
||
|
|
filter.Page = 1
|
||
|
|
}
|
||
|
|
if pageSize, err := strconv.Atoi(query.Get("page_size")); err == nil && pageSize > 0 && pageSize <= 100 {
|
||
|
|
filter.PageSize = pageSize
|
||
|
|
} else {
|
||
|
|
filter.PageSize = 20
|
||
|
|
}
|
||
|
|
|
||
|
|
logs, total, err := h.service.QueryLogs(r.Context(), filter)
|
||
|
|
if err != nil {
|
||
|
|
response.Error(w, errors.Wrap(err, errors.ErrInternal))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
response.PaginatedResponse(w, logs, total, filter.Page, filter.PageSize)
|
||
|
|
}
|
||
|
|
|
||
|
|
// ExportLogs 导出日志为 CSV
|
||
|
|
func (h *LogHandler) ExportLogs(w http.ResponseWriter, r *http.Request) {
|
||
|
|
query := r.URL.Query()
|
||
|
|
|
||
|
|
filter := model.LogQueryFilter{
|
||
|
|
Service: query.Get("service"),
|
||
|
|
Path: query.Get("path"),
|
||
|
|
UserID: query.Get("user_id"),
|
||
|
|
SupplierID: query.Get("supplier_id"),
|
||
|
|
}
|
||
|
|
|
||
|
|
if startStr := query.Get("start"); startStr != "" {
|
||
|
|
if t, err := time.Parse(time.RFC3339, startStr); err == nil {
|
||
|
|
filter.StartTime = &t
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if endStr := query.Get("end"); endStr != "" {
|
||
|
|
if t, err := time.Parse(time.RFC3339, endStr); err == nil {
|
||
|
|
filter.EndTime = &t
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if codeStr := query.Get("status_code"); codeStr != "" {
|
||
|
|
if code, err := strconv.Atoi(codeStr); err == nil {
|
||
|
|
filter.StatusCode = &code
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
w.Header().Set("Content-Type", "text/csv; charset=utf-8")
|
||
|
|
w.Header().Set("Content-Disposition", "attachment; filename=logs_"+time.Now().Format("20060102_150405")+".csv")
|
||
|
|
|
||
|
|
if err := h.service.ExportLogsCSV(r.Context(), filter, w); err != nil {
|
||
|
|
response.Error(w, errors.Wrap(err, errors.ErrInternal))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|