zhangqian
2023-08-26 5193dcb9336e853502baf8a539d3f45efebe2f86
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package middleware
 
import (
    "bytes"
    "encoding/json"
    "io"
    "net/http"
    "net/url"
    "strconv"
    "strings"
    "sync"
    "time"
 
    "srm/utils"
 
    "github.com/gin-gonic/gin"
    "go.uber.org/zap"
    "srm/global"
    "srm/model/system"
    "srm/service"
)
 
var operationRecordService = service.ServiceGroupApp.SystemServiceGroup.OperationRecordService
 
var respPool sync.Pool
 
func init() {
    respPool.New = func() interface{} {
        return make([]byte, 1024)
    }
}
 
func OperationRecord() gin.HandlerFunc {
    return func(c *gin.Context) {
        var body []byte
        var userId int
        if c.Request.Method != http.MethodGet {
            var err error
            body, err = io.ReadAll(c.Request.Body)
            if err != nil {
                global.GVA_LOG.Error("read body from request error:", zap.Error(err))
            } else {
                c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
            }
        } else {
            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)
        }
        claims, _ := utils.GetClaims(c)
        if claims.BaseClaims.ID != 0 {
            userId = int(claims.BaseClaims.ID)
        } else {
            id, err := strconv.Atoi(c.Request.Header.Get("x-user-id"))
            if err != nil {
                userId = 0
            }
            userId = id
        }
        record := system.SysOperationRecord{
            Ip:     c.ClientIP(),
            Method: c.Request.Method,
            Path:   c.Request.URL.Path,
            Agent:  c.Request.UserAgent(),
            Body:   string(body),
            UserID: userId,
        }
 
        // 上传文件时候 中间件日志进行裁断操作
        if strings.Contains(c.GetHeader("Content-Type"), "multipart/form-data") {
            if len(record.Body) > 1024 {
                // 截断
                newBody := respPool.Get().([]byte)
                copy(newBody, record.Body)
                record.Body = string(newBody)
                defer respPool.Put(newBody[:0])
            }
        }
 
        writer := responseBodyWriter{
            ResponseWriter: c.Writer,
            body:           &bytes.Buffer{},
        }
        c.Writer = writer
        now := time.Now()
 
        c.Next()
 
        latency := time.Since(now)
        record.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String()
        record.Status = c.Writer.Status()
        record.Latency = latency
        record.Resp = writer.body.String()
 
        if strings.Contains(c.Writer.Header().Get("Pragma"), "public") ||
            strings.Contains(c.Writer.Header().Get("Expires"), "0") ||
            strings.Contains(c.Writer.Header().Get("Cache-Control"), "must-revalidate, post-check=0, pre-check=0") ||
            strings.Contains(c.Writer.Header().Get("Content-Type"), "application/force-download") ||
            strings.Contains(c.Writer.Header().Get("Content-Type"), "application/octet-stream") ||
            strings.Contains(c.Writer.Header().Get("Content-Type"), "application/vnd.ms-excel") ||
            strings.Contains(c.Writer.Header().Get("Content-Type"), "application/download") ||
            strings.Contains(c.Writer.Header().Get("Content-Disposition"), "attachment") ||
            strings.Contains(c.Writer.Header().Get("Content-Transfer-Encoding"), "binary") {
            if len(record.Resp) > 1024 {
                // 截断
                newBody := respPool.Get().([]byte)
                copy(newBody, record.Resp)
                record.Resp = string(newBody)
                defer respPool.Put(newBody[:0])
            }
        }
 
        if err := operationRecordService.CreateSysOperationRecord(record); err != nil {
            global.GVA_LOG.Error("create operation record error:", zap.Error(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)
}