请求日志按日 JSONL;page_views 不进主库,避免统计数据撑大 jiang13.db。 Co-authored-by: Cursor <cursoragent@cursor.com>
109 lines
3.3 KiB
Go
109 lines
3.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"git.iioio.com/freefire/jiang13-forum/service"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// APIAdminMonitorOverview 今日概览
|
|
func (h *Handlers) APIAdminMonitorOverview(c *gin.Context) {
|
|
if h.Monitor == nil {
|
|
c.JSON(http.StatusOK, service.MonitorOverview{})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, h.Monitor.OverviewToday())
|
|
}
|
|
|
|
// APIAdminMonitorGeo 地理分布
|
|
func (h *Handlers) APIAdminMonitorGeo(c *gin.Context) {
|
|
if h.Monitor == nil {
|
|
c.JSON(http.StatusOK, service.MonitorGeoResult{
|
|
Countries: []service.MonitorGeoItem{},
|
|
Regions: []service.MonitorRegionItem{},
|
|
Cities: []service.MonitorCityItem{},
|
|
ASNs: []service.MonitorASNItem{},
|
|
})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, h.Monitor.GeoStats(c.Query("range")))
|
|
}
|
|
|
|
// APIAdminMonitorStats 维度排行
|
|
func (h *Handlers) APIAdminMonitorStats(c *gin.Context) {
|
|
if h.Monitor == nil {
|
|
c.JSON(http.StatusOK, gin.H{"items": []service.MonitorStatItem{}})
|
|
return
|
|
}
|
|
items := h.Monitor.DimStats(c.Query("dim"), c.Query("range"))
|
|
c.JSON(http.StatusOK, gin.H{"dim": c.Query("dim"), "range": c.Query("range"), "items": items})
|
|
}
|
|
|
|
// APIAdminMonitorLogs 请求日志
|
|
func (h *Handlers) APIAdminMonitorLogs(c *gin.Context) {
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
|
|
if h.Monitor == nil {
|
|
c.JSON(http.StatusOK, gin.H{"items": []service.MonitorLogItem{}, "total": 0, "page": page, "size": size})
|
|
return
|
|
}
|
|
items, total := h.Monitor.ListLogs(page, size, c.Query("method"), c.Query("path"), c.Query("status"), c.Query("ip"))
|
|
c.JSON(http.StatusOK, gin.H{"items": items, "total": total, "page": page, "size": size})
|
|
}
|
|
|
|
// APIAdminMonitorRealtime 实时
|
|
func (h *Handlers) APIAdminMonitorRealtime(c *gin.Context) {
|
|
if h.Monitor == nil {
|
|
c.JSON(http.StatusOK, service.MonitorRealtime{HourlySeries: []service.MonitorRealtimePoint{}})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, h.Monitor.Realtime())
|
|
}
|
|
|
|
// APIAdminGetMonitorSettings 读取监控设置
|
|
func (h *Handlers) APIAdminGetMonitorSettings(c *gin.Context) {
|
|
cfg := h.Settings.MonitorConfig()
|
|
if h.Monitor != nil {
|
|
h.Monitor.EnrichGeoMeta(&cfg)
|
|
}
|
|
c.JSON(http.StatusOK, cfg)
|
|
}
|
|
|
|
// APIAdminUpdateMonitorSettings 更新监控设置
|
|
func (h *Handlers) APIAdminUpdateMonitorSettings(c *gin.Context) {
|
|
var req service.MonitorConfig
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
|
|
return
|
|
}
|
|
if err := h.Settings.UpdateMonitorConfig(req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
cfg := h.Settings.MonitorConfig()
|
|
if h.Monitor != nil {
|
|
h.Monitor.EnrichGeoMeta(&cfg)
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "监控设置已保存", "monitor": cfg})
|
|
}
|
|
|
|
// APIMonitorPageview 前台 SPA 路由 pageview 信标(公开,受 monitor_enabled 控制)
|
|
func (h *Handlers) APIMonitorPageview(c *gin.Context) {
|
|
if h.Monitor == nil || !h.Settings.MonitorEnabled() {
|
|
c.Status(http.StatusNoContent)
|
|
return
|
|
}
|
|
var req service.PageViewInput
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
|
|
return
|
|
}
|
|
if err := h.Monitor.RecordPageView(c.Request, c.Request.RemoteAddr, req); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "记录失败"})
|
|
return
|
|
}
|
|
c.Status(http.StatusNoContent)
|
|
}
|