完善slow

This commit is contained in:
xiangheng
2024-11-07 19:03:35 +08:00
parent 784d9bdd4a
commit aeabacc6a5
18 changed files with 350 additions and 303 deletions

View File

@@ -13,6 +13,21 @@
padding: 0; padding: 0;
} }
</style> </style>
<script src="/XErr.umd.js"></script>
<script>
const xErr = new XErr.XErr(
{
Dns: `${location.origin}/api`,
Pid: 'e19e3be20de94f49b68fafb4c30668bc',
Uid: ''
},
new XErr.XErrWeb({
onloadTimeOut: 300
})
)
xErr.SetUid(2) //设置用户ID
</script>
<link rel="stylesheet" href="/src/styles/loading.css" /> <link rel="stylesheet" href="/src/styles/loading.css" />
</head> </head>
<body> <body>

3
admin/public/XErr.umd.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -11,19 +11,18 @@ import ElementPlus from 'element-plus'
import VForm3 from 'vform3-builds' //引入VForm3库 import VForm3 from 'vform3-builds' //引入VForm3库
import { XErr, XErrWeb } from '../../x_err_sdk/web/index' // import { Base, Web } from '../../x_err_sdk/web/index'
// { XErr, XErrWeb } // const xErr = new Base(
const xErr = new XErr( // {
{ // Dns: `${location.origin}/api`,
Dns: `${location.origin}/api`, // Pid: 'e19e3be20de94f49b68fafb4c30668bc',
Pid: 'e19e3be20de94f49b68fafb4c30668bc', // Uid: ''
Uid: '' // },
}, // new Web({
new XErrWeb({ // onloadTimeOut: 300
onloadTimeOut: 3000 // })
}) // )
) // xErr.SetUid(1) //设置用户ID
xErr.SetUid(1) //设置用户ID
const app = createApp(App) const app = createApp(App)
app.use(install) app.use(install)

View File

@@ -97,10 +97,12 @@ const code = computed(() => {
new XErr( new XErr(
{ {
Dns: '${location.origin}/api', Dns: '${location.origin}/api',
Pid: ${formData.ProjectKey}, Pid: '${formData.ProjectKey}',
Uid: '' Uid: ''
}, },
new XErrWeb() new XErrWeb({
onloadTimeOut: 3000
})
)` )`
}) })
const formRules = { const formRules = {

View File

@@ -9,16 +9,22 @@
label-width="70px" label-width="70px"
label-position="left" label-position="left"
> >
<el-form-item label="项目key" prop="ProjectKey" class="w-[280px]"> <el-form-item label="项目" prop="ProjectKey" class="w-[280px]">
<el-input v-model="queryParams.ProjectKey" /> <el-select v-model="queryParams.ProjectKey" clearable>
</el-form-item> <el-option label="全部" value="" />
<el-form-item label="sdk生成的客户端id" prop="ClientId" class="w-[280px]"> <el-option
<el-input v-model="queryParams.ClientId" /> v-for="(item, index) in listAllData.monitor_project_listAll"
:key="index"
:label="item.ProjectName"
:value="item.ProjectKey"
/>
</el-select>
</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>
<el-form-item label="创建时间" prop="CreateTime" class="w-[280px]"> <el-form-item label="创建时间" prop="CreateTime" class="w-[420px]">
<daterange-picker <daterange-picker
v-model:startTime="queryParams.CreateTimeStart" v-model:startTime="queryParams.CreateTimeStart"
v-model:endTime="queryParams.CreateTimeEnd" v-model:endTime="queryParams.CreateTimeEnd"
@@ -32,13 +38,13 @@
</el-card> </el-card>
<el-card class="!border-none mt-4" shadow="never"> <el-card class="!border-none mt-4" shadow="never">
<div class="text-right"> <div class="text-right">
<el-button v-perms="['admin:monitor_slow:add']" type="primary" @click="handleAdd()"> <!-- <el-button v-perms="['admin:monitor_slow:add']" type="primary" @click="handleAdd()">
<template #icon> <template #icon>
<icon name="el-icon-Plus" /> <icon name="el-icon-Plus" />
</template> </template>
新增 新增
</el-button> </el-button> -->
<upload <!-- <upload
v-perms="['admin:monitor_slow:ImportFile']" v-perms="['admin:monitor_slow:ImportFile']"
class="ml-3 mr-3" class="ml-3 mr-3"
:url="monitor_slow_import_file" :url="monitor_slow_import_file"
@@ -53,8 +59,8 @@
</template> </template>
导入 导入
</el-button> </el-button>
</upload> </upload> -->
<el-button <!-- <el-button
v-perms="['admin:monitor_slow:ExportFile']" v-perms="['admin:monitor_slow:ExportFile']"
type="primary" type="primary"
@click="exportFile" @click="exportFile"
@@ -63,7 +69,7 @@
<icon name="el-icon-Download" /> <icon name="el-icon-Download" />
</template> </template>
导出 导出
</el-button> </el-button> -->
<el-button <el-button
v-perms="['admin:monitor_slow:delBatch']" v-perms="['admin:monitor_slow:delBatch']"
type="danger" type="danger"
@@ -81,22 +87,31 @@
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column label="项目key" prop="ProjectKey" min-width="130" /> <el-table-column label="项目" prop="ProjectKey" width="150">
<el-table-column label="sdk生成的客户端id" prop="ClientId" min-width="130" />
<el-table-column label="用户id" prop="UserId" min-width="130" />
<el-table-column label="URL地址" prop="Path" min-width="130" />
<el-table-column label="时间" prop="Time" min-width="130" />
<el-table-column label="创建时间" prop="CreateTime" min-width="130" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<el-button <dict-value
:options="listAllData.monitor_project_listAll"
:value="row.ProjectKey"
labelKey="ProjectName"
valueKey="ProjectKey"
/>
</template>
</el-table-column>
<el-table-column label="用户id" prop="UserId" width="150" />
<el-table-column label="URL地址" prop="Path" />
<el-table-column label="时间(毫秒)" prop="Time" width="130" />
<el-table-column label="创建时间" prop="CreateTime" width="180" />
<el-table-column label="操作" width="80" fixed="right">
<template #default="{ row }">
<!-- <el-button
v-perms="['admin:monitor_slow:edit']" v-perms="['admin:monitor_slow:edit']"
type="primary" type="primary"
link link
@click="handleEdit(row)" @click="handleEdit(row)"
> >
编辑 编辑
</el-button> </el-button> -->
<el-button <el-button
v-perms="['admin:monitor_slow:del']" v-perms="['admin:monitor_slow:del']"
type="danger" type="danger"
@@ -116,16 +131,15 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, shallowRef, nextTick } from 'vue' import { ref, reactive, shallowRef } from 'vue'
import { import {
monitor_slow_delete, monitor_slow_delete,
monitor_slow_delete_batch, monitor_slow_delete_batch,
monitor_slow_list, monitor_slow_list
monitor_slow_import_file,
monitor_slow_export_file
} from '@/api/monitor/slow' } from '@/api/monitor/slow'
import type { type_monitor_slow, type_monitor_slow_query } from '@/api/monitor/slow' import type { type_monitor_slow, type_monitor_slow_query } from '@/api/monitor/slow'
import { useListAllData } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging' import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback' import feedback from '@/utils/feedback'
import EditPopup from './edit.vue' import EditPopup from './edit.vue'
@@ -148,19 +162,12 @@ const { pager, getLists, resetPage, resetParams } = usePaging<type_monitor_slow>
fetchFun: monitor_slow_list, fetchFun: monitor_slow_list,
params: queryParams params: queryParams
}) })
const { listAllData } = useListAllData<{
monitor_project_listAll: any[]
}>({
monitor_project_listAll: '/monitor_project/listAll'
})
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add')
}
const handleEdit = async (data: any) => {
showEdit.value = true
await nextTick()
editRef.value?.open('edit')
editRef.value?.getDetail(data)
}
const multipleSelection = ref<type_monitor_slow[]>([]) const multipleSelection = ref<type_monitor_slow[]>([])
const handleSelectionChange = (val: type_monitor_slow[]) => { const handleSelectionChange = (val: type_monitor_slow[]) => {
console.log(val) console.log(val)
@@ -191,11 +198,5 @@ const deleteBatch = async () => {
} catch (error) {} } catch (error) {}
} }
const exportFile = async () => {
try {
await feedback.confirm('确定要导出?')
await monitor_slow_export_file(queryParams)
} catch (error) {}
}
getLists() getLists()
</script> </script>

View File

@@ -23,10 +23,12 @@ export default ({ mode }) => {
// 依赖预构建,避免开发刷新 // 依赖预构建,避免开发刷新
include: ['@wangeditor/editor-for-vue', 'vuedraggable', 'vue-echarts', 'crypto-js'] include: ['@wangeditor/editor-for-vue', 'vuedraggable', 'vue-echarts', 'crypto-js']
}, },
base: '/', base: '/',
build: { build: {
sourcemap: true, sourcemap: true,
rollupOptions: { rollupOptions: {
external: ['XErr'],
output: { output: {
manualChunks: { manualChunks: {
vue: ['vue'], vue: ['vue'],

View File

@@ -13,6 +13,7 @@ import (
"x_admin/core/response" "x_admin/core/response"
"x_admin/util" "x_admin/util"
"x_admin/util/excel2" "x_admin/util/excel2"
"x_admin/util/img_util"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
@@ -141,28 +142,24 @@ func (hd *MonitorClientHandler) Add(c *gin.Context) {
data, err := url.QueryUnescape(c.Query("data")) data, err := url.QueryUnescape(c.Query("data"))
if err != nil { if err != nil {
// response.CheckAndRespWithData(c, 0, err) // response.CheckAndRespWithData(c, 0, err)
c.Writer.WriteString("0") c.Data(200, "image/gif", img_util.EmptyGif())
return return
} }
var addReq MonitorClientAddReq var addReq MonitorClientAddReq
json.Unmarshal([]byte(data), &addReq) json.Unmarshal([]byte(data), &addReq)
// if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) {
// return
// }
lastClient, err := MonitorClientService.DetailByClientId(*addReq.ClientId) 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 { if err == nil {
last := lastClient.UserId + lastClient.Width.String() + lastClient.Height.String() + lastClient.Ip + lastClient.Ua last := lastClient.UserId + lastClient.Width.String() + lastClient.Height.String() + lastClient.Ip + lastClient.Ua
newStr := *addReq.UserId + addReq.Width.String() + addReq.Height.String() + ip + uaStr newStr := *addReq.UserId + addReq.Width.String() + addReq.Height.String() + ip + uaStr
if last == newStr { if last == newStr {
// 前后数据一样,不用创建新的数据 // 前后数据一样,不用创建新的数据
fmt.Println("前后数据一样,不用创建新的数据") fmt.Println("前后数据一样,不用创建新的数据")
c.Writer.WriteString("0") c.Data(200, "image/gif", img_util.EmptyGif())
// response.CheckAndRespWithData(c, 0, nil) // response.CheckAndRespWithData(c, 0, nil)
return return
} else { } else {
@@ -188,10 +185,9 @@ func (hd *MonitorClientHandler) Add(c *gin.Context) {
addReq.Province = &regionInfo.Province addReq.Province = &regionInfo.Province
} }
createId, _ := MonitorClientService.Add(addReq) MonitorClientService.Add(addReq)
// response.CheckAndRespWithData(c, createId, e)
// c.Value(createId) c.Data(200, "image/gif", img_util.EmptyGif())
c.Writer.WriteString(strconv.Itoa(createId))
} }
// @Summary 监控-客户端信息删除 // @Summary 监控-客户端信息删除

View File

@@ -1,11 +1,7 @@
package monitor_error package monitor_error
import ( import (
"bytes"
"encoding/json" "encoding/json"
"image"
"image/color"
"image/gif"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@@ -15,6 +11,7 @@ import (
"x_admin/core/response" "x_admin/core/response"
"x_admin/util" "x_admin/util"
"x_admin/util/excel2" "x_admin/util/excel2"
"x_admin/util/img_util"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
@@ -111,7 +108,8 @@ func (hd *MonitorErrorHandler) Detail(c *gin.Context) {
func (hd *MonitorErrorHandler) Add(c *gin.Context) { func (hd *MonitorErrorHandler) Add(c *gin.Context) {
data, err := url.QueryUnescape(c.Query("data")) data, err := url.QueryUnescape(c.Query("data"))
if err != nil { if err != nil {
response.CheckAndRespWithData(c, 0, err) // response.CheckAndRespWithData(c, 0, err)
c.Data(200, "image/gif", img_util.EmptyGif())
return return
} }
@@ -124,35 +122,8 @@ func (hd *MonitorErrorHandler) Add(c *gin.Context) {
for i := 0; i < len(addReq); i++ { for i := 0; i < len(addReq); i++ {
MonitorErrorService.Add(addReq[i]) MonitorErrorService.Add(addReq[i])
} }
img := image.NewRGBA(image.Rect(0, 0, 1, 1))
// 设置像素颜色为黑色
img.Set(0, 0, color.Black)
// 创建GIF动画
g := &gif.GIF{
Image: []*image.Paletted{imageToPaletted(img)},
Delay: []int{0}, // 延迟时间单位是10毫秒
}
var buffer bytes.Buffer
// 编码GIF到缓冲区
err = gif.EncodeAll(&buffer, g)
// response.CheckAndRespWithData(c, g, nil) // response.CheckAndRespWithData(c, g, nil)
c.Data(200, "image/gif", buffer.Bytes()) c.Data(200, "image/gif", img_util.EmptyGif())
}
// 将image.Image转换为*image.Paletted
func imageToPaletted(img image.Image) *image.Paletted {
b := img.Bounds()
pm := image.NewPaletted(b, color.Palette{color.Black})
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
pm.Set(x, y, img.At(x, y))
}
}
return pm
} }
// @Summary 监控-错误列删除 // @Summary 监控-错误列删除

View File

@@ -1,19 +1,22 @@
package monitor_slow package monitor_slow
import ( import (
"encoding/json"
"net/http" "net/http"
"net/url"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/gin-gonic/gin"
"x_admin/core/request" "x_admin/core/request"
"x_admin/core/response" "x_admin/core/response"
"x_admin/util" "x_admin/util"
"x_admin/util/excel2" "x_admin/util/excel2"
"x_admin/util/img_util"
"github.com/gin-gonic/gin"
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
) )
type MonitorSlowHandler struct { type MonitorSlowHandler struct {
requestGroup singleflight.Group requestGroup singleflight.Group
} }
@@ -31,6 +34,7 @@ type MonitorSlowHandler struct {
// @Param Time query number false "时间" // @Param Time query number false "时间"
// @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=[]MonitorSlowResp}} "成功" // @Success 200 {object} response.Response{ data=response.PageResp{ lists=[]MonitorSlowResp}} "成功"
// @Router /api/admin/monitor_slow/list [get] // @Router /api/admin/monitor_slow/list [get]
func (hd *MonitorSlowHandler) List(c *gin.Context) { func (hd *MonitorSlowHandler) List(c *gin.Context) {
@@ -87,7 +91,6 @@ func (hd *MonitorSlowHandler) Detail(c *gin.Context) {
response.CheckAndRespWithData(c, res, err) response.CheckAndRespWithData(c, res, err)
} }
// @Summary 监控-错误列新增 // @Summary 监控-错误列新增
// @Tags monitor_slow-监控-错误列 // @Tags monitor_slow-监控-错误列
// @Produce json // @Produce json
@@ -100,13 +103,19 @@ func (hd *MonitorSlowHandler) Detail(c *gin.Context) {
// @Success 200 {object} response.Response "成功" // @Success 200 {object} response.Response "成功"
// @Router /api/admin/monitor_slow/add [post] // @Router /api/admin/monitor_slow/add [post]
func (hd *MonitorSlowHandler) Add(c *gin.Context) { func (hd *MonitorSlowHandler) Add(c *gin.Context) {
var addReq MonitorSlowAddReq data, err := url.QueryUnescape(c.Query("data"))
if response.IsFailWithResp(c, util.VerifyUtil.VerifyJSON(c, &addReq)) { if err != nil {
c.Data(200, "image/gif", img_util.EmptyGif())
return return
} }
createId, e := MonitorSlowService.Add(addReq)
response.CheckAndRespWithData(c,createId, e) var addReq MonitorSlowAddReq
json.Unmarshal([]byte(data), &addReq)
MonitorSlowService.Add(addReq)
c.Data(200, "image/gif", img_util.EmptyGif())
} }
// @Summary 监控-错误列编辑 // @Summary 监控-错误列编辑
// @Tags monitor_slow-监控-错误列 // @Tags monitor_slow-监控-错误列
// @Produce json // @Produce json
@@ -126,6 +135,7 @@ func (hd *MonitorSlowHandler) Edit(c *gin.Context) {
} }
response.CheckAndRespWithData(c, editReq.Id, MonitorSlowService.Edit(editReq)) response.CheckAndRespWithData(c, editReq.Id, MonitorSlowService.Edit(editReq))
} }
// @Summary 监控-错误列删除 // @Summary 监控-错误列删除
// @Tags monitor_slow-监控-错误列 // @Tags monitor_slow-监控-错误列
// @Produce json // @Produce json
@@ -143,6 +153,7 @@ func (hd *MonitorSlowHandler) Del(c *gin.Context) {
// @Summary 监控-错误列删除-批量 // @Summary 监控-错误列删除-批量
// @Tags monitor_slow-监控-错误列 // @Tags monitor_slow-监控-错误列
//
// @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"
@@ -162,8 +173,6 @@ func (hd *MonitorSlowHandler) DelBatch(c *gin.Context) {
response.CheckAndResp(c, MonitorSlowService.DelBatch(Ids)) response.CheckAndResp(c, MonitorSlowService.DelBatch(Ids))
} }
// @Summary 监控-错误列导出 // @Summary 监控-错误列导出
// @Tags monitor_slow-监控-错误列 // @Tags monitor_slow-监控-错误列
// @Produce json // @Produce json

View File

@@ -1,7 +1,7 @@
package monitor_slow package monitor_slow
import ( import (
"x_admin/core" "x_admin/core"
) )
// MonitorSlowListReq 监控-错误列列表参数 // MonitorSlowListReq 监控-错误列列表参数
@@ -15,8 +15,6 @@ type MonitorSlowListReq struct {
CreateTimeEnd *string // 结束创建时间 CreateTimeEnd *string // 结束创建时间
} }
// MonitorSlowAddReq 监控-错误列新增参数 // MonitorSlowAddReq 监控-错误列新增参数
type MonitorSlowAddReq struct { type MonitorSlowAddReq struct {
ProjectKey *string // 项目key ProjectKey *string // 项目key

View File

@@ -45,7 +45,7 @@ INSERT INTO x_system_auth_menu (pid, menu_type, menu_name, perms,is_cache, is_sh
// MonitorSlowRoute(rg) // MonitorSlowRoute(rg)
func MonitorSlowRoute(rg *gin.RouterGroup) { func MonitorSlowRoute(rg *gin.RouterGroup) {
handle := monitor_slow.MonitorSlowHandler{} handle := monitor_slow.MonitorSlowHandler{}
rg.POST("/monitor_slow/add", middleware.RecordLog("慢接口新增"), handle.Add) rg.GET("/monitor_slow/add", middleware.RecordLog("慢接口新增"), handle.Add)
r := rg.Group("/", middleware.TokenAuth()) r := rg.Group("/", middleware.TokenAuth())
r.GET("/monitor_slow/list", handle.List) r.GET("/monitor_slow/list", handle.List)
r.GET("/monitor_slow/listAll", handle.ListAll) r.GET("/monitor_slow/listAll", handle.ListAll)

View File

@@ -0,0 +1,38 @@
package img_util
import (
"bytes"
"image"
"image/color"
"image/gif"
)
func EmptyGif() []byte {
img := image.NewRGBA(image.Rect(0, 0, 1, 1))
// 设置像素颜色为黑色
img.Set(0, 0, color.Black)
// 创建GIF动画
g := &gif.GIF{
Image: []*image.Paletted{imageToPaletted(img)},
Delay: []int{0}, // 延迟时间单位是10毫秒
}
var buffer bytes.Buffer
// 编码GIF到缓冲区
gif.EncodeAll(&buffer, g)
return buffer.Bytes()
}
// 将image.Image转换为*image.Paletted
func imageToPaletted(img image.Image) *image.Paletted {
b := img.Bounds()
pm := image.NewPaletted(b, color.Palette{color.Black})
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
pm.Set(x, y, img.At(x, y))
}
}
return pm
}

View File

@@ -2,21 +2,25 @@
"name": "@adtkcn/x_err_sdk", "name": "@adtkcn/x_err_sdk",
"version": "1.0.0", "version": "1.0.0",
"description": "错误监控sdk", "description": "错误监控sdk",
"main": "dist/web/index.js", "main": "dist/web/XErr.umd.js",
"private": false, "private": false,
"file": [
"dist"
],
"scripts": { "scripts": {
"build": "npm run build:web&&npm run build:ts", "build": "vite build&&npm run build:ts",
"build:web": "esbuild web/index.ts --bundle --sourcemap --minify --outfile=dist/web/index.js --format=esm --target=es2015",
"build:ts": "tsc --emitDeclarationOnly", "build:ts": "tsc --emitDeclarationOnly",
"outdated": "pnpm outdated" "outdated": "pnpm outdated"
}, },
"keywords": ["x_err_sdk","X_admin"], "keywords": [
"x_err_sdk",
"X_admin"
],
"author": "adtkcn", "author": "adtkcn",
"license": "ISC", "license": "ISC",
"dependencies": {},
"devDependencies": { "devDependencies": {
"typescript": "^5.6.3", "typescript": "^5.6.3",
"uuid": "^11.0.2", "uuid": "^11.0.2",
"esbuild": "^0.24.0" "vite": "^5.4.10"
} }
} }

View File

@@ -5,13 +5,20 @@ export type LogWithEnv = {
ScreenWidth?: number; ScreenWidth?: number;
}; };
export type LogWithError = { export type LogWithError = {
Type: "error"|"event"|"resources"|'click'|'historyChange'|'hashChange'|'onloadTime'; Type: "error"|"event"|"resources"|'click';
EventType: string; EventType: string;
Path:string; Path:string;
Message?: string; Message?: string;
Stack?: string; Stack?: string;
}; };
export type ISlow = {
Type: "onloadTime"
Path:string;
Time: number;
};
// 扩展必须实现的接口 // 扩展必须实现的接口
export interface IErrorEvent { export interface IErrorEvent {
@@ -23,4 +30,4 @@ export interface IErrorEvent {
listen(callback: ListenCallbackFn): void; listen(callback: ListenCallbackFn): void;
unListen(): void; unListen(): void;
} }
export type ListenCallbackFn = (params: LogWithError) => void; export type ListenCallbackFn = (params: LogWithError|ISlow) => void;

21
x_err_sdk/vite.config.js Normal file
View File

@@ -0,0 +1,21 @@
import { defineConfig, loadEnv } from 'vite'
export default defineConfig({
build: {
lib: {
entry: 'web/index.ts', // 库的入口文件
name: 'XErr', // 库的名称
fileName: (format) => `web/XErr.${format}.js`, // 输出文件名
},
rollupOptions: {
// 外部化处理不想打包进库的依赖
// external: ['vue'],
output: {
globals: {
// vue: 'Vue'
}
}
}
}
})

View File

@@ -1,5 +1,5 @@
import { v1 as uuid_v1 } from "uuid"; import { v1 as uuid_v1 } from "uuid";
import type { LogWithError, IErrorEvent, LogWithEnv } from "../types"; import type { LogWithError, IErrorEvent,ISlow, LogWithEnv } from "../types";
type Uid = string | number; type Uid = string | number;
@@ -9,7 +9,7 @@ type Props = {
Uid?: Uid; //用户标识 Uid?: Uid; //用户标识
}; };
class XLog { class Base {
private Dns: string = ""; private Dns: string = "";
private client_id: string = ""; private client_id: string = "";
private Pid: string = ""; private Pid: string = "";
@@ -38,17 +38,23 @@ class XLog {
return; return;
} }
if (props.Uid) { if (props.Uid) {
this.Uid = props.Uid; this.Uid = String(props.Uid);
} }
this.setClientID(); this.setClientID();
this.SetUid(); this.SetUid();
this.getLocalMessage(); this.getLocalMessage();
// 监听错误
platform.listen((params: LogWithError) => {
console.log("listenCallback", params);
// 监听错误
platform.listen((params: LogWithError|ISlow) => {
console.log("listenCallback", params);
if(params.Type=='onloadTime'){
let slow=params as ISlow;
this.uploadSlow(slow);
}else{
this.Push(params); this.Push(params);
}
}); });
this.timer = setInterval(() => { this.timer = setInterval(() => {
@@ -59,8 +65,8 @@ class XLog {
// 设置用户id // 设置用户id
public SetUid(uid?: Uid) { public SetUid(uid?: Uid) {
if (uid) { if (uid) {
this.Uid = uid; this.Uid =String(uid) ;
this.platform?.setCache("x_err_uid", uid); this.platform?.setCache("x_err_uid", this.Uid);
} else { } else {
const u_id = this.platform?.getCache("x_err_uid"); const u_id = this.platform?.getCache("x_err_uid");
@@ -127,6 +133,23 @@ class XLog {
}); });
} catch (error) {} } catch (error) {}
} }
public uploadSlow=(envInfo: ISlow) =>{
if (!this.Dns) return; //未设置Dns服务器不上传
try {
this.platform
?.upload(this.Dns + `/admin/monitor_slow/add`, {
ProjectKey: this.Pid,
ClientId: this.client_id,
UserId: this.Uid,
Path: envInfo.Path,
Time: envInfo.Time,
})
.catch((err: any) => {
// 上传失败
});
} catch (error) {}
}
// 上传文件 // 上传文件
public upload() { public upload() {
@@ -149,4 +172,4 @@ class XLog {
this.platform?.unListen(); this.platform?.unListen();
} }
} }
export default XLog; export default Base;

View File

@@ -1,6 +1,4 @@
import XErr from "./err-entry" import Base from "./base";
import XErrWeb from "./err-implement" import Web from "./web";
export {XErr,XErrWeb}
export { Base, Web };

View File

@@ -2,18 +2,18 @@ import type {
LogWithError, LogWithError,
LogWithEnv, LogWithEnv,
ListenCallbackFn, ListenCallbackFn,
IErrorEvent, IErrorEvent,ISlow
} from "../types"; } from "../types";
interface LoggerProps { interface LoggerProps {
// timeout:number // timeout:number
onloadTimeOut?: number; onloadTimeOut?: number;
} }
class Logger implements IErrorEvent { class Web implements IErrorEvent {
props: LoggerProps; props: LoggerProps;
constructor(props?: LoggerProps) { constructor(props?: LoggerProps) {
this.props = { this.props = {
onloadTimeOut: 3000, onloadTimeOut: 5000,
...props, ...props,
}; };
} }
@@ -67,7 +67,7 @@ class Logger implements IErrorEvent {
} }
return env; return env;
} }
private callback(err: LogWithError): void {} private callback(err: LogWithError|ISlow): void {}
private listenError = (err: any) => { private listenError = (err: any) => {
console.error([err]); console.error([err]);
let target = err.target; let target = err.target;
@@ -117,46 +117,8 @@ class Logger implements IErrorEvent {
}); });
} }
}; };
// private listenClick = (e: Event) => {
// 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.slice(0, 20));
// }
// this.callback({
// Type: "click",
// EventType: "click",
// Path: window.location.href,
// Message: name.join(""),
// Stack: "",
// });
// };
// private listenHistoryRouterChange = () => {
// this.callback({
// Type: "historyChange",
// EventType: "popstate",
// Path: window.location.href,
// Message: "",
// Stack: "",
// });
// };
// // 监听hash
// private listenHashRouterChange = () => {
// this.callback({
// Type: "hashChange",
// EventType: "hashChange",
// Path: window.location.href,
// Message: "",
// Stack: "",
// });
// };
private handleStack(stack: string): string { private handleStack(stack: string): string {
let newStack: string[] = []; let newStack: string[] = [];
if (stack) { if (stack) {
@@ -186,10 +148,8 @@ class Logger implements IErrorEvent {
// 页面加载时间5s以上 // 页面加载时间5s以上
this.callback({ this.callback({
Type: "onloadTime", Type: "onloadTime",
EventType: "onloadTime",
Path: window.location.href, Path: window.location.href,
Message: "时间:" + parseFloat(onloadTime.toFixed(2)) + "ms", Time:onloadTime
Stack: "",
}); });
} }
} }
@@ -216,4 +176,4 @@ class Logger implements IErrorEvent {
} }
} }
export default Logger; export default Web;