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"
|
2023-01-18 16:23:39 +08:00
|
|
|
"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)
|
|
|
|
}
|
|
|
|
|
2023-01-18 16:23:39 +08:00
|
|
|
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
|
|
|
|
}
|
2023-01-18 16:23:39 +08:00
|
|
|
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) {
|
2023-01-18 16:23:39 +08:00
|
|
|
config, err := service.SysConfig().GetLoadLog(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2022-02-25 17:11:17 +08:00
|
|
|
}
|
|
|
|
|
2023-01-18 16:23:39 +08:00
|
|
|
if !config.Switch {
|
2022-02-25 17:11:17 +08:00
|
|
|
return nil
|
|
|
|
}
|
2023-01-18 16:23:39 +08:00
|
|
|
|
|
|
|
data := s.AnalysisLog(ctx)
|
|
|
|
if ok := validate.InSliceExistStr(config.Module, data.Module); !ok {
|
2022-02-25 17:11:17 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-01-18 16:23:39 +08:00
|
|
|
if ok := validate.InSliceExistStr(config.SkipCode, gconv.String(data.ErrorCode)); ok {
|
|
|
|
return nil
|
2022-02-25 17:11:17 +08:00
|
|
|
}
|
|
|
|
|
2023-01-18 16:23:39 +08:00
|
|
|
if config.Queue {
|
|
|
|
q, err := queue.InstanceProducer()
|
2022-02-25 17:11:17 +08:00
|
|
|
if err != nil {
|
2023-01-18 16:23:39 +08:00
|
|
|
queue.FatalLog(ctx, "queue.InstanceProducer err:%+v", err)
|
2022-02-25 17:11:17 +08:00
|
|
|
return err
|
|
|
|
}
|
2023-01-18 16:23:39 +08:00
|
|
|
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()
|
2023-01-18 16:23:39 +08:00
|
|
|
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 = ""
|
2023-01-18 16:23:39 +08:00
|
|
|
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 {
|
2023-01-18 16:23:39 +08:00
|
|
|
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 {
|
2023-01-18 16:23:39 +08:00
|
|
|
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) != "" {
|
2023-01-18 16:23:39 +08:00
|
|
|
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 {
|
2023-01-18 16:23:39 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-01-18 16:23:39 +08:00
|
|
|
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,
|
2023-01-18 16:23:39 +08:00
|
|
|
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
|
|
|
|
}
|
2023-01-18 16:23:39 +08:00
|
|
|
isDemo := g.Cfg().MustGet(ctx, "hotgo.isDemo", false)
|
2022-11-24 23:37:34 +08:00
|
|
|
if isDemo.Bool() {
|
2023-01-18 16:23:39 +08:00
|
|
|
// 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 列表
|
2023-01-18 16:23:39 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-01-18 16:23:39 +08:00
|
|
|
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
|
|
|
|
}
|
2023-01-18 16:23:39 +08:00
|
|
|
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() {
|
2023-01-18 16:23:39 +08:00
|
|
|
// list[i].HeaderData = `{
|
|
|
|
// "none": [
|
|
|
|
// "` + consts.DemoTips + `"
|
|
|
|
// ]
|
|
|
|
//}`
|
2022-11-24 23:37:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return list, totalCount, err
|
|
|
|
}
|