From 8c4918e4edd7435db04b173d4a4942d3192a8201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=96=8C?= <259278618@qq.com> Date: Tue, 30 Dec 2025 18:18:56 +0800 Subject: [PATCH] =?UTF-8?q?mongo=E5=BC=80=E5=8F=91=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB=E5=A2=9E=E5=8A=A0=E5=A2=9E=E5=88=A0=E6=94=B9=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=97=A5=E5=BF=97=E5=86=99=E5=85=A5redis=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- log/controller/log_controller.go | 25 ----------- log/dao/log_dao.go | 20 +++------ log/model/dto/log_dto.go | 73 ++++++++------------------------ log/model/entity/log.go | 20 +++------ log/service/log_service.go | 55 ++++++++++-------------- mongo/mongo.go | 51 ++++++++++++++++++++++ 6 files changed, 106 insertions(+), 138 deletions(-) diff --git a/log/controller/log_controller.go b/log/controller/log_controller.go index e9cb10c..996293d 100644 --- a/log/controller/log_controller.go +++ b/log/controller/log_controller.go @@ -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 -} diff --git a/log/dao/log_dao.go b/log/dao/log_dao.go index 4b75dec..c459117 100644 --- a/log/dao/log_dao.go +++ b/log/dao/log_dao.go @@ -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 != "" { diff --git a/log/model/dto/log_dto.go b/log/model/dto/log_dto.go index 148e141..81e8b29 100644 --- a/log/model/dto/log_dto.go +++ b/log/model/dto/log_dto.go @@ -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:"当前数据"` } diff --git a/log/model/entity/log.go b/log/model/entity/log.go index e180a77..cfa8f28 100644 --- a/log/model/entity/log.go +++ b/log/model/entity/log.go @@ -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"` // 当前数据:操作时的数据状态 } diff --git a/log/service/log_service.go b/log/service/log_service.go index ba99f15..cc9ea4e 100644 --- a/log/service/log_service.go +++ b/log/service/log_service.go @@ -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 "" } diff --git a/mongo/mongo.go b/mongo/mongo.go index 101f2d1..466021a 100644 --- a/mongo/mongo.go +++ b/mongo/mongo.go @@ -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 }