1Panel/backend/middleware/operation.go

112 lines
2.4 KiB
Go

package middleware
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
"github.com/1Panel-dev/1Panel/app/model"
"github.com/1Panel-dev/1Panel/app/service"
"github.com/1Panel-dev/1Panel/global"
"github.com/gin-gonic/gin"
)
func OperationRecord() gin.HandlerFunc {
return func(c *gin.Context) {
var body []byte
if strings.Contains(c.Request.URL.Path, "search") {
c.Next()
return
}
if c.Request.Method == http.MethodGet {
query := c.Request.URL.RawQuery
query, _ = url.QueryUnescape(query)
split := strings.Split(query, "&")
m := make(map[string]string)
for _, v := range split {
kv := strings.Split(v, "=")
if len(kv) == 2 {
m[kv[0]] = kv[1]
}
}
body, _ = json.Marshal(&m)
} else {
var err error
body, err = ioutil.ReadAll(c.Request.Body)
if err != nil {
global.LOG.Errorf("read body from request failed, err: %v", err)
} else {
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
}
}
pathInfo := loadLogInfo(c.Request.URL.Path)
record := model.OperationLog{
Group: pathInfo.group,
Source: pathInfo.source,
Action: pathInfo.action,
IP: c.ClientIP(),
Method: c.Request.Method,
Path: c.Request.URL.Path,
UserAgent: c.Request.UserAgent(),
Body: string(body),
}
writer := responseBodyWriter{
ResponseWriter: c.Writer,
body: &bytes.Buffer{},
}
c.Writer = writer
now := time.Now()
c.Next()
latency := time.Since(now)
record.Latency = latency
record.Resp = writer.body.String()
if err := service.NewIOperationService().Create(record); err != nil {
global.LOG.Errorf("create operation record failed, err: %v", err)
}
}
}
type responseBodyWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
func (r responseBodyWriter) Write(b []byte) (int, error) {
r.body.Write(b)
return r.ResponseWriter.Write(b)
}
type pathInfo struct {
group string
source string
action string
}
func loadLogInfo(path string) pathInfo {
path = strings.ReplaceAll(path, "/api/v1", "")
if !strings.Contains(path, "/") {
return pathInfo{}
}
pathArrys := strings.Split(path, "/")
if len(pathArrys) < 2 {
return pathInfo{}
}
if len(pathArrys) == 2 {
return pathInfo{group: pathArrys[1]}
}
if len(pathArrys) == 3 {
return pathInfo{group: pathArrys[1], source: pathArrys[2]}
}
return pathInfo{group: pathArrys[1], source: pathArrys[2], action: pathArrys[3]}
}