错误上报sdk

This commit is contained in:
xiangheng
2024-10-31 01:12:07 +08:00
parent ff9e39f964
commit daeea359bc
18 changed files with 786 additions and 247 deletions

View File

@@ -0,0 +1,62 @@
<script setup lang="ts">
import XLog from '../../../../x_error_sdk/x-log'
import x_log_browser from '../../../../x_error_sdk/x-log-browser'
const xlog = new XLog(
{
Dns: 'http://localhost:5174/api',
Pid: 'e19e3be20de94f49b68fafb4c30668bc',
Uid: '10'
},
x_log_browser
)
defineProps<{ msg: string }>()
function error() {
throw new Error('主动抛error')
}
function promiseError() {
Promise.reject('主动抛promise1')
Promise.reject(new Error('主动抛promiseError2'))
}
function yufaError() {
// try {
setTimeout(() => {
a = 1
// a = 2;
}, 100)
// } catch (error) {
// console.log(error);
// }
}
function loadError() {
const img = new Image()
console.log(img)
img.src = 'http://a.cn'
document.body.appendChild(img)
}
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button class="a b" type="button" aa="11" @click="error">主动抛error</button>
<button class="a b" type="button" aa="11" @click="yufaError">语法错误</button>
<button class="a b c" id="abv" type="button" @click="promiseError">promiseerror</button>
<button type="button" @click="loadError">资源加载错误</button>
<!-- <img src="http://a.cn/a/b" alt="" srcset="" />
<link rel="stylesheet" href="http://a.cn/c/c/c" /> -->
</div>
</template>
<style scoped>
button {
color: #fff;
background-color: rgb(150, 149, 149);
border: 0;
padding: 6px 10px;
margin: 6px;
font-size: 14px;
line-height: 18px;
}
</style>

View File

@@ -20,9 +20,9 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="客户端id" prop="ClientId" class="w-[280px]"> <!-- <el-form-item label="客户端id" prop="ClientId" class="w-[280px]">
<el-input v-model="queryParams.ClientId" /> <el-input v-model="queryParams.ClientId" />
</el-form-item> </el-form-item> -->
<el-form-item label="用户id" prop="UserId" class="w-[280px]"> <el-form-item label="用户id" prop="UserId" class="w-[280px]">
<el-input v-model="queryParams.UserId" /> <el-input v-model="queryParams.UserId" />
</el-form-item> </el-form-item>
@@ -47,10 +47,10 @@
<el-form-item label="ip" prop="Ip" class="w-[280px]"> <el-form-item label="ip" prop="Ip" class="w-[280px]">
<el-input v-model="queryParams.Ip" /> <el-input v-model="queryParams.Ip" />
</el-form-item> </el-form-item>
<el-form-item label="ua记录" prop="Ua" class="w-[280px]"> <!-- <el-form-item label="ua记录" prop="Ua" class="w-[280px]">
<el-input v-model="queryParams.Ua" /> <el-input v-model="queryParams.Ua" />
</el-form-item> </el-form-item> -->
<el-form-item label="创建时间" prop="CreateTime" class="w-[280px]"> <el-form-item label="创建时间" prop="CreateTime" class="w-[425px]">
<daterange-picker <daterange-picker
v-model:startTime="queryParams.CreateTimeStart" v-model:startTime="queryParams.CreateTimeStart"
v-model:endTime="queryParams.CreateTimeEnd" v-model:endTime="queryParams.CreateTimeEnd"
@@ -128,21 +128,56 @@
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="客户端id" prop="ClientId" min-width="130" /> <!-- <el-table-column label="客户端id" prop="ClientId" min-width="130" /> -->
<el-table-column label="用户id" prop="UserId" min-width="130" /> <el-table-column label="用户id" prop="UserId">
<el-table-column label="系统" prop="Os" min-width="130" /> <template #default="{ row }">
<el-table-column label="浏览器" prop="Browser" min-width="130" /> <el-popover
<el-table-column label="国家" prop="Country" min-width="130" /> placement="top-start"
<el-table-column label="省份" prop="Province" min-width="130" /> :width="500"
<el-table-column label="城市" prop="City" min-width="130" /> trigger="hover"
<el-table-column label="电信运营商" prop="Operator" min-width="130" /> :content="row.ClientId"
<el-table-column label="ip" prop="Ip" min-width="130" /> >
<el-table-column label="屏幕" prop="Width" min-width="130"> <template #reference>
<el-link type="primary">{{ row.UserId }}</el-link>
</template>
<div> ID {{ row.UserId }}</div>
<div>客户端ID{{ row.ClientId }}</div>
</el-popover>
</template>
</el-table-column>
<el-table-column label="浏览器" prop="Browser" min-width="150">
<template #default="{ row }">
<el-popover
placement="top-start"
title="浏览器ua"
:width="500"
trigger="hover"
:content="row.Ua"
>
<template #reference>
<el-link type="primary">{{ row.Os }} / {{ row.Browser }}</el-link>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column label="IP" prop="Ip" />
<el-table-column label="区域">
<template #default="{ row }">
{{ row.Country }}{{ row.Province }}{{ row.City }}
</template>
</el-table-column>
<!-- <el-table-column label="省份" prop="Province" />
<el-table-column label="城市" prop="City" /> -->
<el-table-column label="运营商" prop="Operator" />
<el-table-column label="屏幕" prop="Width">
<template #default="{ row }"> {{ row.Width }} * {{ row.Height }} </template> <template #default="{ row }"> {{ row.Width }} * {{ row.Height }} </template>
</el-table-column> </el-table-column>
<!-- <el-table-column label="屏幕高度" prop="Height" min-width="130" /> --> <!-- <el-table-column label="屏幕高度" prop="Height" min-width="130" /> -->
<el-table-column label="ua记录" prop="Ua" min-width="380" /> <!-- <el-table-column label="ua记录" prop="Ua" min-width="380" /> -->
<el-table-column label="创建时间" prop="CreateTime" min-width="130" /> <el-table-column label="创建时间" prop="CreateTime" min-width="140" />
<el-table-column label="操作" width="80" fixed="right"> <el-table-column label="操作" width="80" fixed="right">
<template #default="{ row }"> <template #default="{ row }">

View File

@@ -105,7 +105,7 @@
<el-table-column label="事件类型" prop="EventType" min-width="130" /> <el-table-column label="事件类型" prop="EventType" min-width="130" />
<el-table-column label="URL地址" prop="Path" min-width="130" /> <el-table-column label="URL地址" prop="Path" min-width="130" />
<el-table-column label="错误消息" prop="Message" min-width="130" /> <el-table-column label="错误消息" prop="Message" min-width="130" />
<el-table-column label="错误堆栈" prop="Stack" min-width="130" /> <!-- <el-table-column label="错误堆栈" prop="Stack" min-width="130" /> -->
<el-table-column label="md5" prop="Md5" min-width="130" /> <el-table-column label="md5" prop="Md5" min-width="130" />
<el-table-column label="创建时间" prop="CreateTime" min-width="130" /> <el-table-column label="创建时间" prop="CreateTime" min-width="130" />

View File

@@ -37,13 +37,13 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="创建时间" prop="CreateTime" class="w-[280px]"> <el-form-item label="创建时间" prop="CreateTime" class="w-[430px]">
<daterange-picker <daterange-picker
v-model:startTime="queryParams.CreateTimeStart" v-model:startTime="queryParams.CreateTimeStart"
v-model:endTime="queryParams.CreateTimeEnd" v-model:endTime="queryParams.CreateTimeEnd"
/> />
</el-form-item> </el-form-item>
<el-form-item label="更新时间" prop="UpdateTime" class="w-[280px]"> <el-form-item label="更新时间" prop="UpdateTime" class="w-[420px]">
<daterange-picker <daterange-picker
v-model:startTime="queryParams.UpdateTimeStart" v-model:startTime="queryParams.UpdateTimeStart"
v-model:endTime="queryParams.UpdateTimeEnd" v-model:endTime="queryParams.UpdateTimeEnd"

View File

@@ -1,7 +1,10 @@
package monitor_client package monitor_client
import ( import (
"encoding/json"
"fmt"
"net/http" "net/http"
"net/url"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -19,30 +22,30 @@ type MonitorClientHandler struct {
requestGroup singleflight.Group requestGroup singleflight.Group
} }
// @Summary 监控-客户端信息列表 // @Summary 监控-客户端信息列表
// @Tags monitor_client-监控-客户端信息 // @Tags monitor_client-监控-客户端信息
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param PageNo query int true "页码" // @Param PageNo query int true "页码"
// @Param PageSize query int true "每页数量" // @Param PageSize query int true "每页数量"
// @Param ProjectKey query string false "项目key" // @Param ProjectKey query string false "项目key"
// @Param ClientId query string false "sdk生成的客户端id" // @Param ClientId query string false "sdk生成的客户端id"
// @Param UserId query string false "用户id" // @Param UserId query string false "用户id"
// @Param Os query string false "系统" // @Param Os query string false "系统"
// @Param Browser query string false "浏览器" // @Param Browser query string false "浏览器"
// @Param Country query string false "国家" // @Param Country query string false "国家"
// @Param Province query string false "省份" // @Param Province query string false "省份"
// @Param City query string false "城市" // @Param City query string false "城市"
// @Param Operator query string false "电信运营商" // @Param Operator query string false "电信运营商"
// @Param Ip query string false "ip" // @Param Ip query string false "ip"
// @Param Width query number false "屏幕" // @Param Width query number false "屏幕"
// @Param Height query number false "屏幕高度" // @Param Height query number false "屏幕高度"
// @Param Ua query string false "ua记录" // @Param Ua query string false "ua记录"
// @Param CreateTimeStart query string false "创建时间" // @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间" // @Param CreateTimeEnd query string false "创建时间"
// //
// @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]MonitorClientResp}} "成功" // @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]MonitorClientResp}} "成功"
// @Router /api/admin/monitor_client/list [get] // @Router /api/admin/monitor_client/list [get]
func (hd *MonitorClientHandler) List(c *gin.Context) { func (hd *MonitorClientHandler) List(c *gin.Context) {
var page request.PageReq var page request.PageReq
var listReq MonitorClientListReq var listReq MonitorClientListReq
@@ -56,27 +59,27 @@ func (hd *MonitorClientHandler) List(c *gin.Context) {
response.CheckAndRespWithData(c, res, err) response.CheckAndRespWithData(c, res, err)
} }
// @Summary 监控-客户端信息列表-所有 // @Summary 监控-客户端信息列表-所有
// @Tags monitor_client-监控-客户端信息 // @Tags monitor_client-监控-客户端信息
// @Produce json // @Produce json
// @Param ProjectKey query string false "项目key" // @Param ProjectKey query string false "项目key"
// @Param ClientId query string false "sdk生成的客户端id" // @Param ClientId query string false "sdk生成的客户端id"
// @Param UserId query string false "用户id" // @Param UserId query string false "用户id"
// @Param Os query string false "系统" // @Param Os query string false "系统"
// @Param Browser query string false "浏览器" // @Param Browser query string false "浏览器"
// @Param Country query string false "国家" // @Param Country query string false "国家"
// @Param Province query string false "省份" // @Param Province query string false "省份"
// @Param City query string false "城市" // @Param City query string false "城市"
// @Param Operator query string false "电信运营商" // @Param Operator query string false "电信运营商"
// @Param Ip query string false "ip" // @Param Ip query string false "ip"
// @Param Width query number // @Param Width query number
// @Param Width query number false "屏幕" // @Param Width query number false "屏幕"
// @Param Height query number false "屏幕高度" // @Param Height query number false "屏幕高度"
// @Param Ua query string false "ua记录" // @Param Ua query string false "ua记录"
// @Param CreateTimeStart query string false "创建时间" // @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间" // @Param CreateTimeEnd query string false "创建时间"
// @Success 200 {object} response.Response{ data=[]MonitorClientResp} "成功" // @Success 200 {object} response.Response{ data=[]MonitorClientResp} "成功"
// @Router /api/admin/monitor_client/listAll [get] // @Router /api/admin/monitor_client/listAll [get]
func (hd *MonitorClientHandler) ListAll(c *gin.Context) { func (hd *MonitorClientHandler) ListAll(c *gin.Context) {
var listReq MonitorClientListReq var listReq MonitorClientListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) { if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
@@ -95,13 +98,13 @@ func (hd *MonitorClientHandler) ErrorUsers(c *gin.Context) {
response.CheckAndRespWithData(c, res, err) response.CheckAndRespWithData(c, res, err)
} }
// @Summary 监控-客户端信息详情 // @Summary 监控-客户端信息详情
// @Tags monitor_client-监控-客户端信息 // @Tags monitor_client-监控-客户端信息
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param Id query number false "uuid" // @Param Id query number false "uuid"
// @Success 200 {object} response.Response{ data=MonitorClientResp} "成功" // @Success 200 {object} response.Response{ data=MonitorClientResp} "成功"
// @Router /api/admin/monitor_client/detail [get] // @Router /api/admin/monitor_client/detail [get]
func (hd *MonitorClientHandler) Detail(c *gin.Context) { func (hd *MonitorClientHandler) Detail(c *gin.Context) {
var detailReq MonitorClientDetailReq var detailReq MonitorClientDetailReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) { if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) {
@@ -115,34 +118,57 @@ func (hd *MonitorClientHandler) Detail(c *gin.Context) {
response.CheckAndRespWithData(c, res, err) response.CheckAndRespWithData(c, res, err)
} }
// @Summary 监控-客户端信息新增 // @Summary 监控-客户端信息新增
// @Tags monitor_client-监控-客户端信息 // @Tags monitor_client-监控-客户端信息
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param ProjectKey body string false "项目key" // @Param ProjectKey body string false "项目key"
// @Param ClientId body string false "sdk生成的客户端id" // @Param ClientId body string false "sdk生成的客户端id"
// @Param UserId body string false "用户id" // @Param UserId body string false "用户id"
// @Param Os body string false "系统" // @Param Os body string false "系统"
// @Param Browser body string false "浏览器" // @Param Browser body string false "浏览器"
// @Param Country query string false "国家" // @Param Country query string false "国家"
// @Param Province query string false "省份" // @Param Province query string false "省份"
// @Param City query string false "城市" // @Param City query string false "城市"
// @Param Operator query string false "电信运营商" // @Param Operator query string false "电信运营商"
// @Param Ip query string false "ip" // @Param Ip query string false "ip"
// @Param Width body number false "屏幕" // @Param Width body number false "屏幕"
// @Param Height body number false "屏幕高度" // @Param Height body number false "屏幕高度"
// @Param Ua body string false "ua记录" // @Param Ua body string false "ua记录"
// @Success 200 {object} response.Response "成功" // @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_client/add [post] // @Router /api/admin/monitor_client/add [post]
func (hd *MonitorClientHandler) Add(c *gin.Context) { func (hd *MonitorClientHandler) Add(c *gin.Context) {
data, err := url.QueryUnescape(c.Query("data"))
var addReq MonitorClientAddReq if err != nil {
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) { response.CheckAndRespWithData(c, 0, err)
return return
} }
var addReq MonitorClientAddReq
json.Unmarshal([]byte(data), &addReq)
// if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
// return
// }
lastClient, err := MonitorClientService.DetailByClientId(*addReq.ClientId)
uaStr := c.GetHeader("user-agent") uaStr := c.GetHeader("user-agent")
ip := c.ClientIP() ip := c.ClientIP()
// createFlag := true
if err == nil {
last := lastClient.UserId + lastClient.Width.String() + lastClient.Height.String() + lastClient.Ip + lastClient.Ua
newStr := *addReq.UserId + addReq.Width.String() + addReq.Height.String() + ip + uaStr
if last == newStr {
// 前后数据一样,不用创建新的数据
fmt.Println("前后数据一样,不用创建新的数据")
response.CheckAndRespWithData(c, 0, nil)
return
} else {
// 新建的话需要清除lastClient对应的缓存
cacheUtil.RemoveCache("ClientId:" + lastClient.ClientId)
}
}
if uaStr != "" { if uaStr != "" {
ua := core.UAParser.Parse(uaStr) ua := core.UAParser.Parse(uaStr)
addReq.Ua = &uaStr addReq.Ua = &uaStr
@@ -164,13 +190,13 @@ func (hd *MonitorClientHandler) Add(c *gin.Context) {
response.CheckAndRespWithData(c, createId, e) response.CheckAndRespWithData(c, createId, e)
} }
// @Summary 监控-客户端信息删除 // @Summary 监控-客户端信息删除
// @Tags monitor_client-监控-客户端信息 // @Tags monitor_client-监控-客户端信息
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param Id body number false "uuid" // @Param Id body number false "uuid"
// @Success 200 {object} response.Response "成功" // @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_client/del [post] // @Router /api/admin/monitor_client/del [post]
func (hd *MonitorClientHandler) Del(c *gin.Context) { func (hd *MonitorClientHandler) Del(c *gin.Context) {
var delReq MonitorClientDelReq var delReq MonitorClientDelReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) { if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
@@ -179,14 +205,14 @@ func (hd *MonitorClientHandler) Del(c *gin.Context) {
response.CheckAndResp(c, MonitorClientService.Del(delReq.Id)) response.CheckAndResp(c, MonitorClientService.Del(delReq.Id))
} }
// @Summary 监控-客户端信息删除-批量 // @Summary 监控-客户端信息删除-批量
// @Tags monitor_client-监控-客户端信息 // @Tags monitor_client-监控-客户端信息
// //
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param Ids body string false "逗号分割的id" // @Param Ids body string false "逗号分割的id"
// @Success 200 {object} response.Response "成功" // @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_client/delBatch [post] // @Router /api/admin/monitor_client/delBatch [post]
func (hd *MonitorClientHandler) DelBatch(c *gin.Context) { func (hd *MonitorClientHandler) DelBatch(c *gin.Context) {
var delReq MonitorClientDelBatchReq var delReq MonitorClientDelBatchReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) { if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
@@ -201,26 +227,26 @@ func (hd *MonitorClientHandler) DelBatch(c *gin.Context) {
response.CheckAndResp(c, MonitorClientService.DelBatch(Ids)) response.CheckAndResp(c, MonitorClientService.DelBatch(Ids))
} }
// @Summary 监控-客户端信息导出 // @Summary 监控-客户端信息导出
// @Tags monitor_client-监控-客户端信息 // @Tags monitor_client-监控-客户端信息
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param ProjectKey query string false "项目key" // @Param ProjectKey query string false "项目key"
// @Param ClientId query string false "sdk生成的客户端id" // @Param ClientId query string false "sdk生成的客户端id"
// @Param UserId query string false "用户id" // @Param UserId query string false "用户id"
// @Param Os query string false "系统" // @Param Os query string false "系统"
// @Param Browser query string false "浏览器" // @Param Browser query string false "浏览器"
// @Param Country query string false "国家" // @Param Country query string false "国家"
// @Param Province query string false "省份" // @Param Province query string false "省份"
// @Param City query string false "城市" // @Param City query string false "城市"
// @Param Operator query string false "电信运营商" // @Param Operator query string false "电信运营商"
// @Param Ip query string false "ip" // @Param Ip query string false "ip"
// @Param Width query number false "屏幕" // @Param Width query number false "屏幕"
// @Param Height query number false "屏幕高度" // @Param Height query number false "屏幕高度"
// @Param Ua query string false "ua记录" // @Param Ua query string false "ua记录"
// @Param CreateTimeStart query string false "创建时间" // @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间" // @Param CreateTimeEnd query string false "创建时间"
// @Router /api/admin/monitor_client/ExportFile [get] // @Router /api/admin/monitor_client/ExportFile [get]
func (hd *MonitorClientHandler) ExportFile(c *gin.Context) { func (hd *MonitorClientHandler) ExportFile(c *gin.Context) {
var listReq MonitorClientListReq var listReq MonitorClientListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) { if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
@@ -239,10 +265,10 @@ func (hd *MonitorClientHandler) ExportFile(c *gin.Context) {
excel2.DownLoadExcel("监控-客户端信息"+time.Now().Format("20060102-150405"), c.Writer, f) excel2.DownLoadExcel("监控-客户端信息"+time.Now().Format("20060102-150405"), c.Writer, f)
} }
// @Summary 监控-客户端信息导入 // @Summary 监控-客户端信息导入
// @Tags monitor_client-监控-客户端信息 // @Tags monitor_client-监控-客户端信息
// @Produce json // @Produce json
// @Router /api/admin/monitor_client/ImportFile [post] // @Router /api/admin/monitor_client/ImportFile [post]
func (hd *MonitorClientHandler) ImportFile(c *gin.Context) { func (hd *MonitorClientHandler) ImportFile(c *gin.Context) {
file, _, err := c.Request.FormFile("file") file, _, err := c.Request.FormFile("file")
if err != nil { if err != nil {

View File

@@ -1,6 +1,7 @@
package monitor_client package monitor_client
import ( import (
"errors"
"x_admin/core" "x_admin/core"
"x_admin/core/request" "x_admin/core/request"
"x_admin/core/response" "x_admin/core/response"
@@ -111,34 +112,6 @@ func (service monitorClientService) List(page request.PageReq, listReq MonitorCl
}, nil }, nil
} }
// List 监控-客户端信息列表
// func (service monitorClientService) ListByErrorId(page request.PageReq, listReq MonitorClientListReq, errorId int) (res response.PageResp, e error) {
// // 分页信息
// limit := page.PageSize
// offset := page.PageSize * (page.PageNo - 1)
// dbModel := service.GetModel(listReq)
// // 总数
// var count int64
// err := dbModel.Count(&count).Error
// if e = response.CheckErr(err, "失败"); e != nil {
// return
// }
// // 数据
// var modelList []model.MonitorClient
// err = dbModel.Limit(limit).Offset(offset).Order("id desc").Find(&modelList).Error
// if e = response.CheckErr(err, "查询失败"); e != nil {
// return
// }
// result := []MonitorClientResp{}
// util.ConvertUtil.Copy(&result, modelList)
// return response.PageResp{
// PageNo: page.PageNo,
// PageSize: page.PageSize,
// Count: count,
// Lists: result,
// }, nil
// }
// ListAll 监控-客户端信息列表 // ListAll 监控-客户端信息列表
func (service monitorClientService) ListAll(listReq MonitorClientListReq) (res []MonitorClientResp, e error) { func (service monitorClientService) ListAll(listReq MonitorClientListReq) (res []MonitorClientResp, e error) {
dbModel := service.GetModel(listReq) dbModel := service.GetModel(listReq)
@@ -154,6 +127,9 @@ func (service monitorClientService) ListAll(listReq MonitorClientListReq) (res [
} }
func (service monitorClientService) DetailByClientId(ClientId string) (res MonitorClientResp, e error) { func (service monitorClientService) DetailByClientId(ClientId string) (res MonitorClientResp, e error) {
if ClientId == "" {
return res, errors.New("ClientId不能为空")
}
var obj = model.MonitorClient{} var obj = model.MonitorClient{}
err := cacheUtil.GetCache("ClientId:"+ClientId, &obj) err := cacheUtil.GetCache("ClientId:"+ClientId, &obj)
if err != nil { if err != nil {
@@ -164,6 +140,7 @@ func (service monitorClientService) DetailByClientId(ClientId string) (res Monit
if e = response.CheckErr(err, "获取详情失败"); e != nil { if e = response.CheckErr(err, "获取详情失败"); e != nil {
return return
} }
cacheUtil.SetCache(obj.Id, obj)
cacheUtil.SetCache("ClientId:"+obj.ClientId, obj) cacheUtil.SetCache("ClientId:"+obj.ClientId, obj)
} }
@@ -184,6 +161,7 @@ func (service monitorClientService) Detail(Id int) (res MonitorClientResp, e err
return return
} }
cacheUtil.SetCache(obj.Id, obj) cacheUtil.SetCache(obj.Id, obj)
cacheUtil.SetCache("ClientId:"+obj.ClientId, obj)
} }
util.ConvertUtil.Copy(&res, obj) util.ConvertUtil.Copy(&res, obj)
@@ -193,7 +171,7 @@ func (service monitorClientService) Detail(Id int) (res MonitorClientResp, e err
// ErrorUser 监控-客户端信息详情 // ErrorUser 监控-客户端信息详情
func (service monitorClientService) ErrorUsers(error_id int) (res []MonitorClientResp, e error) { func (service monitorClientService) ErrorUsers(error_id int) (res []MonitorClientResp, e error) {
var obj = []model.MonitorClient{} var obj = []model.MonitorClient{}
service.db.Raw("SELECT client.* from x_monitor_error_list as list right join x_monitor_client as client on client.id = list.client_id where list.error_id = ? Order by list.id DESC", error_id).Scan(&obj) service.db.Raw("SELECT client.*,list.create_time AS create_time from x_monitor_error_list as list right join x_monitor_client as client on client.id = list.client_id where list.error_id = ? Order by list.id DESC LIMIT 0,20", error_id).Scan(&obj)
util.ConvertUtil.Copy(&res, obj) util.ConvertUtil.Copy(&res, obj)
return return
@@ -209,6 +187,7 @@ func (service monitorClientService) Add(addReq MonitorClientAddReq) (createId in
return 0, e return 0, e
} }
cacheUtil.SetCache(obj.Id, obj) cacheUtil.SetCache(obj.Id, obj)
cacheUtil.SetCache("ClientId:"+obj.ClientId, obj)
createId = obj.Id createId = obj.Id
return return
} }

View File

@@ -1,7 +1,9 @@
package monitor_error package monitor_error
import ( import (
"encoding/json"
"net/http" "net/http"
"net/url"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -18,23 +20,23 @@ type MonitorErrorHandler struct {
requestGroup singleflight.Group requestGroup singleflight.Group
} }
// @Summary 监控-错误列列表 // @Summary 监控-错误列列表
// @Tags monitor_error-监控-错误列 // @Tags monitor_error-监控-错误列
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param PageNo query int true "页码" // @Param PageNo query int true "页码"
// @Param PageSize query int true "每页数量" // @Param PageSize query int true "每页数量"
// @Param ProjectKey query string false "项目key" // @Param ProjectKey query string false "项目key"
// @Param EventType query string false "事件类型" // @Param EventType query string false "事件类型"
// @Param Path query string false "URL地址" // @Param Path query string false "URL地址"
// @Param Message query string false "错误消息" // @Param Message query string false "错误消息"
// @Param Stack query string false "错误堆栈" // @Param Stack query string false "错误堆栈"
// @Param Md5 query string false "md5" // @Param Md5 query string false "md5"
// @Param CreateTimeStart query string false "创建时间" // @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间" // @Param CreateTimeEnd query string false "创建时间"
// //
// @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]MonitorErrorResp}} "成功" // @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]MonitorErrorResp}} "成功"
// @Router /api/admin/monitor_error/list [get] // @Router /api/admin/monitor_error/list [get]
func (hd *MonitorErrorHandler) List(c *gin.Context) { func (hd *MonitorErrorHandler) List(c *gin.Context) {
var page request.PageReq var page request.PageReq
var listReq MonitorErrorListReq var listReq MonitorErrorListReq
@@ -48,19 +50,19 @@ func (hd *MonitorErrorHandler) List(c *gin.Context) {
response.CheckAndRespWithData(c, res, err) response.CheckAndRespWithData(c, res, err)
} }
// @Summary 监控-错误列列表-所有 // @Summary 监控-错误列列表-所有
// @Tags monitor_error-监控-错误列 // @Tags monitor_error-监控-错误列
// @Produce json // @Produce json
// @Param ProjectKey query string false "项目key" // @Param ProjectKey query string false "项目key"
// @Param EventType query string false "事件类型" // @Param EventType query string false "事件类型"
// @Param Path query string false "URL地址" // @Param Path query string false "URL地址"
// @Param Message query string false "错误消息" // @Param Message query string false "错误消息"
// @Param Stack query string false "错误堆栈" // @Param Stack query string false "错误堆栈"
// @Param Md5 query string false "md5" // @Param Md5 query string false "md5"
// @Param CreateTimeStart query string false "创建时间" // @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间" // @Param CreateTimeEnd query string false "创建时间"
// @Success 200 {object} response.Response{ data=[]MonitorErrorResp} "成功" // @Success 200 {object} response.Response{ data=[]MonitorErrorResp} "成功"
// @Router /api/admin/monitor_error/listAll [get] // @Router /api/admin/monitor_error/listAll [get]
func (hd *MonitorErrorHandler) ListAll(c *gin.Context) { func (hd *MonitorErrorHandler) ListAll(c *gin.Context) {
var listReq MonitorErrorListReq var listReq MonitorErrorListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) { if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
@@ -70,13 +72,13 @@ func (hd *MonitorErrorHandler) ListAll(c *gin.Context) {
response.CheckAndRespWithData(c, res, err) response.CheckAndRespWithData(c, res, err)
} }
// @Summary 监控-错误列详情 // @Summary 监控-错误列详情
// @Tags monitor_error-监控-错误列 // @Tags monitor_error-监控-错误列
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param Id query number false "错误id" // @Param Id query number false "错误id"
// @Success 200 {object} response.Response{ data=MonitorErrorResp} "成功" // @Success 200 {object} response.Response{ data=MonitorErrorResp} "成功"
// @Router /api/admin/monitor_error/detail [get] // @Router /api/admin/monitor_error/detail [get]
func (hd *MonitorErrorHandler) Detail(c *gin.Context) { func (hd *MonitorErrorHandler) Detail(c *gin.Context) {
var detailReq MonitorErrorDetailReq var detailReq MonitorErrorDetailReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) { if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &detailReq)) {
@@ -90,34 +92,45 @@ func (hd *MonitorErrorHandler) Detail(c *gin.Context) {
response.CheckAndRespWithData(c, res, err) response.CheckAndRespWithData(c, res, err)
} }
// @Summary 监控-错误列新增 // @Summary 监控-错误列新增
// @Tags monitor_error-监控-错误列 // @Tags monitor_error-监控-错误列
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param ProjectKey body string false "项目key" // @Param ProjectKey body string false "项目key"
// @Param EventType body string false "事件类型" // @Param EventType body string false "事件类型"
// @Param Path body string false "URL地址" // @Param Path body string false "URL地址"
// @Param Message body string false "错误消息" // @Param Message body string false "错误消息"
// @Param Stack body string false "错误堆栈" // @Param Stack body string false "错误堆栈"
// @Param Md5 body string false "md5" // @Param Md5 body string false "md5"
// @Success 200 {object} response.Response "成功" // @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_error/add [post] // @Router /api/admin/monitor_error/add [post]
func (hd *MonitorErrorHandler) Add(c *gin.Context) { func (hd *MonitorErrorHandler) Add(c *gin.Context) {
var addReq MonitorErrorAddReq data, err := url.QueryUnescape(c.Query("data"))
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) { if err != nil {
response.CheckAndRespWithData(c, 0, err)
return return
} }
createId, e := MonitorErrorService.Add(addReq)
response.CheckAndRespWithData(c, createId, e) var addReq []MonitorErrorAddReq
json.Unmarshal([]byte(data), &addReq)
// if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
// return
// }
for i := 0; i < len(addReq); i++ {
MonitorErrorService.Add(addReq[i])
}
// createId, e := MonitorErrorService.Add(addReq)
response.CheckAndRespWithData(c, nil, nil)
} }
// @Summary 监控-错误列删除 // @Summary 监控-错误列删除
// @Tags monitor_error-监控-错误列 // @Tags monitor_error-监控-错误列
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param Id body number false "错误id" // @Param Id body number false "错误id"
// @Success 200 {object} response.Response "成功" // @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_error/del [post] // @Router /api/admin/monitor_error/del [post]
func (hd *MonitorErrorHandler) Del(c *gin.Context) { func (hd *MonitorErrorHandler) Del(c *gin.Context) {
var delReq MonitorErrorDelReq var delReq MonitorErrorDelReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) { if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
@@ -126,14 +139,14 @@ func (hd *MonitorErrorHandler) Del(c *gin.Context) {
response.CheckAndResp(c, MonitorErrorService.Del(delReq.Id)) response.CheckAndResp(c, MonitorErrorService.Del(delReq.Id))
} }
// @Summary 监控-错误列删除-批量 // @Summary 监控-错误列删除-批量
// @Tags monitor_error-监控-错误列 // @Tags monitor_error-监控-错误列
// //
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param Ids body string false "逗号分割的id" // @Param Ids body string false "逗号分割的id"
// @Success 200 {object} response.Response "成功" // @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_error/delBatch [post] // @Router /api/admin/monitor_error/delBatch [post]
func (hd *MonitorErrorHandler) DelBatch(c *gin.Context) { func (hd *MonitorErrorHandler) DelBatch(c *gin.Context) {
var delReq MonitorErrorDelBatchReq var delReq MonitorErrorDelBatchReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) { if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &delReq)) {
@@ -148,19 +161,19 @@ func (hd *MonitorErrorHandler) DelBatch(c *gin.Context) {
response.CheckAndResp(c, MonitorErrorService.DelBatch(Ids)) response.CheckAndResp(c, MonitorErrorService.DelBatch(Ids))
} }
// @Summary 监控-错误列导出 // @Summary 监控-错误列导出
// @Tags monitor_error-监控-错误列 // @Tags monitor_error-监控-错误列
// @Produce json // @Produce json
// @Param Token header string true "token" // @Param Token header string true "token"
// @Param ProjectKey query string false "项目key" // @Param ProjectKey query string false "项目key"
// @Param EventType query string false "事件类型" // @Param EventType query string false "事件类型"
// @Param Path query string false "URL地址" // @Param Path query string false "URL地址"
// @Param Message query string false "错误消息" // @Param Message query string false "错误消息"
// @Param Stack query string false "错误堆栈" // @Param Stack query string false "错误堆栈"
// @Param Md5 query string false "md5" // @Param Md5 query string false "md5"
// @Param CreateTimeStart query string false "创建时间" // @Param CreateTimeStart query string false "创建时间"
// @Param CreateTimeEnd query string false "创建时间" // @Param CreateTimeEnd query string false "创建时间"
// @Router /api/admin/monitor_error/ExportFile [get] // @Router /api/admin/monitor_error/ExportFile [get]
func (hd *MonitorErrorHandler) ExportFile(c *gin.Context) { func (hd *MonitorErrorHandler) ExportFile(c *gin.Context) {
var listReq MonitorErrorListReq var listReq MonitorErrorListReq
if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) { if response.IsFailWithResp(c, util.VerifyUtil.VerifyQuery(c, &listReq)) {
@@ -179,10 +192,10 @@ func (hd *MonitorErrorHandler) ExportFile(c *gin.Context) {
excel2.DownLoadExcel("监控-错误列"+time.Now().Format("20060102-150405"), c.Writer, f) excel2.DownLoadExcel("监控-错误列"+time.Now().Format("20060102-150405"), c.Writer, f)
} }
// @Summary 监控-错误列导入 // @Summary 监控-错误列导入
// @Tags monitor_error-监控-错误列 // @Tags monitor_error-监控-错误列
// @Produce json // @Produce json
// @Router /api/admin/monitor_error/ImportFile [post] // @Router /api/admin/monitor_error/ImportFile [post]
func (hd *MonitorErrorHandler) ImportFile(c *gin.Context) { func (hd *MonitorErrorHandler) ImportFile(c *gin.Context) {
file, _, err := c.Request.FormFile("file") file, _, err := c.Request.FormFile("file")
if err != nil { if err != nil {

View File

@@ -151,7 +151,7 @@ func (service monitorErrorService) Add(addReq MonitorErrorAddReq) (createId int,
var obj model.MonitorError var obj model.MonitorError
util.ConvertUtil.StructToStruct(addReq, &obj) util.ConvertUtil.StructToStruct(addReq, &obj)
Md5 := util.ToolsUtil.MakeMd5(obj.ProjectKey + obj.Path + obj.Stack) Md5 := util.ToolsUtil.MakeMd5(obj.ProjectKey + obj.EventType + obj.Message + obj.Path + obj.Stack)
errorDetails, e := service.DetailByMD5(Md5) errorDetails, e := service.DetailByMD5(Md5)
if e != nil { if e != nil {

View File

@@ -45,6 +45,7 @@ INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_sh
// MonitorClientRoute(rg) // MonitorClientRoute(rg)
func MonitorClientRoute(rg *gin.RouterGroup) { func MonitorClientRoute(rg *gin.RouterGroup) {
handle := monitor_client.MonitorClientHandler{} handle := monitor_client.MonitorClientHandler{}
rg.GET("/monitor_client/add", middleware.RecordLog("监控-客户端信息新增"), handle.Add)
r := rg.Group("/", middleware.TokenAuth()) r := rg.Group("/", middleware.TokenAuth())
r.GET("/monitor_client/list", handle.List) r.GET("/monitor_client/list", handle.List)
@@ -52,7 +53,6 @@ func MonitorClientRoute(rg *gin.RouterGroup) {
r.GET("/monitor_client/detail", handle.Detail) r.GET("/monitor_client/detail", handle.Detail)
r.GET("/monitor_client/errorUsers", handle.ErrorUsers) r.GET("/monitor_client/errorUsers", handle.ErrorUsers)
r.POST("/monitor_client/add", middleware.RecordLog("监控-客户端信息新增"), handle.Add)
// r.POST("/monitor_client/edit",middleware.RecordLog("监控-客户端信息编辑"), handle.Edit) // r.POST("/monitor_client/edit",middleware.RecordLog("监控-客户端信息编辑"), handle.Edit)
r.POST("/monitor_client/del", middleware.RecordLog("监控-客户端信息删除"), handle.Del) r.POST("/monitor_client/del", middleware.RecordLog("监控-客户端信息删除"), handle.Del)

View File

@@ -45,14 +45,13 @@ INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_sh
// MonitorErrorRoute(rg) // MonitorErrorRoute(rg)
func MonitorErrorRoute(rg *gin.RouterGroup) { func MonitorErrorRoute(rg *gin.RouterGroup) {
handle := monitor_error.MonitorErrorHandler{} handle := monitor_error.MonitorErrorHandler{}
rg.GET("/monitor_error/add", middleware.RecordLog("监控-错误列新增"), handle.Add)
r := rg.Group("/", middleware.TokenAuth()) r := rg.Group("/", middleware.TokenAuth())
r.GET("/monitor_error/list", handle.List) r.GET("/monitor_error/list", handle.List)
r.GET("/monitor_error/listAll", handle.ListAll) r.GET("/monitor_error/listAll", handle.ListAll)
r.GET("/monitor_error/detail", handle.Detail) r.GET("/monitor_error/detail", handle.Detail)
r.POST("/monitor_error/add", middleware.RecordLog("监控-错误列新增"), handle.Add)
r.POST("/monitor_error/del", middleware.RecordLog("监控-错误列删除"), handle.Del) r.POST("/monitor_error/del", middleware.RecordLog("监控-错误列删除"), handle.Del)
r.POST("/monitor_error/delBatch", middleware.RecordLog("监控-错误列删除-批量"), handle.DelBatch) r.POST("/monitor_error/delBatch", middleware.RecordLog("监控-错误列删除-批量"), handle.DelBatch)

16
x_error_sdk/.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
pnpm-lock.yaml
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local

25
x_error_sdk/package.json Normal file
View File

@@ -0,0 +1,25 @@
{
"name": "@adtkcn/x-log",
"version": "1.0.0",
"description": "",
"module": "./index.ts",
"main": "./index.ts",
"scripts": {
"build": "npm run build:index&&npm run build:browser&&npm run build:ts",
"build:index": "esbuild x-log.ts --bundle --sourcemap --outfile=dist/x-log.js --format=esm --target=es2015",
"build:browser": "esbuild x-log-browser.ts --bundle --sourcemap --outfile=dist/x-log-browser.js --format=esm --target=es2015",
"build:ts": "tsc --emitDeclarationOnly"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"typescript": "^5.6.3",
"uuid": "^9.0.0"
},
"devDependencies": {
"@dcloudio/types": "^3.0.19",
"@types/uuid": "^8.3.4",
"esbuild": "^0.15.14"
}
}

18
x_error_sdk/tsconfig.json Normal file
View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"declaration": true, // 生成声明文件,开启后会自动生成声明文件
"target": "esnext", // 最新的ES标准
"lib": [
"esnext",
"dom"
], // TS需要引用的库即声明文件es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性通常都需要配置如es8的数组新特性需要引入"ES2019.Array"
"strict": true, // 开启所有严格的类型检查
"noImplicitAny": false, // 不允许隐式的any类型
"esModuleInterop": true, // 允许export=导出由import from 导入
"moduleResolution": "node", // 模块解析策略ts默认用node的解析策略即相对的方式导入
"outDir": "dist", // 指定输出目录
"types": [
"@dcloudio/types"
]
}
}

25
x_error_sdk/types.ts Normal file
View File

@@ -0,0 +1,25 @@
export type LogWithEnv = {
Type: "env";
ScreenHeight?: number;
ScreenWidth?: number;
};
export type LogWithError = {
Type: "error"|"event"|"resources";
EventType: string;
Path:string;
Message: string;
Stack: string;
};
export interface Platform {
upload(url: string, data: Object);
getEnvInfo(): LogWithEnv;
listen(callback: ListenCallbackFn): void;
getCache(key: string): any;
setCache(key: string, info: any): void;
delCache(key: string): void;
}
export type ListenCallbackFn = (params: LogWithError) => void;

View File

@@ -0,0 +1,160 @@
import type { LogWithError, LogWithEnv, ListenCallbackFn } from "./types";
export function upload(url: string, data: object[]) {
return new Promise(() => {
try {
let h = new Image();
h.onerror = function (event) {
var e = event as Event;
e.preventDefault();
};
h.onload = function () {};
h.src = url + "?data=" + encodeURIComponent(JSON.stringify(data));
} catch (error) {}
});
}
export function setCache(key: string, info: any) {
localStorage.setItem(key, JSON.stringify(info));
}
export function getCache(key: string): any {
try {
let list = localStorage.getItem(key);
if (list) {
return JSON.parse(list);
} else {
return null;
}
} catch (error) {
return null;
}
}
export function delCache(key: string) {
localStorage.removeItem(key);
}
// 获取环境信息
export function getEnvInfo(): LogWithEnv {
const env: LogWithEnv = {
Type: "env",
ScreenHeight: 0,
ScreenWidth: 0,
};
// navigator对象数据
if (window ) {
env.ScreenHeight = window.innerHeight || 0; // 获取显示屏信息
env.ScreenWidth = window.innerWidth || 0;
}
return env;
}
export function listenError(callback: ListenCallbackFn) {
window.addEventListener(
"error",
(err: any) => {
console.error(err);
let target = err.target;
if (target?.localName) {
if (target?.localName == "img" || target?.localName == "script") {
// errorResources(target?.localName, target.src);
callback({
Type: "resources",
EventType: target?.localName,
Path: target.src,
Message:'',
Stack: "",
});
} else if (target?.localName == "link") {
// errorResources(target?.localName, target.href);
callback({
Type: "resources",
EventType: target?.localName,
Path: target.href,
Message:'',
Stack: "",
});
}
} else {
// errorLog(err.type, err.message, err.error?.stack || "");
callback({
Type: "error",
EventType: err.type,
Path:window.location.href,
Message: err.message,
Stack: err.error?.stack || "",
});
}
},
true
);
window.addEventListener("unhandledrejection", (err) => {
if (typeof err.reason == "string") {
// errorLog(err.type, err.reason, "");
callback({
Type: "error",
EventType: err.type,
Path:window.location.href,
Message: err.reason,
Stack: "",
});
} else if (typeof err.reason == "object") {
// errorLog(err.type, err.reason?.message || "", err.reason?.stack || "");
callback({
Type: "error",
EventType: err.type,
Path:window.location.href,
Message: err.reason?.message || "",
Stack: err.reason?.stack || "",
});
}
});
}
// export function listenBehavior(eventLog: EventLog) {
// window.addEventListener("click", (e) => {
// let target = e.target as HTMLElement;
// let tagName = target?.localName;
// let name = [tagName];
// if (target.id) {
// name.push("#" + target.id);
// }
// target.classList.forEach((item) => {
// name.push("." + item);
// });
// if (target.innerText) {
// name.push(":" + target.innerText);
// }
// eventLog("click", name.join(""));
// });
// window.addEventListener("hashchange", (e) => {
// eventLog("pageChange", e.newURL);
// });
// eventLog("pageChange", window.location.href);
// }
export function listen(callback: ListenCallbackFn) {
listenError((params: LogWithError) => {
if (params.Stack) {
let newStack: string[] = [];
params.Stack.split("\n").map((item, index) => {
if (index < 4) {
newStack.push(item);
}
});
params.Stack = newStack.join("\n");
}
callback(params);
});
}
export default {
getEnvInfo,
listenError,
upload,
getCache,
setCache,
delCache,
listen,
};

18
x_error_sdk/x-log-node.ts Normal file
View File

@@ -0,0 +1,18 @@
// import http from "http";
// export function upload(url: string, data: Object) {
// let h = new Image();
// h.onerror = function () {};
// h.src = url + "?log=" + encodeURIComponent(data.toString());
// const req = http.request(url, { method: "POST" }, (res: any) => {
// res.setEncoding("utf8");
// res.on("data", (chunk) => {});
// // 监听接口请求完成, 除非error最终都会执行end;
// res.on("end", () => {});
// });
// req.on("error", (e) => {});
// // 写入请求的数据
// data && req.write(data);
// req.end();
// }

View File

@@ -0,0 +1,20 @@
export function upload(url: string, data: Object) {
if (uni) {
uni.request({
url: url, //仅为示例,并非真实接口地址。
data: {
log: encodeURIComponent(JSON.stringify(data)),
},
method: "POST",
header: {
// xlog: "version", //自定义请求头信息
},
success: (res: any) => {
console.log(res.data);
},
fail: (err: any) => {
console.log(err);
},
});
}
}

143
x_error_sdk/x-log.ts Normal file
View File

@@ -0,0 +1,143 @@
import { v1 as uuid_v1 } from "uuid";
import type { LogWithError, Platform,LogWithEnv } from "./types";
type Uid = string | number;
type Props = {
Dns: string; // 域名
Pid: string; // 项目标识
Uid?: Uid; //用户标识
};
class XLog {
private Dns: string = "";
private client_id: string = "";
private Pid: string = "";
private Uid: Uid = "";
private platform: Platform;
MessageList: any[] = [];
constructor(props: Props, platform: Platform) {
this.platform = platform;
if (props) {
props.Dns && (this.Dns = props.Dns);
props.Pid && (this.Pid = props.Pid);
props.Uid && (this.Uid = props.Uid);
}
this.SetClientID();
this.getLocalMessage();
this.initEnv();
// 监听错误
platform.listen((params: LogWithError) => {
console.log('listen',params);
this.Push(params);
});
setInterval(() => {
this.upload();
}, 1000 * 10);
}
private initEnv() {
let envInfo:LogWithEnv = this.platform.getEnvInfo();
if (envInfo) {
this.uploadInfo(envInfo);
}
}
// 关联用户id
public SetUid(uid: Uid) {
this.Uid = uid;
this.initEnv();
}
// 设置错误ID
private SetClientID() {
const client_id = this.platform.getCache("x_log_client_id");
if (client_id) {
this.client_id = client_id;
} else {
this.client_id = uuid_v1();
this.platform.setCache("x_log_client_id", this.client_id);
}
}
// 获取本地缓存消息
private getLocalMessage() {
let x_message_list = this.platform.getCache("x_message_list");
if (x_message_list) {
this.MessageList = x_message_list;
} else {
this.MessageList = [];
}
}
// 记录错误超出5条时立即上报否则缓存到本地(等待定时器上报)
public Push(data: LogWithError) {
console.log(this);
this.MessageList.push({
...data,
ProjectKey:this.Pid,
ClientId:this.client_id
});
if (this.MessageList.length > 5) {
this.upload(); //上传
} else {
this.platform.setCache(
"x_message_list",
this.MessageList
);
}
}
public uploadInfo(envInfo:LogWithEnv ) {
if (!this.Dns) return; //未设置Dns服务器不上传
try {
this.platform
.upload(
this.Dns +
`/admin/monitor_client/add`,
{
ProjectKey:this.Pid,
ClientId:this.client_id,
UserId:this.Uid,
Width: envInfo.ScreenWidth,
Height:envInfo.ScreenHeight
}
)
.catch((err: any) => {
// 上传失败
});
} catch (error) {}
}
// 上传文件
public upload() {
if (!this.Dns) return; //未设置Dns服务器不上传
if (!this.MessageList.length) {
return;
}
try {
this.platform
.upload(
this.Dns +
`/admin/monitor_error/add`,
this.MessageList
)
.catch((err: any) => {
// 上传失败
});
this.MessageList = [];
this.platform.delCache("x_message_list");
} catch (error) {}
}
// public Vue2 = (app: any) => {
// app.prototype.$xLog = this;
// };
// public Vue3 = (app: any) => {
// app.config.globalProperties.$xLog = this;
// };
}
export default XLog;