hotgo/hotgo-server/app/service/sysService/log_service.go

401 lines
9.9 KiB
Go
Raw Normal View History

2022-02-25 17:11:17 +08:00
//
// @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
}