hotgo/hotgo-server/app/service/sysService/log_service.go
2022-02-25 17:11:17 +08:00

401 lines
9.9 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package sysService
import (
"context"
"encoding/json"
"github.com/bufanyun/hotgo/app/com"
"github.com/bufanyun/hotgo/app/consts"
"github.com/bufanyun/hotgo/app/factory/queue"
"github.com/bufanyun/hotgo/app/form/input"
"github.com/bufanyun/hotgo/app/model"
"github.com/bufanyun/hotgo/app/model/entity"
"github.com/bufanyun/hotgo/app/service/internal/dao"
"github.com/bufanyun/hotgo/app/utils"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"time"
)
var Log = new(log)
type log struct{}
//
//  @Title  导出
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   in
//  @Return  err
//
func (service *log) Export(ctx context.Context, in input.LogListInp) (err error) {
// 导出格式
type exportImage struct {
Id int64 `json:"id" description:""`
AppId string `json:"app_id" description:"应用id"`
Method string `json:"method" description:"提交类型"`
Module string `json:"module" description:"模块"`
Url string `json:"url" description:"提交url"`
Ip string `json:"ip" description:"ip地址"`
ErrorCode int `json:"error_code" description:"报错code"`
ErrorMsg string `json:"error_msg" description:"报错信息"`
ReqId string `json:"req_id" description:"对外id"`
TakeUpTime int64 `json:"take_up_time" description:"请求耗时"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
MemberName string `json:"member_name"`
Region string `json:"region"`
}
var (
titleList = []string{"ID", "应用", "提交类型", "模块", "提交url", "ip地址", "报错code", "报错信息", "对外id", "请求耗时", "创建时间", "用户", "访问地"}
fileName = "全局日志导出-" + com.Context.Get(ctx).ReqId + ".xlsx"
sheetName = "HotGo"
exportList []exportImage
row exportImage
)
list, _, err := service.List(ctx, in)
if err != nil {
return err
}
// TODO 格式化格式
for i := 0; i < len(list); i++ {
row.Id = list[i].Id
row.AppId = list[i].AppId
row.Module = list[i].Module
row.Method = list[i].Method
row.Url = list[i].Url
row.Ip = list[i].Ip
row.ReqId = list[i].ReqId
row.ErrorCode = list[i].ErrorCode
row.ErrorMsg = list[i].ErrorMsg
row.TakeUpTime = list[i].TakeUpTime
row.CreatedAt = list[i].CreatedAt
row.MemberName = list[i].MemberName
row.Region = list[i].Region
exportList = append(exportList, row)
}
// TODO 强转类型
writer := com.Context.Get(ctx).Request.Response.Writer
w, _ := interface{}(writer).(*ghttp.ResponseWriter)
if err = utils.Excel.ExportByStruct(w, titleList, gconv.Interfaces(exportList), fileName, sheetName); err != nil {
err = gerror.Wrap(err, "ExportByStruct:")
return err
}
// TODO 加入到上下文
com.Context.SetResponse(ctx, &model.Response{
Code: consts.CodeOK,
Message: "导出成功",
Timestamp: time.Now().Unix(),
ReqId: com.Context.Get(ctx).ReqId,
})
return
}
//
//  @Title  获取菜单列表
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   req
//  @Return  res
//  @Return  err
//
func (service *log) List(ctx context.Context, in input.LogListInp) (list []*input.LogListModel, totalCount int, err error) {
mod := dao.SysLog.Ctx(ctx)
// 访问路径
if in.Url != "" {
mod = mod.WhereLike("url", "%"+in.Url+"%")
}
// 模块
if in.Module != "" {
mod = mod.Where("module", in.Module)
}
// 请求方式
if in.Method != "" {
mod = mod.Where("method", in.Method)
}
// 用户
if in.MemberId > 0 {
mod = mod.Where("member_id", in.MemberId)
}
// 访问IP
if in.Ip != "" {
mod = mod.Where("ip", in.Ip)
}
// 日期范围
if in.StartTime != "" {
mod = mod.WhereGTE("created_at", in.StartTime)
}
if in.EndTime != "" {
mod = mod.WhereLTE("created_at", in.EndTime)
}
// 状态码
if in.ErrorCode != "" {
mod = mod.Where("error_code", in.ErrorCode)
}
// 请求耗时
if in.TakeUpTime > 0 {
mod = mod.WhereGTE("take_up_time", in.TakeUpTime)
}
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
err = mod.Page(in.Page, in.Limit).Order("id desc").Scan(&list)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
for i := 0; i < len(list); i++ {
// TODO  管理员
if list[i].AppId == consts.AppAdmin {
memberName, err := dao.AdminMember.Ctx(ctx).Fields("realname").Where("id", list[i].MemberId).Value()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
list[i].MemberName = memberName.String()
}
// TODO  接口
if list[i].AppId == consts.AppApi {
//memberName, err = dao.Member.Ctx(ctx).Fields("realname").Where("id", res.List[i].MemberId).Value()
//if err != nil {
// err = gerror.Wrap(err, consts.ErrorORM)
// return nil, err
//}
}
if list[i].MemberName == "" {
list[i].MemberName = "游客"
}
// TODO  获取省市编码对应的地区名称
region, err := dao.SysProvinces.GetRegion(ctx, list[i].ProvinceId, list[i].CityId)
if err != nil {
return list, totalCount, err
}
list[i].Region = region
// TODO  截取请求url路径
if gstr.Contains(list[i].Url, "?") {
list[i].Url = gstr.StrTillEx(list[i].Url, "?")
}
}
return list, totalCount, err
}
//
//  @Title  真实写入
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   commonLog
//  @Return  err
//
func (service *log) RealWrite(ctx context.Context, commonLog entity.SysLog) error {
result, err := dao.SysLog.Ctx(ctx).Data(commonLog).Insert()
if err != nil {
return err
}
if _, err := result.LastInsertId(); err != nil {
return err
}
return nil
}
//
//  @Title  根据配置自动记录请求日志
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Return  err
//
func (service *log) AutoLog(ctx context.Context) (err error) {
// TODO 日志开关
logSwitch, _ := g.Cfg().Get(ctx, "hotgo.log.switch", true)
if !logSwitch.Bool() {
return nil
}
data := service.AnalysisLog(ctx)
// TODO 判断模块是否需要记录
module, _ := g.Cfg().Get(ctx, "hotgo.log.module", nil)
if module == nil {
return nil
}
if exist := utils.Charset.IsExists(module.Strings(), data.Module); !exist {
return nil
}
// TODO 判断状态码是否需要记录
code, _ := g.Cfg().Get(ctx, "hotgo.log.skipCode", nil)
if code != nil {
if exist := utils.Charset.IsExists(code.Strings(), gconv.String(data.ErrorCode)); exist {
return nil
}
}
// TODO 是否开启队列
queueSwitch, _ := g.Cfg().Get(ctx, "hotgo.log.queue", true)
if queueSwitch.Bool() {
// TODO 获取生产者实例
queueInstance, err := queue.InstanceProducer()
if err != nil {
queue.FatalLog(ctx, "InstanceProducer异常", err)
return err
}
// TODO 生产消息
mqMsg, err := queueInstance.SendMsg(consts.QueueLogTopic, gconv.String(data))
// TODO 记录生产日志
queue.ProducerLog(ctx, consts.QueueLogTopic, mqMsg.MsgId, err)
return err
}
return service.RealWrite(ctx, data)
}
//
//  @Title  队列消费
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Param   mqMsg
//  @Return  err
//
func (service *log) QueueJob(ctx context.Context, mqMsg queue.MqMsg) (err error) {
var data entity.SysLog
if err = json.Unmarshal(mqMsg.Body, &data); err != nil {
return err
}
return service.RealWrite(ctx, data)
}
//
//  @Title  解析日志数据
//  @Description
//  @Author  Ms <133814250@qq.com>
//  @Param   ctx
//  @Return  entity.SysLog
//
func (service *log) AnalysisLog(ctx context.Context) entity.SysLog {
var (
modelContext = com.Context.Get(ctx)
response = modelContext.ComResponse
user = modelContext.User
request = modelContext.Request
module = modelContext.Module
ip = request.GetClientIp()
locationData = com.Ip.GetLocation(ctx, ip)
postData = "null"
getData = "null"
headerData = "null"
data = entity.SysLog{}
memberId = 0
errorCode = 0
errorMsg = ""
errorData = "null"
reqId = ""
timestamp = 0
appId = ""
)
// TODO 响应数据
if response != nil {
errorCode = response.Code
errorMsg = response.Message
reqId = response.ReqId
timestamp = gconv.Int(response.Timestamp)
if len(gconv.String(response.Error)) > 0 {
errorData = gconv.String(response.Error)
}
}
// TODO 请求头
if reqHeadersBytes, _ := json.Marshal(request.Header); len(gconv.String(reqHeadersBytes)) > 0 {
headerData = gconv.String(reqHeadersBytes)
}
// TODO post参数
if gconv.String(request.PostForm) != "" {
postData = gconv.String(request.PostForm)
}
// TODO get参数
if len(request.URL.Query()) > 0 {
getData = gconv.String(request.URL.Query())
}
// TODO 当前登录用户
if user != nil {
memberId = int(user.Id)
appId = user.App
}
data = entity.SysLog{
AppId: appId,
MerchantId: 0,
MemberId: memberId,
Method: request.Method,
Module: module,
Url: request.RequestURI,
GetData: getData,
PostData: postData,
HeaderData: headerData,
Ip: ip,
ProvinceId: locationData.ProvinceCode,
CityId: locationData.CityCode,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
ErrorData: errorData,
ReqId: reqId,
Timestamp: timestamp,
UserAgent: request.Header.Get("User-Agent"),
Status: consts.StatusEnabled,
TakeUpTime: modelContext.TakeUpTime,
}
return data
}