feat: 添加mml日志和操作日志收集中间件

This commit is contained in:
TsMask
2023-10-20 18:34:18 +08:00
parent b52a08aeb3
commit 0633f38ca0
3 changed files with 218 additions and 13 deletions

68
lib/midware/mml_log.go Normal file
View File

@@ -0,0 +1,68 @@
package midware
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
"ems.agt/lib/core/datasource"
"ems.agt/lib/core/utils/ctx"
"ems.agt/lib/core/utils/date"
"ems.agt/lib/dborm"
"ems.agt/lib/log"
)
// LogMML mml操作日志搜集
func LogMML(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 读取请求体内容
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
// 解析json内参数
var bodyArgs map[string]any
_ = json.Unmarshal(bytes.Clone(body), &bodyArgs)
// 将请求体内容存储在临时缓冲区中
buffer := bytes.NewBuffer(body)
r.Body = io.NopCloser(buffer)
next.ServeHTTP(w, r)
// 收尾存入数据库的参数
mmlCmd := bodyArgs["mml"].([]any)[0]
ipAddr := strings.Split(r.RemoteAddr, ":")[0]
neType := ctx.Param(r, "elementTypeValue")
neId := ctx.GetQuery(r, "ne_id")
timeStr := date.ParseDateToStr(time.Now(), date.YYYY_MM_DD_HH_MM_SS)
// 响应内容长度和状态码作为结果
str := strings.TrimSuffix(fmt.Sprintf("%v", w), "}")
strArr := strings.Split(str, " ")
size := strArr[1]
status := strArr[2]
contentType := w.Header().Get("Content-Type")
resultStr := fmt.Sprintf(`{"status":"%s","size":"%s","content-type":"%s"}`, status, size, contentType)
// 用户名
username := "-"
accessToken := r.Header.Get("AccessToken")
if accessToken != "" {
// 验证令牌 == 这里直接查数据库session
se, _ := dborm.XormUpdateSessionShakeTime(accessToken)
username = se.AccountId
}
// 执行插入
sql := "insert into mml_log (user,ip,ne_type,ne_id,mml,result,log_time)values(?,?,?,?,?,?,?)"
_, sqlerr := datasource.ExecDB("", sql, []any{username, ipAddr, neType, neId, mmlCmd, resultStr, timeStr})
if sqlerr != nil {
log.Errorf("insert row : %v", err.Error())
}
})
}

136
lib/midware/operate_log.go Normal file
View File

@@ -0,0 +1,136 @@
package midware
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"reflect"
"runtime"
"strings"
"time"
"ems.agt/lib/core/utils/parse"
"ems.agt/lib/dborm"
"ems.agt/src/framework/constants/common"
"ems.agt/src/framework/middleware/collectlogs"
"ems.agt/src/framework/utils/ip2region"
"ems.agt/src/modules/system/model"
"ems.agt/src/modules/system/service"
)
// 敏感属性字段进行掩码
var maskProperties []string = []string{
"password",
"oldPassword",
"newPassword",
"confirmPassword",
}
// LogOperate 操作日志搜集
func LogOperate(options collectlogs.Options) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
// 函数名
funcName := runtime.FuncForPC(reflect.ValueOf(next).Pointer()).Name()
lastDotIndex := strings.LastIndex(funcName, "/")
funcName = funcName[lastDotIndex+1:]
// 用户名
username := "-"
accessToken := r.Header.Get("AccessToken")
if accessToken != "" {
// 验证令牌 == 这里直接查数据库session
se, _ := dborm.XormUpdateSessionShakeTime(accessToken)
username = se.AccountId
}
// 解析ip地址
ip := strings.Split(r.RemoteAddr, ":")[0]
ipaddr := ip2region.ClientIP(ip)
location := ip2region.RealAddressByIp(ipaddr)
// 操作日志记录
operLog := model.SysLogOperate{
Title: options.Title,
BusinessType: options.BusinessType,
OperatorType: collectlogs.OPERATOR_TYPE_MANAGE,
Method: funcName,
OperURL: r.RequestURI,
RequestMethod: r.Method,
OperIP: ipaddr,
OperLocation: location,
OperName: username,
DeptName: "",
}
// 是否需要保存request参数和值
if options.IsSaveRequestData && (r.Method == "POST" || r.Method == "PUT") {
// 读取请求体内容
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
// 解析json内参数
var bodyArgs map[string]any
_ = json.Unmarshal(bytes.Clone(body), &bodyArgs)
// 将请求体内容存储在临时缓冲区中
buffer := bytes.NewBuffer(body)
r.Body = io.NopCloser(buffer)
params := bodyArgs
for k, v := range params {
// 敏感属性字段进行掩码
for _, s := range maskProperties {
if s == k {
params[k] = parse.SafeContent(v.(string))
break
}
}
}
jsonStr, _ := json.Marshal(params)
paramsStr := string(jsonStr)
if len(paramsStr) > 2000 {
paramsStr = paramsStr[:2000]
}
operLog.OperParam = paramsStr
}
next.ServeHTTP(w, r)
// 响应内容长度和状态码作为结果
str := strings.TrimSuffix(fmt.Sprintf("%v", w), "}")
strArr := strings.Split(str, " ")
size := strArr[1]
status := strArr[2]
// 响应状态
if status == "200" {
operLog.Status = common.STATUS_YES
} else {
operLog.Status = common.STATUS_NO
}
// 是否需要保存response参数和值
if options.IsSaveResponseData {
contentDisposition := w.Header().Get("Content-Disposition")
contentType := w.Header().Get("Content-Type")
content := contentType + contentDisposition
msg := fmt.Sprintf(`{"status":"%s","size":"%s","content-type":"%s"}`, status, size, content)
operLog.OperMsg = msg
}
// 日志记录时间
duration := time.Since(startTime)
operLog.CostTime = duration.Milliseconds()
operLog.OperTime = time.Now().UnixMilli()
// 保存操作记录到数据库
service.NewSysLogOperateImpl.InsertSysLogOperate(operLog)
})
}
}