hotgo/server/internal/logic/sys/log.go

397 lines
10 KiB
Go
Raw Normal View History

2022-11-24 23:37:34 +08:00
// Package sys
2022-02-25 17:11:17 +08:00
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
2022-11-24 23:37:34 +08:00
// @Author Ms <133814250@qq.com>
2022-02-25 17:11:17 +08:00
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
2022-11-24 23:37:34 +08:00
package sys
2022-02-25 17:11:17 +08:00
import (
"context"
"encoding/json"
"github.com/gogf/gf/v2/encoding/gjson"
2022-02-25 17:11:17 +08:00
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
2022-11-24 23:37:34 +08:00
"github.com/gogf/gf/v2/os/gctx"
2022-02-25 17:11:17 +08:00
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
2022-11-24 23:37:34 +08:00
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/location"
"hotgo/internal/library/queue"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/excel"
"hotgo/utility/validate"
2022-02-25 17:11:17 +08:00
)
2022-11-24 23:37:34 +08:00
type sSysLog struct{}
2022-02-25 17:11:17 +08:00
2022-11-24 23:37:34 +08:00
func NewSysLog() *sSysLog {
return &sSysLog{}
}
2022-02-25 17:11:17 +08:00
2022-11-24 23:37:34 +08:00
func init() {
service.RegisterSysLog(NewSysLog())
}
2022-02-25 17:11:17 +08:00
2022-11-24 23:37:34 +08:00
// Export 导出
func (s *sSysLog) Export(ctx context.Context, in sysin.LogListInp) (err error) {
2022-02-25 17:11:17 +08:00
// 导出格式
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", "请求耗时", "创建时间", "用户", "访问地"}
2022-11-24 23:37:34 +08:00
fileName = "全局日志导出-" + gctx.CtxId(ctx) + ".xlsx"
2022-02-25 17:11:17 +08:00
sheetName = "HotGo"
exportList []exportImage
row exportImage
)
2022-11-24 23:37:34 +08:00
list, _, err := s.List(ctx, in)
2022-02-25 17:11:17 +08:00
if err != nil {
return err
}
2022-11-24 23:37:34 +08:00
// 格式化格式
2022-02-25 17:11:17 +08:00
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)
}
if err = excel.ExportByStructs(ctx, titleList, exportList, fileName, sheetName); err != nil {
2022-02-25 17:11:17 +08:00
return err
}
return
}
2022-11-24 23:37:34 +08:00
// RealWrite 真实写入
func (s *sSysLog) RealWrite(ctx context.Context, commonLog entity.SysLog) error {
2022-02-25 17:11:17 +08:00
result, err := dao.SysLog.Ctx(ctx).Data(commonLog).Insert()
if err != nil {
return err
}
if _, err = result.LastInsertId(); err != nil {
2022-02-25 17:11:17 +08:00
return err
}
return nil
}
2022-11-24 23:37:34 +08:00
// AutoLog 根据配置自动记录请求日志
func (s *sSysLog) AutoLog(ctx context.Context) (err error) {
config, err := service.SysConfig().GetLoadLog(ctx)
if err != nil {
return err
2022-02-25 17:11:17 +08:00
}
if !config.Switch {
2022-02-25 17:11:17 +08:00
return nil
}
data := s.AnalysisLog(ctx)
if ok := validate.InSliceExistStr(config.Module, data.Module); !ok {
2022-02-25 17:11:17 +08:00
return nil
}
if ok := validate.InSliceExistStr(config.SkipCode, gconv.String(data.ErrorCode)); ok {
return nil
2022-02-25 17:11:17 +08:00
}
if config.Queue {
q, err := queue.InstanceProducer()
2022-02-25 17:11:17 +08:00
if err != nil {
queue.FatalLog(ctx, "queue.InstanceProducer err:%+v", err)
2022-02-25 17:11:17 +08:00
return err
}
mqMsg, err := q.SendMsg(consts.QueueLogTopic, gconv.String(data))
2022-02-25 17:11:17 +08:00
queue.ProducerLog(ctx, consts.QueueLogTopic, mqMsg.MsgId, err)
return err
}
2022-11-24 23:37:34 +08:00
return s.RealWrite(ctx, data)
2022-02-25 17:11:17 +08:00
}
2022-11-24 23:37:34 +08:00
// QueueJob 队列消费
func (s *sSysLog) QueueJob(ctx context.Context, mqMsg queue.MqMsg) (err error) {
2022-02-25 17:11:17 +08:00
var data entity.SysLog
if err = json.Unmarshal(mqMsg.Body, &data); err != nil {
return err
}
2022-11-24 23:37:34 +08:00
return s.RealWrite(ctx, data)
2022-02-25 17:11:17 +08:00
}
2022-11-24 23:37:34 +08:00
// AnalysisLog 解析日志数据
func (s *sSysLog) AnalysisLog(ctx context.Context) entity.SysLog {
2022-02-25 17:11:17 +08:00
var (
2022-11-24 23:37:34 +08:00
modelContext = contexts.Get(ctx)
response = modelContext.Response
user = modelContext.User
request = ghttp.RequestFromCtx(ctx)
module = modelContext.Module
clientIp = request.GetClientIp()
postData = gjson.New(consts.NilJsonToString)
getData = gjson.New(consts.NilJsonToString)
headerData = gjson.New(consts.NilJsonToString)
2022-11-24 23:37:34 +08:00
data = entity.SysLog{}
memberId int64 = 0
errorCode = 0
errorMsg = ""
errorData = gjson.New(consts.NilJsonToString)
2022-11-24 23:37:34 +08:00
traceID = ""
timestamp int64 = 0
appId = ""
2022-02-25 17:11:17 +08:00
)
2022-11-24 23:37:34 +08:00
// 响应数据
2022-02-25 17:11:17 +08:00
if response != nil {
errorCode = response.Code
errorMsg = response.Message
2022-11-24 23:37:34 +08:00
traceID = response.TraceID
timestamp = response.Timestamp
2022-02-25 17:11:17 +08:00
if len(gconv.String(response.Error)) > 0 {
errorData = gjson.New(response.Error)
2022-02-25 17:11:17 +08:00
}
}
2022-11-24 23:37:34 +08:00
// 请求头
2022-02-25 17:11:17 +08:00
if reqHeadersBytes, _ := json.Marshal(request.Header); len(gconv.String(reqHeadersBytes)) > 0 {
headerData = gjson.New(reqHeadersBytes)
2022-02-25 17:11:17 +08:00
}
2022-11-24 23:37:34 +08:00
// post参数
2022-02-25 17:11:17 +08:00
if gconv.String(request.PostForm) != "" {
postData = gjson.New(gconv.String(request.PostForm))
}
if postData.IsNil() {
postData = gjson.New(request.GetBodyString())
2022-02-25 17:11:17 +08:00
}
2022-11-24 23:37:34 +08:00
// get参数
2022-02-25 17:11:17 +08:00
if len(request.URL.Query()) > 0 {
getData = gjson.New(request.URL.Query())
2022-02-25 17:11:17 +08:00
}
2022-11-24 23:37:34 +08:00
// 当前登录用户
2022-02-25 17:11:17 +08:00
if user != nil {
2022-11-24 23:37:34 +08:00
memberId = user.Id
2022-02-25 17:11:17 +08:00
appId = user.App
}
var ipData = new(location.IpLocationData)
//if validate.IsPublicIp(clientIp) {
// ipData, err := location.GetLocation(ctx, clientIp)
// if err != nil {
// g.Log().Errorf(ctx, "location.GetLocation err:%+v", err)
// }
// if ipData == nil {
// ipData = new(location.IpLocationData)
// }
//}
ipData, err := location.GetLocation(ctx, clientIp)
if err != nil {
g.Log().Errorf(ctx, "location.GetLocation err:%+v", err)
}
if ipData == nil {
ipData = new(location.IpLocationData)
}
2022-02-25 17:11:17 +08:00
data = entity.SysLog{
AppId: appId,
MerchantId: 0,
MemberId: memberId,
Method: request.Method,
Module: module,
Url: request.RequestURI,
GetData: getData,
PostData: postData,
HeaderData: headerData,
2022-11-24 23:37:34 +08:00
Ip: clientIp,
ProvinceId: ipData.ProvinceCode,
CityId: ipData.CityCode,
2022-02-25 17:11:17 +08:00
ErrorCode: errorCode,
ErrorMsg: errorMsg,
ErrorData: errorData,
2022-11-24 23:37:34 +08:00
ReqId: traceID,
2022-02-25 17:11:17 +08:00
Timestamp: timestamp,
UserAgent: request.Header.Get("User-Agent"),
Status: consts.StatusEnabled,
TakeUpTime: modelContext.TakeUpTime,
}
return data
}
2022-11-24 23:37:34 +08:00
// View 获取指定字典类型信息
func (s *sSysLog) View(ctx context.Context, in sysin.LogViewInp) (res *sysin.LogViewModel, err error) {
if err = dao.SysLog.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
isDemo := g.Cfg().MustGet(ctx, "hotgo.isDemo", false)
2022-11-24 23:37:34 +08:00
if isDemo.Bool() {
// res.HeaderData = `{
// "none": [
// "` + consts.DemoTips + `"
// ]
//}`
2022-11-24 23:37:34 +08:00
}
return res, nil
}
// Delete 删除
func (s *sSysLog) Delete(ctx context.Context, in sysin.LogDeleteInp) error {
if _, err := dao.SysLog.Ctx(ctx).Where("id", in.Id).Delete(); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// List 列表
func (s *sSysLog) List(ctx context.Context, in sysin.LogListInp) (list []*sysin.LogListModel, totalCount int, err error) {
2022-11-24 23:37:34 +08:00
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 len(in.CreatedAt) == 2 {
mod = mod.WhereBetween("created_at", gtime.New(in.CreatedAt[0]), gtime.New(in.CreatedAt[1]))
}
// 状态码
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
}
if totalCount == 0 {
return list, totalCount, err
}
if err = mod.Page(in.Page, in.PerPage).Order("id desc").Scan(&list); err != nil {
2022-11-24 23:37:34 +08:00
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
isDemo := g.Cfg().MustGet(ctx, "hotgo.isDemo", false)
2022-11-24 23:37:34 +08:00
for i := 0; i < len(list); i++ {
// 管理员
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()
}
// 接口
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 = "游客"
}
//// 获取省市编码对应的地区名称
//region, err := dao.SysProvinces.GetRegion(ctx, list[i].ProvinceId, list[i].CityId)
//if err != nil {
// return list, totalCount, err
//}
//list[i].Region = region
// 截取请求url路径
if gstr.Contains(list[i].Url, "?") {
list[i].Url = gstr.StrTillEx(list[i].Url, "?")
}
if isDemo.Bool() {
// list[i].HeaderData = `{
// "none": [
// "` + consts.DemoTips + `"
// ]
//}`
2022-11-24 23:37:34 +08:00
}
}
return list, totalCount, err
}