mongo开发工具类增加增删改操作日志写入redis消息逻辑
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/beans"
|
||||
"gitee.com/red-future---jilin-g/common/log/model/dto"
|
||||
"gitee.com/red-future---jilin-g/common/log/service"
|
||||
)
|
||||
@@ -50,27 +49,3 @@ func (c *operationLog) List(ctx context.Context, req *dto.ListLogsReq) (res *dto
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RecordCreate 记录创建操作日志
|
||||
// @Summary 记录创建操作日志
|
||||
// @Description 记录数据创建操作的行为日志
|
||||
func (c *operationLog) RecordCreate(ctx context.Context, req *dto.RecordCreateLogReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.OperationLog.RecordCreate(ctx, req.Module, req.Service, req.Resource, req.ResourceID, req.Description, req.AfterData)
|
||||
return
|
||||
}
|
||||
|
||||
// RecordUpdate 记录更新操作日志
|
||||
// @Summary 记录更新操作日志
|
||||
// @Description 记录数据更新操作的行为日志
|
||||
func (c *operationLog) RecordUpdate(ctx context.Context, req *dto.RecordUpdateLogReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.OperationLog.RecordUpdate(ctx, req.Module, req.Service, req.Resource, req.ResourceID, req.Description, req.BeforeData, req.AfterData)
|
||||
return
|
||||
}
|
||||
|
||||
// RecordDelete 记录删除操作日志
|
||||
// @Summary 记录删除操作日志
|
||||
// @Description 记录数据删除操作的行为日志
|
||||
func (c *operationLog) RecordDelete(ctx context.Context, req *dto.RecordDeleteLogReq) (res *beans.ResponseEmpty, err error) {
|
||||
err = service.OperationLog.RecordDelete(ctx, req.Module, req.Service, req.Resource, req.ResourceID, req.Description, req.BeforeData)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -100,24 +100,18 @@ func buildFilter(filter interface{}) bson.M {
|
||||
|
||||
// 从ListLogsReq结构体中提取字段值
|
||||
if req, ok := filter.(*dto.ListLogsReq); ok {
|
||||
if req.Module != "" {
|
||||
bsonFilter["module"] = req.Module
|
||||
if req.ServiceName != "" {
|
||||
bsonFilter["service_name"] = req.ServiceName
|
||||
}
|
||||
if req.Service != "" {
|
||||
bsonFilter["service"] = req.Service
|
||||
if req.Collection != "" {
|
||||
bsonFilter["collection"] = req.Collection
|
||||
}
|
||||
if req.CollectionID != "" {
|
||||
bsonFilter["collection_id"] = req.CollectionID
|
||||
}
|
||||
if req.Operation != "" {
|
||||
bsonFilter["operation"] = req.Operation
|
||||
}
|
||||
if req.Resource != "" {
|
||||
bsonFilter["resource"] = req.Resource
|
||||
}
|
||||
if req.ResourceID != "" {
|
||||
bsonFilter["resource_id"] = req.ResourceID
|
||||
}
|
||||
if req.UserID != "" {
|
||||
bsonFilter["user_id"] = req.UserID
|
||||
}
|
||||
|
||||
// 处理时间范围字段
|
||||
if req.StartTime != "" || req.EndTime != "" {
|
||||
|
||||
@@ -20,37 +20,27 @@ type GetLogResp struct {
|
||||
|
||||
// OperationLogInfo 操作日志信息
|
||||
type OperationLogInfo struct {
|
||||
ID string `json:"id" dc:"日志ID"`
|
||||
Module string `json:"module" dc:"模块名"`
|
||||
Service string `json:"service" dc:"服务名"`
|
||||
Operation string `json:"operation" dc:"操作类型"`
|
||||
Resource string `json:"resource" dc:"资源类型"`
|
||||
ResourceID string `json:"resource_id" dc:"资源ID"`
|
||||
UserID interface{} `json:"user_id" dc:"操作人ID"`
|
||||
UserName string `json:"user_name" dc:"操作人名称"`
|
||||
IPAddress string `json:"ip_address" dc:"操作IP地址"`
|
||||
UserAgent string `json:"user_agent" dc:"用户代理"`
|
||||
Description string `json:"description" dc:"操作描述"`
|
||||
BeforeData map[string]interface{} `json:"before_data" dc:"操作前的数据"`
|
||||
AfterData map[string]interface{} `json:"after_data" dc:"操作后的数据"`
|
||||
ExtraData map[string]interface{} `json:"extra_data" dc:"额外数据"`
|
||||
CreatedAt string `json:"created_at" dc:"创建时间"`
|
||||
UpdatedAt string `json:"updated_at" dc:"更新时间"`
|
||||
ID string `json:"id" dc:"日志ID"`
|
||||
ServiceName string `json:"service_name" dc:"服务名"`
|
||||
Collection string `json:"collection" dc:"数据所在集合名称"`
|
||||
CollectionID string `json:"collection_id" dc:"数据ID"`
|
||||
Operation string `json:"operation" dc:"操作类型"`
|
||||
UserName string `json:"user_name" dc:"操作人名称"`
|
||||
IPAddress string `json:"ip_address" dc:"操作IP地址"`
|
||||
Data map[string]interface{} `json:"data" dc:"当前数据"`
|
||||
}
|
||||
|
||||
// ListLogsReq 查询操作日志列表请求(通用方法,支持根据不同条件动态查询)
|
||||
type ListLogsReq struct {
|
||||
g.Meta `path:"/listLogs" method:"get" tags:"操作日志" summary:"查询操作日志列表" dc:"根据多个条件查询操作日志列表"`
|
||||
beans.Page
|
||||
Module string `json:"module" dc:"模块名(可选)"`
|
||||
Service string `json:"service" dc:"服务名(可选)"`
|
||||
Operation string `json:"operation" dc:"操作类型(可选)"`
|
||||
Resource string `json:"resource" dc:"资源类型(可选)"`
|
||||
ResourceID string `json:"resource_id" dc:"资源ID(可选)"`
|
||||
UserID string `json:"user_id" dc:"用户ID(可选)"`
|
||||
StartTime string `json:"start_time" dc:"开始时间(可选)"`
|
||||
EndTime string `json:"end_time" dc:"结束时间(可选)"`
|
||||
SortFields string `json:"sort_fields" dc:"排序字段,多个用逗号分隔,如:-createdAt,module(可选)"`
|
||||
ServiceName string `json:"service_name" dc:"服务名(可选)"`
|
||||
Collection string `json:"collection" dc:"数据所在集合名称(可选)"`
|
||||
CollectionID string `json:"collection_id" dc:"数据ID(可选)"`
|
||||
Operation string `json:"operation" dc:"操作类型(可选)"`
|
||||
StartTime string `json:"start_time" dc:"开始时间(可选)"`
|
||||
EndTime string `json:"end_time" dc:"结束时间(可选)"`
|
||||
SortFields string `json:"sort_fields" dc:"排序字段,多个用逗号分隔,如:-createdAt"`
|
||||
}
|
||||
|
||||
// ListLogsResp 查询操作日志列表响应
|
||||
@@ -63,34 +53,7 @@ type ListLogsResp struct {
|
||||
|
||||
// RecordCreateLogReq 记录创建操作日志请求
|
||||
type RecordCreateLogReq struct {
|
||||
g.Meta `path:"/recordCreateLog" method:"post" tags:"操作日志" summary:"记录创建操作日志" dc:"记录数据创建操作的行为日志"`
|
||||
Module string `json:"module" v:"required" dc:"模块名"`
|
||||
Service string `json:"service" v:"required" dc:"服务名"`
|
||||
Resource string `json:"resource" v:"required" dc:"资源类型"`
|
||||
ResourceID string `json:"resource_id" v:"required" dc:"资源ID"`
|
||||
Description string `json:"description" dc:"操作描述"`
|
||||
AfterData map[string]interface{} `json:"after_data" dc:"操作后的数据"`
|
||||
}
|
||||
|
||||
// RecordUpdateLogReq 记录更新操作日志请求
|
||||
type RecordUpdateLogReq struct {
|
||||
g.Meta `path:"/recordUpdateLog" method:"post" tags:"操作日志" summary:"记录更新操作日志" dc:"记录数据更新操作的行为日志"`
|
||||
Module string `json:"module" v:"required" dc:"模块名"`
|
||||
Service string `json:"service" v:"required" dc:"服务名"`
|
||||
Resource string `json:"resource" v:"required" dc:"资源类型"`
|
||||
ResourceID string `json:"resource_id" v:"required" dc:"资源ID"`
|
||||
Description string `json:"description" dc:"操作描述"`
|
||||
BeforeData map[string]interface{} `json:"before_data" dc:"操作前的数据"`
|
||||
AfterData map[string]interface{} `json:"after_data" dc:"操作后的数据"`
|
||||
}
|
||||
|
||||
// RecordDeleteLogReq 记录删除操作日志请求
|
||||
type RecordDeleteLogReq struct {
|
||||
g.Meta `path:"/recordDeleteLog" method:"post" tags:"操作日志" summary:"记录删除操作日志" dc:"记录数据删除操作的行为日志"`
|
||||
Module string `json:"module" v:"required" dc:"模块名"`
|
||||
Service string `json:"service" v:"required" dc:"服务名"`
|
||||
Resource string `json:"resource" v:"required" dc:"资源类型"`
|
||||
ResourceID string `json:"resource_id" v:"required" dc:"资源ID"`
|
||||
Description string `json:"description" dc:"操作描述"`
|
||||
BeforeData map[string]interface{} `json:"before_data" dc:"操作前的数据"`
|
||||
ServiceName string `json:"service_name" v:"required" dc:"服务名"`
|
||||
Collection string `json:"collection" v:"required" dc:"数据所在集合名称"`
|
||||
Data []interface{} `json:"data" dc:"当前数据"`
|
||||
}
|
||||
|
||||
@@ -8,17 +8,11 @@ import (
|
||||
type OperationLog struct {
|
||||
do.MongoBaseDO `bson:",inline"`
|
||||
|
||||
Module string `bson:"module" json:"module"` // 模块名:如 order, wallet, market 等
|
||||
Service string `bson:"service" json:"service"` // 服务名:具体的微服务名称
|
||||
Operation string `bson:"operation" json:"operation"` // 操作类型:create, update, delete
|
||||
Resource string `bson:"resource" json:"resource"` // 资源类型:如 order, wallet, product 等
|
||||
ResourceID string `bson:"resource_id" json:"resource_id"` // 资源ID:具体操作的数据ID,如订单号、钱包ID等
|
||||
UserID interface{} `bson:"user_id" json:"user_id"` // 操作人ID
|
||||
UserName string `bson:"user_name" json:"user_name"` // 操作人名称
|
||||
IPAddress string `bson:"ip_address" json:"ip_address"` // 操作IP地址
|
||||
UserAgent string `bson:"user_agent" json:"user_agent"` // 用户代理
|
||||
Description string `bson:"description" json:"description"` // 操作描述
|
||||
BeforeData map[string]interface{} `bson:"before_data,omitempty" json:"before_data"` // 操作前的数据(用于update/delete)
|
||||
AfterData map[string]interface{} `bson:"after_data,omitempty" json:"after_data"` // 操作后的数据(用于create/update)
|
||||
ExtraData map[string]interface{} `bson:"extra_data,omitempty" json:"extra_data"` // 额外数据
|
||||
ServiceName string `bson:"service_name" json:"service_name"` // 服务名:具体的微服务名称
|
||||
Collection string `bson:"collection" json:"collection"` // 集合名:数据所在的集合名称
|
||||
CollectionID string `bson:"collection_id" json:"collection_id"` // 数据ID:具体操作的数据ID,如订单号、钱包ID等
|
||||
Operation string `bson:"operation" json:"operation"` // 操作类型:create, update, delete
|
||||
UserName string `bson:"user_name" json:"user_name"` // 操作人名称
|
||||
IPAddress string `bson:"ip_address" json:"ip_address"` // 操作IP地址
|
||||
Data map[string]interface{} `bson:"data,omitempty" json:"data"` // 当前数据:操作时的数据状态
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
logEntity "gitee.com/red-future---jilin-g/common/log/model/entity"
|
||||
"gitee.com/red-future---jilin-g/common/utils"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
@@ -19,18 +18,18 @@ type operationLog struct{}
|
||||
var OperationLog = &operationLog{}
|
||||
|
||||
// RecordCreate 记录创建操作
|
||||
func (s *operationLog) RecordCreate(ctx context.Context, module, service, resource, resourceID, description string, afterData map[string]interface{}) error {
|
||||
return s.record(ctx, module, service, string(consts.OperationCreate), resource, resourceID, description, nil, afterData, nil)
|
||||
func (s *operationLog) RecordCreate(ctx context.Context, serviceName, collection, collectionID string, data map[string]interface{}) error {
|
||||
return s.record(ctx, serviceName, collection, collectionID, string(consts.OperationCreate), data)
|
||||
}
|
||||
|
||||
// RecordUpdate 记录更新操作
|
||||
func (s *operationLog) RecordUpdate(ctx context.Context, module, service, resource, resourceID, description string, beforeData, afterData map[string]interface{}) error {
|
||||
return s.record(ctx, module, service, string(consts.OperationUpdate), resource, resourceID, description, beforeData, afterData, nil)
|
||||
func (s *operationLog) RecordUpdate(ctx context.Context, serviceName, collection, collectionID string, data map[string]interface{}) error {
|
||||
return s.record(ctx, serviceName, collection, collectionID, string(consts.OperationUpdate), data)
|
||||
}
|
||||
|
||||
// RecordDelete 记录删除操作
|
||||
func (s *operationLog) RecordDelete(ctx context.Context, module, service, resource, resourceID, description string, beforeData map[string]interface{}) error {
|
||||
return s.record(ctx, module, service, string(consts.OperationDelete), resource, resourceID, description, beforeData, nil, nil)
|
||||
func (s *operationLog) RecordDelete(ctx context.Context, serviceName, collection, collectionID string, data map[string]interface{}) error {
|
||||
return s.record(ctx, serviceName, collection, collectionID, string(consts.OperationDelete), data)
|
||||
}
|
||||
|
||||
// BatchRecordCreate 批量记录创建操作
|
||||
@@ -46,22 +45,22 @@ func (s *operationLog) GetByID(ctx context.Context, id string) (*dto.OperationLo
|
||||
}
|
||||
|
||||
var logInfo dto.OperationLogInfo
|
||||
gconv.Struct(log, &logInfo)
|
||||
if err := gconv.Struct(log, &logInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logInfo.ID = log.Id.Hex()
|
||||
logInfo.CreatedAt = gtime.New(log.CreatedAt).Format("Y-m-d H:i:s")
|
||||
logInfo.UpdatedAt = gtime.New(log.UpdatedAt).Format("Y-m-d H:i:s")
|
||||
return &logInfo, nil
|
||||
}
|
||||
|
||||
// List 查询操作日志列表
|
||||
func (s *operationLog) List(ctx context.Context, filter interface{}, sortFields ...string) ([]dto.OperationLogInfo, int64, error) {
|
||||
func (s *operationLog) List(ctx context.Context, filter *dto.ListLogsReq, sortFields ...string) ([]dto.OperationLogInfo, int64, error) {
|
||||
logs, total, err := dao.Log.List(ctx, filter, sortFields...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
var logInfos []dto.OperationLogInfo
|
||||
err = gconv.Slice(logs, &logInfos)
|
||||
err = gconv.Structs(logs, &logInfos)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
@@ -69,15 +68,13 @@ func (s *operationLog) List(ctx context.Context, filter interface{}, sortFields
|
||||
// 处理特殊字段
|
||||
for i, log := range logs {
|
||||
logInfos[i].ID = log.Id.Hex()
|
||||
logInfos[i].CreatedAt = gtime.New(log.CreatedAt).Format("Y-m-d H:i:s")
|
||||
logInfos[i].UpdatedAt = gtime.New(log.UpdatedAt).Format("Y-m-d H:i:s")
|
||||
}
|
||||
|
||||
return logInfos, total, nil
|
||||
}
|
||||
|
||||
// record 记录操作日志的通用方法
|
||||
func (s *operationLog) record(ctx context.Context, module, service, operation, resource, resourceID, description string, beforeData, afterData, extraData map[string]interface{}) error {
|
||||
func (s *operationLog) record(ctx context.Context, serviceName, collection, collectionID, operation string, data map[string]interface{}) error {
|
||||
// 获取用户信息
|
||||
user, err := utils.GetUserInfo(ctx)
|
||||
if err != nil {
|
||||
@@ -85,7 +82,7 @@ func (s *operationLog) record(ctx context.Context, module, service, operation, r
|
||||
}
|
||||
|
||||
// 获取请求信息
|
||||
ipAddress, userAgent := getHTTPRequestInfo(ctx)
|
||||
ipAddress := getHTTPRequestInfo(ctx)
|
||||
|
||||
var userName string
|
||||
if user.UserName != nil {
|
||||
@@ -93,29 +90,23 @@ func (s *operationLog) record(ctx context.Context, module, service, operation, r
|
||||
}
|
||||
|
||||
log := &logEntity.OperationLog{
|
||||
Module: module,
|
||||
Service: service,
|
||||
Operation: operation,
|
||||
Resource: resource,
|
||||
ResourceID: resourceID,
|
||||
UserID: user.UserName,
|
||||
UserName: userName,
|
||||
IPAddress: ipAddress,
|
||||
UserAgent: userAgent,
|
||||
Description: description,
|
||||
BeforeData: beforeData,
|
||||
AfterData: afterData,
|
||||
ExtraData: extraData,
|
||||
ServiceName: serviceName,
|
||||
Collection: collection,
|
||||
CollectionID: collectionID,
|
||||
Operation: operation,
|
||||
UserName: userName,
|
||||
IPAddress: ipAddress,
|
||||
Data: data,
|
||||
}
|
||||
|
||||
return dao.Log.Create(ctx, log)
|
||||
}
|
||||
|
||||
// getHTTPRequestInfo 从上下文中获取HTTP请求信息
|
||||
func getHTTPRequestInfo(ctx context.Context) (ipAddress, userAgent string) {
|
||||
func getHTTPRequestInfo(ctx context.Context) string {
|
||||
request := g.RequestFromCtx(ctx)
|
||||
if request != nil {
|
||||
return request.GetClientIp(), request.Header.Get("User-Agent")
|
||||
return request.GetClientIp()
|
||||
}
|
||||
return "", ""
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/log/model/dto"
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/consts"
|
||||
@@ -403,12 +404,25 @@ func (m *MongoDB) Delete(ctx context.Context, filter bson.M, collection string,
|
||||
return
|
||||
}
|
||||
filter["tenantId"] = user.TenantId
|
||||
var rows []interface{}
|
||||
if err = m.Find(ctx, filter, &rows, collection); err != nil {
|
||||
return
|
||||
}
|
||||
r, err := db.Collection(collection).DeleteMany(ctx, filter, opts...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
count = r.DeletedCount
|
||||
err = cleanRedis(ctx, filter, user.TenantId, collection)
|
||||
serverName := g.Cfg().MustGet(ctx, "server.name").String()
|
||||
logRedisKey := fmt.Sprintf("log:%s", serverName)
|
||||
if _, err = redis.AddToStream(ctx, logRedisKey, &dto.RecordCreateLogReq{
|
||||
ServiceName: serverName,
|
||||
Collection: collection,
|
||||
Data: rows,
|
||||
}); err != nil {
|
||||
glog.Error(ctx, "mongoLog-AddToStream err: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -432,11 +446,24 @@ func (m *MongoDB) Update(ctx context.Context, filter bson.M, update bson.M, coll
|
||||
}
|
||||
setDoc["updatedAt"] = gtime.Now().Time
|
||||
update = bson.M{"$set": setDoc}
|
||||
var rows []interface{}
|
||||
if err = m.Find(ctx, filter, &rows, collection); err != nil {
|
||||
return
|
||||
}
|
||||
result, err = db.Collection(collection).UpdateMany(ctx, filter, update, opts...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = cleanRedis(ctx, filter, user.TenantId, collection)
|
||||
serverName := g.Cfg().MustGet(ctx, "server.name").String()
|
||||
logRedisKey := fmt.Sprintf("log:%s", serverName)
|
||||
if _, err = redis.AddToStream(ctx, logRedisKey, &dto.RecordCreateLogReq{
|
||||
ServiceName: serverName,
|
||||
Collection: collection,
|
||||
Data: rows,
|
||||
}); err != nil {
|
||||
glog.Error(ctx, "mongoLog-AddToStream err: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -592,6 +619,30 @@ func (m *MongoDB) Insert(ctx context.Context, documents []interface{}, collectio
|
||||
}
|
||||
ids = r.InsertedIDs
|
||||
err = cleanRedis(ctx, bson.M{}, user.TenantId, collection)
|
||||
//写日志
|
||||
serverName := g.Cfg().MustGet(ctx, "server.name").String()
|
||||
logRedisKey := fmt.Sprintf("log:%s", serverName)
|
||||
if len(ids) == 0 {
|
||||
return
|
||||
}
|
||||
rows := make([]interface{}, 0, len(ids))
|
||||
if len(ids) == 1 {
|
||||
doc := gconv.Map(documents[0])
|
||||
doc["id"] = ids[0]
|
||||
rows = append(rows, doc)
|
||||
} else {
|
||||
filter := bson.M{"_id": bson.M{"$in": ids}}
|
||||
if err = m.Find(ctx, filter, &rows, collection); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if _, err = redis.AddToStream(ctx, logRedisKey, &dto.RecordCreateLogReq{
|
||||
ServiceName: serverName,
|
||||
Collection: collection,
|
||||
Data: rows,
|
||||
}); err != nil {
|
||||
glog.Error(ctx, "mongoLog-AddToStream err: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user