🎨新增请求日志记录
This commit is contained in:
parent
30b7d6aeb6
commit
e1f168b274
42
http/api/dashboard.go
Normal file
42
http/api/dashboard.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"wireguard-dashboard/http/param"
|
||||||
|
"wireguard-dashboard/model/entity"
|
||||||
|
"wireguard-dashboard/repository"
|
||||||
|
"wireguard-dashboard/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dashboard struct{}
|
||||||
|
|
||||||
|
func Dashboard() dashboard {
|
||||||
|
return dashboard{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List
|
||||||
|
// @description: 操作日志分页列表
|
||||||
|
// @receiver d
|
||||||
|
// @param c
|
||||||
|
func (d dashboard) List(c *gin.Context) {
|
||||||
|
var p param.OnlyPage
|
||||||
|
if err := c.ShouldBind(&p); err != nil {
|
||||||
|
utils.GinResponse(c).FailedWithErr("参数错误", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不是超级管理员只能看自己的
|
||||||
|
userInfo, ok := c.Get("user")
|
||||||
|
if !ok {
|
||||||
|
utils.GinResponse(c).AuthorizationFailed()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, count, err := repository.SystemLog().List(p, userInfo.(*entity.User))
|
||||||
|
if err != nil {
|
||||||
|
utils.GinResponse(c).FailedWithErr("获取失败", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.GinResponse(c).OkWithPage(data, count, p.Current, p.Size)
|
||||||
|
}
|
@ -4,3 +4,7 @@ type page struct {
|
|||||||
Current int `json:"current" form:"current" binding:"required"`
|
Current int `json:"current" form:"current" binding:"required"`
|
||||||
Size int `json:"size" form:"size" binding:"required"`
|
Size int `json:"size" form:"size" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OnlyPage struct {
|
||||||
|
page
|
||||||
|
}
|
||||||
|
1
main.go
1
main.go
@ -26,6 +26,7 @@ func main() {
|
|||||||
route.ServerApi,
|
route.ServerApi,
|
||||||
route.ClientApi,
|
route.ClientApi,
|
||||||
route.SettingApi,
|
route.SettingApi,
|
||||||
|
route.DashboardApi,
|
||||||
)
|
)
|
||||||
handler := route.InitRouter()
|
handler := route.InitRouter()
|
||||||
|
|
||||||
|
107
middleware/system_log.go
Normal file
107
middleware/system_log.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"gitee.ltd/lxh/logger/log"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
"io"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"wireguard-dashboard/model/entity"
|
||||||
|
"wireguard-dashboard/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
// bodyWriter
|
||||||
|
// @description: 重写ResponseBody
|
||||||
|
type bodyWriter struct {
|
||||||
|
gin.ResponseWriter
|
||||||
|
body *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func SystemLogRequest() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
var userId string
|
||||||
|
if userInfo, ok := c.Get("user"); ok {
|
||||||
|
userId = userInfo.(*entity.User).Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始时间
|
||||||
|
start := time.Now()
|
||||||
|
host := c.Request.Host // 请求域名
|
||||||
|
path := c.Request.URL.Path // 接口地址
|
||||||
|
query := c.Request.URL.RawQuery // 参数
|
||||||
|
if strings.Contains(path, "/api/dashboard/list") {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var bodyStr string
|
||||||
|
if !strings.Contains(path, "/api/login") {
|
||||||
|
body, err := c.GetRawData() // body参数
|
||||||
|
if err == nil {
|
||||||
|
bodyStr = string(body)
|
||||||
|
c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
|
||||||
|
reg := regexp.MustCompile("\\s+")
|
||||||
|
bodyStr = reg.ReplaceAllString(bodyStr, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
method := c.Request.Method // 请求方式
|
||||||
|
ip := c.ClientIP() // 取出IP
|
||||||
|
// 处理实际客户端IP
|
||||||
|
if c.Request.Header.Get("U-Real-Ip") != "" {
|
||||||
|
ip = c.Request.Header.Get("U-Real-Ip") // 这个是网关Nginx自定义的Header头
|
||||||
|
} else if c.Request.Header.Get("U-Forwarded-For") != "" {
|
||||||
|
ip = c.Request.Header.Get("U-Forwarded-For") // 这个是网关Nginx自定义的Header头
|
||||||
|
}
|
||||||
|
ua := c.Request.UserAgent() // UA
|
||||||
|
|
||||||
|
// 重写客户端IP
|
||||||
|
c.Request.Header.Set("X-Forwarded-For", ip)
|
||||||
|
c.Request.Header.Set("X-Real-Ip", ip)
|
||||||
|
|
||||||
|
// 拦截response
|
||||||
|
bw := &bodyWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
|
||||||
|
c.Writer = bw
|
||||||
|
|
||||||
|
header := c.Request.Header
|
||||||
|
headerStr, _ := jsoniter.MarshalToString(header)
|
||||||
|
|
||||||
|
// 执行下一步请求
|
||||||
|
c.Next()
|
||||||
|
// 计算耗时
|
||||||
|
cost := time.Since(start).Milliseconds()
|
||||||
|
|
||||||
|
// 组装实体
|
||||||
|
l := entity.SystemLog{
|
||||||
|
UserId: userId,
|
||||||
|
ClientIP: ip,
|
||||||
|
Host: host,
|
||||||
|
Method: method,
|
||||||
|
Uri: path,
|
||||||
|
Header: headerStr,
|
||||||
|
Body: bodyStr,
|
||||||
|
Form: "",
|
||||||
|
Query: query,
|
||||||
|
UserAgent: ua,
|
||||||
|
Cost: cost,
|
||||||
|
StatusCode: c.Writer.Status(),
|
||||||
|
Response: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不是返回200,把返回值保存一下
|
||||||
|
if c.Writer.Status() != 200 {
|
||||||
|
resp := bw.body.String()
|
||||||
|
l.Response = resp
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if er := repository.SystemLog().SaveLog(&l); er != nil {
|
||||||
|
log.Debugf("请求日志: %+v", l)
|
||||||
|
log.Errorf("保存请求日志失败: %v", er)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
@ -10,3 +10,26 @@ type Setting struct {
|
|||||||
func (Setting) TableName() string {
|
func (Setting) TableName() string {
|
||||||
return "t_setting"
|
return "t_setting"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SystemLog
|
||||||
|
// @description: 系统日志
|
||||||
|
type SystemLog struct {
|
||||||
|
Base
|
||||||
|
UserId string `json:"userId" gorm:"type:char(40);comment:'用户id'"`
|
||||||
|
ClientIP string `json:"clientIP" gorm:"type:varchar(60);not null;comment:'客户端IP'"`
|
||||||
|
Host string `json:"host" gorm:"type:varchar(255);not null;comment:'请求域名'"`
|
||||||
|
Method string `json:"method" gorm:"type:varchar(20);not null;comment:'请求方法[GET POST DELETE PUT PATCH]'"`
|
||||||
|
Uri string `json:"uri" gorm:"type:varchar(255);not null;comment:'请求path'"`
|
||||||
|
Header string `json:"header" gorm:"type:text;comment:'请求头'"`
|
||||||
|
Body string `json:"body" gorm:"type:text;comment:'请求体'"`
|
||||||
|
Form string `json:"form" gorm:"type:text;comment:'请求表单'"`
|
||||||
|
Query string `json:"query" gorm:"type:text;comment:'请求query'"`
|
||||||
|
UserAgent string `json:"userAgent" gorm:"type:text;comment:'ua信息'"`
|
||||||
|
Cost int64 `json:"cost" gorm:"type:int(10);comment:'请求耗时'"`
|
||||||
|
StatusCode int `json:"statusCode" gorm:"type:int(10);comment:'响应状态码'"`
|
||||||
|
Response string `json:"response" gorm:"type:text;comment:'返回数据'"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (SystemLog) TableName() string {
|
||||||
|
return "t_system_log"
|
||||||
|
}
|
||||||
|
14
model/vo/dashboard.go
Normal file
14
model/vo/dashboard.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package vo
|
||||||
|
|
||||||
|
import "wireguard-dashboard/model/entity"
|
||||||
|
|
||||||
|
type SystemLogItem struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
ClientIP string `json:"clientIP"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Uri string `json:"uri"`
|
||||||
|
StatusCode int `json:"statusCode"`
|
||||||
|
CreatedAt entity.JsonTime `json:"createdAt"`
|
||||||
|
}
|
50
repository/system_log.go
Normal file
50
repository/system_log.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"wireguard-dashboard/client"
|
||||||
|
"wireguard-dashboard/constant"
|
||||||
|
"wireguard-dashboard/http/param"
|
||||||
|
"wireguard-dashboard/model/entity"
|
||||||
|
"wireguard-dashboard/model/vo"
|
||||||
|
"wireguard-dashboard/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type systemLog struct {
|
||||||
|
*gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func SystemLog() systemLog {
|
||||||
|
return systemLog{
|
||||||
|
client.DB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveLog
|
||||||
|
// @description: 保存记录
|
||||||
|
// @receiver systemLog
|
||||||
|
// @param data
|
||||||
|
// @return err
|
||||||
|
func (s systemLog) SaveLog(data *entity.SystemLog) (err error) {
|
||||||
|
return s.Create(&data).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// List
|
||||||
|
// @description: 分页列表
|
||||||
|
// @receiver s
|
||||||
|
// @param p
|
||||||
|
// @return data
|
||||||
|
// @return total
|
||||||
|
// @return err
|
||||||
|
func (s systemLog) List(p param.OnlyPage, loginUser *entity.User) (data []vo.SystemLogItem, total int64, err error) {
|
||||||
|
sel := s.Scopes(utils.Page(p.Current, p.Size)).Table("t_system_log as tsl").
|
||||||
|
Joins("LEFT JOIN t_user as tu ON tu.id = tsl.user_id").
|
||||||
|
Select("tsl.id", "tu.name as username", "tsl.client_ip", "tsl.method", "tsl.status_code", "tsl.host", "tsl.uri", "tsl.created_at").
|
||||||
|
Order("tsl.created_at DESC")
|
||||||
|
|
||||||
|
if loginUser.IsAdmin == constant.NormalAdmin {
|
||||||
|
sel.Where("tsl.user_id = ?", loginUser.Id)
|
||||||
|
}
|
||||||
|
err = sel.Find(&data).Offset(-1).Limit(-1).Count(&total).Error
|
||||||
|
return
|
||||||
|
}
|
@ -3,13 +3,14 @@ package route
|
|||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"wireguard-dashboard/http/api"
|
"wireguard-dashboard/http/api"
|
||||||
|
"wireguard-dashboard/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CaptchaApi
|
// CaptchaApi
|
||||||
// @description: 验证码
|
// @description: 验证码
|
||||||
// @param r
|
// @param r
|
||||||
func CaptchaApi(r *gin.RouterGroup) {
|
func CaptchaApi(r *gin.RouterGroup) {
|
||||||
captcha := r.Group("captcha")
|
captcha := r.Group("captcha", middleware.SystemLogRequest())
|
||||||
{
|
{
|
||||||
captcha.GET("", api.Captcha().GenerateCaptcha) // 生成验证码
|
captcha.GET("", api.Captcha().GenerateCaptcha) // 生成验证码
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ClientApi(r *gin.RouterGroup) {
|
func ClientApi(r *gin.RouterGroup) {
|
||||||
apiGroup := r.Group("client", middleware.Authorization())
|
apiGroup := r.Group("client", middleware.Authorization(), middleware.SystemLogRequest())
|
||||||
{
|
{
|
||||||
apiGroup.GET("list", api.Client().List) // 客户端列表
|
apiGroup.GET("list", api.Client().List) // 客户端列表
|
||||||
apiGroup.POST("save", middleware.Permission(), api.Client().Save) // 新增/编辑客户端
|
apiGroup.POST("save", middleware.Permission(), api.Client().Save) // 新增/编辑客户端
|
||||||
|
17
route/dashboard.go
Normal file
17
route/dashboard.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package route
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"wireguard-dashboard/http/api"
|
||||||
|
"wireguard-dashboard/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DashboardApi
|
||||||
|
// @description: 控制台相关API
|
||||||
|
// @param r
|
||||||
|
func DashboardApi(r *gin.RouterGroup) {
|
||||||
|
apiGroup := r.Group("dashboard", middleware.Authorization(), middleware.SystemLogRequest())
|
||||||
|
{
|
||||||
|
apiGroup.GET("list", api.Dashboard().List) // 操作日志
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ServerApi(r *gin.RouterGroup) {
|
func ServerApi(r *gin.RouterGroup) {
|
||||||
apiGroup := r.Group("server", middleware.Authorization())
|
apiGroup := r.Group("server", middleware.Authorization(), middleware.Permission(), middleware.SystemLogRequest())
|
||||||
{
|
{
|
||||||
apiGroup.GET("", api.Server().GetServer) // 获取服务端信息
|
apiGroup.GET("", api.Server().GetServer) // 获取服务端信息
|
||||||
apiGroup.POST("", middleware.Permission(), api.Server().SaveServer) // 新增/更新服务端信息
|
apiGroup.POST("", middleware.Permission(), api.Server().SaveServer) // 新增/更新服务端信息
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
// @description: 设置相关API
|
// @description: 设置相关API
|
||||||
// @param r
|
// @param r
|
||||||
func SettingApi(r *gin.RouterGroup) {
|
func SettingApi(r *gin.RouterGroup) {
|
||||||
apiGroup := r.Group("setting", middleware.Authorization())
|
apiGroup := r.Group("setting", middleware.Authorization(), middleware.SystemLogRequest())
|
||||||
{
|
{
|
||||||
apiGroup.POST("save", middleware.Permission(), api.Setting().SetSetting) // 添加/更改设置 - 设置其他的配置
|
apiGroup.POST("save", middleware.Permission(), api.Setting().SetSetting) // 添加/更改设置 - 设置其他的配置
|
||||||
apiGroup.POST("server-global", middleware.Permission(), api.Setting().SetServerGlobal) // 设置服务端全局配置
|
apiGroup.POST("server-global", middleware.Permission(), api.Setting().SetServerGlobal) // 设置服务端全局配置
|
||||||
|
@ -8,13 +8,13 @@ import (
|
|||||||
|
|
||||||
func UserApi(r *gin.RouterGroup) {
|
func UserApi(r *gin.RouterGroup) {
|
||||||
// 登陆相关API
|
// 登陆相关API
|
||||||
login := r.Group("/login")
|
login := r.Group("/login", middleware.SystemLogRequest())
|
||||||
{
|
{
|
||||||
login.POST("", api.UserApi().Login)
|
login.POST("", api.UserApi().Login)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户登陆后相关的API
|
// 用户登陆后相关的API
|
||||||
userApi := r.Group("user", middleware.Authorization())
|
userApi := r.Group("user", middleware.Authorization(), middleware.SystemLogRequest())
|
||||||
{
|
{
|
||||||
userApi.DELETE("logout", api.UserApi().Logout) // 用户退出登陆
|
userApi.DELETE("logout", api.UserApi().Logout) // 用户退出登陆
|
||||||
userApi.GET("", api.UserApi().GetUser) // 获取登陆用户信息
|
userApi.GET("", api.UserApi().GetUser) // 获取登陆用户信息
|
||||||
|
@ -47,6 +47,7 @@ func (s Script) DBMigrate() error {
|
|||||||
new(entity.Server),
|
new(entity.Server),
|
||||||
new(entity.Client),
|
new(entity.Client),
|
||||||
new(entity.Setting),
|
new(entity.Setting),
|
||||||
|
new(entity.SystemLog),
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.DB.AutoMigrate(ent...)
|
return client.DB.AutoMigrate(ent...)
|
||||||
|
Loading…
Reference in New Issue
Block a user