web-tracing-core 2.1.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/{dist/README.md → README.md} +8 -0
  2. package/{dist/index.cjs → index.cjs} +24 -5
  3. package/{dist/index.iife.js → index.iife.js} +24 -5
  4. package/{dist/index.iife.min.js → index.iife.min.js} +9 -9
  5. package/{dist/index.mjs → index.mjs} +24 -5
  6. package/package.json +9 -9
  7. package/__test__/css/performance.css +0 -3
  8. package/__test__/err-batch.spec.ts +0 -47
  9. package/__test__/err.spec.ts +0 -82
  10. package/__test__/event.spec.ts +0 -62
  11. package/__test__/html/performance.html +0 -57
  12. package/__test__/html/recordscreen.html +0 -39
  13. package/__test__/http.spec.ts +0 -143
  14. package/__test__/img/performance.png +0 -0
  15. package/__test__/js/performance.js +0 -3
  16. package/__test__/performance.spec.ts +0 -112
  17. package/__test__/recordscreen.spec.ts +0 -50
  18. package/__test__/utils/index.ts +0 -99
  19. package/__test__/utils/pollify.ts +0 -14
  20. package/__test__/utils.spec.ts +0 -18
  21. package/dist/package.json +0 -49
  22. package/index.ts +0 -75
  23. package/src/common/config.ts +0 -13
  24. package/src/common/constant.ts +0 -57
  25. package/src/common/index.ts +0 -2
  26. package/src/lib/base.ts +0 -129
  27. package/src/lib/err-batch.ts +0 -134
  28. package/src/lib/err.ts +0 -323
  29. package/src/lib/event-dwell.ts +0 -63
  30. package/src/lib/event.ts +0 -252
  31. package/src/lib/eventBus.ts +0 -97
  32. package/src/lib/exportMethods.ts +0 -208
  33. package/src/lib/http.ts +0 -197
  34. package/src/lib/intersectionObserver.ts +0 -164
  35. package/src/lib/line-status.ts +0 -45
  36. package/src/lib/options.ts +0 -325
  37. package/src/lib/performance.ts +0 -302
  38. package/src/lib/pv.ts +0 -199
  39. package/src/lib/recordscreen.ts +0 -169
  40. package/src/lib/replace.ts +0 -371
  41. package/src/lib/sendData.ts +0 -264
  42. package/src/observer/computed.ts +0 -52
  43. package/src/observer/config.ts +0 -1
  44. package/src/observer/dep.ts +0 -21
  45. package/src/observer/index.ts +0 -91
  46. package/src/observer/ref.ts +0 -80
  47. package/src/observer/types.ts +0 -22
  48. package/src/observer/watch.ts +0 -19
  49. package/src/observer/watcher.ts +0 -88
  50. package/src/types/index.ts +0 -126
  51. package/src/utils/debug.ts +0 -17
  52. package/src/utils/element.ts +0 -47
  53. package/src/utils/fingerprintjs.ts +0 -2132
  54. package/src/utils/getIps.ts +0 -127
  55. package/src/utils/global.ts +0 -49
  56. package/src/utils/index.ts +0 -551
  57. package/src/utils/is.ts +0 -78
  58. package/src/utils/localStorage.ts +0 -70
  59. package/src/utils/session.ts +0 -27
  60. /package/{dist/LICENSE → LICENSE} +0 -0
  61. /package/{dist/index.d.ts → index.d.ts} +0 -0
@@ -1,50 +0,0 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
- import http from 'http'
4
-
5
- import { getServerURL, startServer, launchPuppeteer, getHtml } from './utils'
6
- import { Browser, Page } from 'puppeteer'
7
-
8
- describe('err', () => {
9
- vi.setConfig({ testTimeout: 30_000, hookTimeout: 30_000 })
10
-
11
- let code: string
12
- let serverURL: string
13
- let server: http.Server
14
- let browser: Browser
15
-
16
- beforeAll(async () => {
17
- server = await startServer(3031)
18
- serverURL = getServerURL(server)
19
- browser = await launchPuppeteer()
20
-
21
- const bundlePath = path.resolve(__dirname, '../dist/index.iife.js')
22
- code = fs.readFileSync(bundlePath, 'utf8')
23
- })
24
-
25
- afterAll(async () => {
26
- browser && (await browser.close())
27
- server && server.close()
28
- })
29
-
30
- async function loadTestPage() {
31
- const page: Page = await browser.newPage()
32
- const htmlName = 'recordscreen.html'
33
- await page.goto(`${serverURL}/${htmlName}`)
34
- const html = getHtml(`${htmlName}`, code)
35
- await page.setContent(html)
36
- await page.waitForFunction(() => {
37
- return document.readyState === 'complete'
38
- })
39
- return page
40
- }
41
-
42
- it('error recordscreen should be captured correctly', async () => {
43
- const page = await loadTestPage()
44
- await page.click('.code-error-button')
45
- const webTracingData = await page.evaluate(`window.__WebTracingData__`)
46
- expect(
47
- (webTracingData as any).eventInfo[0].recordscreen
48
- ).not.toBeUndefined()
49
- })
50
- })
@@ -1,99 +0,0 @@
1
- import path from 'path'
2
- import http from 'http'
3
- import url from 'url'
4
- import fs from 'fs'
5
- import puppeteer from 'puppeteer'
6
-
7
- interface IMimeType {
8
- [key: string]: string
9
- }
10
-
11
- export function startServer(defaultPort = 3030) {
12
- return new Promise<http.Server>((resolve, reject) => {
13
- const mimeType: IMimeType = {
14
- '.html': 'text/html',
15
- '.js': 'text/javascript',
16
- '.css': 'text/css',
17
- '.png': 'image/png'
18
- }
19
-
20
- const s = http.createServer((req, res) => {
21
- const parsedUrl = url.parse(req.url!)
22
- const sanitizePath = path
23
- .normalize(parsedUrl.pathname!)
24
- .replace(/^(\.\.[/\\])+/, '')
25
- const pathname = path.join(__dirname, '../', sanitizePath)
26
-
27
- try {
28
- const data = fs.readFileSync(pathname)
29
- const ext = path.parse(pathname).ext
30
- res.setHeader('Content-type', mimeType[ext] || 'text/plain')
31
- res.setHeader('Access-Control-Allow-Origin', '*')
32
- res.setHeader('Access-Control-Allow-Methods', 'GET')
33
- res.setHeader('Access-Control-Allow-Headers', 'Content-type')
34
- setTimeout(() => {
35
- res.end(data)
36
- }, 100)
37
- } catch (error) {
38
- res.end()
39
- }
40
- })
41
- s.listen(defaultPort)
42
- .on('listening', () => {
43
- resolve(s)
44
- })
45
- .on('error', e => {
46
- reject(e)
47
- })
48
- })
49
- }
50
-
51
- export function getServerURL(server: http.Server): string {
52
- const address = server.address()
53
- if (address && typeof address !== 'string') {
54
- return `http://localhost:${address.port}`
55
- } else {
56
- return `${address}`
57
- }
58
- }
59
-
60
- export function replaceLast(str: string, find: string, replace: string) {
61
- const index = str.lastIndexOf(find)
62
- if (index === -1) {
63
- return str
64
- }
65
- return str.substring(0, index) + replace + str.substring(index + find.length)
66
- }
67
-
68
- export async function launchPuppeteer(
69
- options?: Parameters<(typeof puppeteer)['launch']>[0]
70
- ) {
71
- return await puppeteer.launch({
72
- headless: true,
73
- defaultViewport: {
74
- width: 1920,
75
- height: 1080
76
- },
77
- args: ['--no-sandbox'],
78
- ...options
79
- })
80
- }
81
-
82
- export function getHtml(fileName: string, code: string) {
83
- const filePath = path.resolve(__dirname, `../html/${fileName}`)
84
- const html = fs.readFileSync(filePath, 'utf8')
85
- return replaceLast(
86
- html,
87
- '</body>',
88
- `
89
- <script>
90
- ${code}
91
- </script>
92
- </body>
93
- `
94
- )
95
- }
96
-
97
- export function delay(timeout: number) {
98
- return new Promise(resolve => setTimeout(resolve, timeout))
99
- }
@@ -1,14 +0,0 @@
1
- export type PromiseRejectionEventInit = {
2
- promise: Promise<any>
3
- reason: any
4
- }
5
-
6
- export class PromiseRejectionEvent extends Event {
7
- public readonly reason: any
8
- public readonly promise: Promise<any>
9
- constructor(type: string, eventInitDict: PromiseRejectionEventInit) {
10
- super(type)
11
- this.promise = eventInitDict.promise
12
- this.reason = eventInitDict.reason
13
- }
14
- }
@@ -1,18 +0,0 @@
1
- import { getNodeXPath } from '../src/utils/element'
2
-
3
- describe('utils', () => {
4
- it('getNodeXPath should work', () => {
5
- const element = document.createElement('div')
6
- element.innerHTML = `
7
- <div id="wrapper">
8
- <div></div>
9
- <div></div>
10
- <div>
11
- <div class="target"></div>
12
- </div>
13
- </div>
14
- `
15
- const target = element.querySelector('.target')!
16
- expect(getNodeXPath(target)).toBe('#wrapper>div>div')
17
- })
18
- })
package/dist/package.json DELETED
@@ -1,49 +0,0 @@
1
- {
2
- "name": "web-tracing-core",
3
- "version": "2.1.0",
4
- "description": "基于 JS 跨平台插件,为前端项目提供【 埋点、行为、性能、异常、请求、资源、路由、曝光、录屏 】监控手段",
5
- "main": "./index.cjs",
6
- "module": "./index.mjs",
7
- "jsdelivr": "./index.iife.min.js",
8
- "types": "./index.d.ts",
9
- "sideEffects": false,
10
- "exports": {
11
- ".": {
12
- "import": "./index.mjs",
13
- "require": "./index.cjs",
14
- "types": "./index.d.ts"
15
- },
16
- "./*": "./*"
17
- },
18
- "license": "MIT",
19
- "repository": {
20
- "type": "git",
21
- "url": "git+https://github.com/M-cheng-web/web-tracing.git",
22
- "directory": "packages/core"
23
- },
24
- "author": "M-cheng-web <https://github.com/M-cheng-web>",
25
- "keywords": [
26
- "埋点",
27
- "性能",
28
- "异常",
29
- "性能采集",
30
- "异常采集",
31
- "前端埋点",
32
- "前端性能采集"
33
- ],
34
- "dependencies": {
35
- "ua-parser-js": "2.0.0-alpha.1",
36
- "@types/pako": "^2.0.0",
37
- "pako": "^2.1.0",
38
- "js-base64": "^3.7.5",
39
- "rrweb": "2.0.0-alpha.5"
40
- },
41
- "devDependencies": {
42
- "@types/ua-parser-js": "^0.7.36"
43
- },
44
- "bugs": {
45
- "url": "https://github.com/M-cheng-web/web-tracing/issues"
46
- },
47
- "homepage": "https://github.com/M-cheng-web/web-tracing#readme",
48
- "unpkg": "./index.iife.min.js"
49
- }
package/index.ts DELETED
@@ -1,75 +0,0 @@
1
- import type { InitOptions } from './src/types'
2
- import { initReplace, destroyReplace } from './src/lib/replace'
3
- import { initOptions, options as _options } from './src/lib/options'
4
- import { initBase } from './src/lib/base'
5
- import { initSendData, sendData } from './src/lib/sendData'
6
- import { initLineStatus } from './src/lib/line-status'
7
- import { initError, parseError, destroyError } from './src/lib/err'
8
- import { initEvent, destroyEvent } from './src/lib/event'
9
- import { initHttp, destroyHttp } from './src/lib/http'
10
- import { initPerformance, destroyPerformance } from './src/lib/performance'
11
- import { initPv, destroyPv } from './src/lib/pv'
12
- import {
13
- initIntersection,
14
- destroyIntersection
15
- } from './src/lib/intersectionObserver'
16
- import { _global } from './src/utils/global'
17
- import { SENDID } from './src/common'
18
- import { logError } from './src/utils/debug'
19
- import { initRecordScreen, destroyRecordScreen } from './src/lib/recordscreen'
20
- import * as exportMethods from './src/lib/exportMethods'
21
- import './src/observer/index'
22
-
23
- function init(options: InitOptions): void {
24
- if (_global.__webTracingInit__) return
25
- if (!initOptions(options)) return
26
-
27
- // 注册全局
28
- initReplace()
29
- initBase()
30
- initSendData()
31
- initLineStatus()
32
-
33
- // 注册各个业务
34
- initError()
35
- initEvent()
36
- initHttp()
37
- initPerformance()
38
- initPv()
39
- initIntersection()
40
-
41
- if (_options.value.recordScreen) initRecordScreen()
42
-
43
- _global.__webTracingInit__ = true
44
- }
45
-
46
- /**
47
- * 销毁SDK添加的事件监听器,不会影响用户手动添加的监听器
48
- */
49
- function destroyTracing(): void {
50
- destroyEvent()
51
- destroyError()
52
- destroyHttp()
53
- destroyPerformance()
54
- destroyIntersection()
55
- destroyRecordScreen()
56
- destroyPv()
57
- destroyReplace()
58
- if (sendData) sendData.destroy()
59
-
60
- // 重置全局状态,确保重新初始化时能正常工作
61
- _global.__webTracingInit__ = false
62
- }
63
-
64
- export {
65
- init,
66
- destroyTracing,
67
- InitOptions,
68
- logError,
69
- parseError,
70
- SENDID,
71
- exportMethods,
72
- _options as options
73
- }
74
- export * from './src/lib/exportMethods'
75
- export default { init, destroyTracing, ...exportMethods, options: _options }
@@ -1,13 +0,0 @@
1
- import { name, version } from '../../package.json'
2
-
3
- export const DEVICE_KEY = '_webtracing_device_id' // 设备ID Key - 私有属性
4
-
5
- export const SESSION_KEY = '_webtracing_session_id' // 会话ID Key(一个站点只允许运行一个埋点程序) - 私有属性
6
-
7
- export const SURVIVIE_MILLI_SECONDS = 1800000 // 会话 session存活时长(30minutes) - 私有属性
8
-
9
- export const SDK_LOCAL_KEY = '_webtracing_localization_key' // 事件本地化的key
10
-
11
- export const SDK_VERSION = version
12
-
13
- export const SDK_NAME = name
@@ -1,57 +0,0 @@
1
- /**
2
- * 事件类型
3
- */
4
- export enum EVENTTYPES {
5
- ERROR = 'error',
6
- CONSOLEERROR = 'consoleError',
7
- UNHANDLEDREJECTION = 'unhandledrejection',
8
- CLICK = 'click',
9
- LOAD = 'load',
10
- BEFOREUNLOAD = 'beforeunload',
11
- FETCH = 'fetch',
12
- XHROPEN = 'xhr-open',
13
- XHRSEND = 'xhr-send',
14
- HASHCHANGE = 'hashchange',
15
- HISTORYPUSHSTATE = 'history-pushState',
16
- HISTORYREPLACESTATE = 'history-replaceState',
17
- POPSTATE = 'popstate',
18
- READYSTATECHANGE = 'readystatechange',
19
- ONLINE = 'online',
20
- OFFLINE = 'offline'
21
- }
22
-
23
- /**
24
- * 触发的事件是什么类型 - eventType
25
- */
26
- export enum SEDNEVENTTYPES {
27
- PV = 'pv', // 路由跳转
28
- PVDURATION = 'pv-duration', // 页面停留事件
29
- ERROR = 'error', // 错误
30
- PERFORMANCE = 'performance', // 资源
31
- CLICK = 'click', // 点击
32
- DWELL = 'dwell', // 页面卸载
33
- CUSTOM = 'custom', // 手动触发事件
34
- INTERSECTION = 'intersection' // 曝光采集
35
- }
36
-
37
- /**
38
- * 触发的事件id - eventID
39
- */
40
- export enum SENDID {
41
- PAGE = 'page', // 页面
42
- RESOURCE = 'resource', // 资源
43
- SERVER = 'server', // 请求
44
- CODE = 'code', // code
45
- REJECT = 'reject', // reject
46
- CONSOLEERROR = 'console.error' // console.error
47
- }
48
-
49
- /**
50
- * 网页的几种加载方式
51
- */
52
- export const WEBPAGELOAD: Record<number, string> = {
53
- 0: 'navigate', // 网页通过点击链接,地址栏输入,表单提交,脚本操作等方式加载
54
- 1: 'reload', // 网页通过“重新加载”按钮或者location.reload()方法加载
55
- 2: 'back_forward', // 网页通过“前进”或“后退”按钮加载
56
- 255: 'reserved' // 任何其他来源的加载
57
- }
@@ -1,2 +0,0 @@
1
- export * from './config'
2
- export * from './constant'
package/src/lib/base.ts DELETED
@@ -1,129 +0,0 @@
1
- import { DEVICE_KEY, SDK_VERSION } from '../common'
2
- import { _support, getGlobal, isTestEnv } from '../utils/global'
3
- import { load } from '../utils/fingerprintjs'
4
- import { getCookieByName, uuid } from '../utils'
5
- import { getSessionId } from '../utils/session'
6
- import { options } from './options'
7
- import { getIPs } from '../utils/getIps'
8
- import { AnyObj } from '../types'
9
- import { computed } from '../observer'
10
- import type { ObserverValue } from '../observer/types'
11
- import { sendData } from './sendData'
12
-
13
- interface Device {
14
- clientHeight: number
15
- clientWidth: number
16
- colorDepth: number
17
- pixelDepth: number
18
- screenWidth: number
19
- screenHeight: number
20
- deviceId: string
21
- vendor: string
22
- platform: string
23
- }
24
- interface Base extends Device {
25
- userUuid: string
26
- sdkUserUuid: string
27
- ext: AnyObj
28
- appName: string
29
- appCode: string
30
- pageId: string
31
- sessionId: string
32
- sdkVersion: string
33
- ip: string
34
- }
35
-
36
- export class BaseInfo {
37
- public base: ObserverValue<Base> | undefined
38
- public pageId: string
39
- private sdkUserUuid = ''
40
- private device: Device | undefined
41
- // 基础信息是否初始化成功
42
- public _initSuccess = false
43
-
44
- constructor() {
45
- this.pageId = uuid() // 当前应用ID,在整个页面生命周期内不变,单页应用路由变化也不会改变;加载SDK时创建且只创建一次
46
-
47
- this.initSdkUserUuid()
48
- .then(() => {
49
- this.initDevice()
50
- this.initBase()
51
- })
52
- .finally(() => {
53
- this._initSuccess = true
54
- sendData.emit([])
55
- })
56
- }
57
- private initDevice() {
58
- const { screen } = getGlobal()
59
- const { clientWidth, clientHeight } = document.documentElement
60
- const { width, height, colorDepth, pixelDepth } = screen
61
- let deviceId = getCookieByName(DEVICE_KEY)
62
- if (!deviceId) {
63
- deviceId = `t_${uuid()}`
64
- document.cookie = `${DEVICE_KEY}=${deviceId};path=/;`
65
- }
66
- this.device = {
67
- clientHeight, // 网页可见区高度
68
- clientWidth, // 网页可见区宽度
69
- colorDepth, // 显示屏幕调色板的比特深度
70
- pixelDepth, // 显示屏幕的颜色分辨率
71
- deviceId, // id
72
- screenWidth: width, // 显示屏幕的宽度
73
- screenHeight: height, // 显示屏幕的高度
74
- vendor: navigator.vendor, // 浏览器名称
75
- platform: navigator.platform // 浏览器平台的环境,不是电脑系统的x64这样的(浏览器平台的环境可能是x32)
76
- }
77
- }
78
- /**
79
- * 初始化 base 数据
80
- */
81
- private initBase() {
82
- // 与一般业务上理解的sessionId做区分,此session与业务无关,单纯就是浏览器端和后端直接的联系
83
- const sessionId = getSessionId()
84
- let ip = ''
85
-
86
- this.base = computed<Base>(() => ({
87
- ...this.device!,
88
- userUuid: options.value.userUuid,
89
- sdkUserUuid: this.sdkUserUuid,
90
- ext: options.value.ext,
91
- appName: options.value.appName,
92
- appCode: options.value.appCode,
93
- pageId: this.pageId,
94
- sessionId,
95
- sdkVersion: SDK_VERSION,
96
- ip
97
- }))
98
-
99
- !isTestEnv &&
100
- getIPs().then((res: any) => {
101
- this.base!.value.ip = res[0]
102
- ip = res[0]
103
- })
104
- }
105
- /**
106
- * 初始化sdk中给用户的唯一标识
107
- */
108
- private initSdkUserUuid() {
109
- return isTestEnv
110
- ? Promise.resolve().then(() => {
111
- this.sdkUserUuid = 'unit-test-id'
112
- options.value.sdkUserUuid = 'unit-test-id'
113
- })
114
- : load({})
115
- .then((fp: any) => fp.get())
116
- .then((result: any) => {
117
- const visitorId = result.visitorId
118
- this.sdkUserUuid = visitorId
119
- options.value.sdkUserUuid = visitorId
120
- })
121
- }
122
- }
123
-
124
- export let baseInfo: BaseInfo
125
-
126
- export function initBase() {
127
- baseInfo = new BaseInfo()
128
- _support.baseInfo = baseInfo
129
- }
@@ -1,134 +0,0 @@
1
- import { sendData } from './sendData'
2
- import { AnyFun } from '../types'
3
- import { debounce, throttle, groupArray } from '../utils'
4
-
5
- const SETTIMEA = 2000
6
- const SETTIMEB = 20000
7
- const MAXLENGTHA = 5
8
- const GROUPARRAYKEY = ['errMessage', 'eventId', 'requestUrl']
9
-
10
- /**
11
- * 判断是否为批量错误
12
- * 判断流程:
13
- * 1. 先把所有错误都放入 a栈
14
- * 2. 每次发生错误后防抖 2s查 a栈是否有批量错误(批量错误: errMessage、errType相同且发生个数大于等于5)
15
- * 1. 如果为批量错误则合并这些错误并加入[时间区间参数、发生个数参数]后放入 b栈
16
- * 2. 不为批量错误则发送这些错误
17
- * 3. 每次推入错误到b栈后延迟 20s查 b栈并发送这些错误
18
- * 4. 在这个过程中,如果用户关闭了网页,会统一把 a栈、b栈内的数据发送
19
- * 5. 在这个过程中,a栈每满50个错误也会强制触发a栈和b栈的错误处理(处理结果为直接发送批量错误)
20
- */
21
- class BatchError {
22
- cacheErrorA: any[]
23
- cacheErrorB: any[]
24
- throttleProxyAddCacheErrorA: AnyFun
25
- throttleProxyAddCacheErrorB: AnyFun
26
- constructor() {
27
- this.cacheErrorA = []
28
- this.cacheErrorB = []
29
- this.throttleProxyAddCacheErrorA = debounce(
30
- this.proxyAddCacheErrorA,
31
- SETTIMEA
32
- )
33
- this.throttleProxyAddCacheErrorB = throttle(
34
- this.proxyAddCacheErrorB,
35
- SETTIMEB
36
- )
37
- }
38
- proxyAddCacheErrorA() {
39
- let len = this.cacheErrorA.length
40
- if (!len) return
41
- const arr = groupArray(this.cacheErrorA, ...GROUPARRAYKEY)
42
- const arrA = arr.filter(item => item.length < MAXLENGTHA)
43
- const arrB = arr.filter(item => item.length >= MAXLENGTHA)
44
-
45
- if (arrA.length) {
46
- sendData.emit(arrA.flat(Infinity))
47
- }
48
- if (arrB.length) {
49
- const arrBsum: any[] = []
50
- arrB.forEach(item => {
51
- const sumItem = item[0]
52
- sumItem.batchError = true
53
- sumItem.batchErrorLength = item.length
54
- sumItem.batchErrorLastHappenTime = item[item.length - 1].triggerTime
55
- arrBsum.push(sumItem)
56
- })
57
- this.cacheErrorB.push(...arrBsum)
58
- this.throttleProxyAddCacheErrorB()
59
- }
60
-
61
- while (len--) {
62
- this.cacheErrorA.shift()
63
- }
64
- }
65
- proxyAddCacheErrorB() {
66
- let len = this.cacheErrorB.length
67
- if (!len) return
68
- const arr = groupArray(this.cacheErrorB, ...GROUPARRAYKEY)
69
-
70
- while (len--) {
71
- this.cacheErrorB.shift()
72
- }
73
-
74
- // 将区间报错合并
75
- const emitList: any[] = []
76
- arr.forEach((itemList: any[]) => {
77
- const sumItem = itemList[0]
78
- if (itemList.length > 1) {
79
- sumItem.batchErrorLength = itemList.reduce(
80
- (p, item) => (p += item.batchErrorLength),
81
- 0
82
- )
83
- sumItem.batchErrorLastHappenTime =
84
- itemList[itemList.length - 1].triggerTime
85
- }
86
- emitList.push(sumItem)
87
- })
88
- sendData.emit(emitList)
89
- }
90
- /**
91
- * 获取所有的错误
92
- * 用户突然关闭页面时调用此方法集成错误
93
- */
94
- sendAllCacheError() {
95
- const errInfoList = this.cacheErrorA.concat(this.cacheErrorB)
96
- const arr = groupArray(errInfoList, ...GROUPARRAYKEY)
97
- const arrA = arr.filter(item => item.length < MAXLENGTHA)
98
- const arrB = arr.filter(item => item.length >= MAXLENGTHA)
99
-
100
- if (arrA.length) {
101
- sendData.emit(arrA.flat(Infinity), true)
102
- }
103
- if (arrB.length) {
104
- const arrBsum: any[] = []
105
- arrB.forEach(item => {
106
- const sumItem = item[0]
107
- sumItem.batchError = true
108
- sumItem.batchErrorLength = item.length
109
- sumItem.batchErrorLastHappenTime = item[item.length - 1].triggerTime
110
- arrBsum.push(sumItem)
111
- })
112
- sendData.emit(arrBsum, true)
113
- }
114
- }
115
- pushCacheErrorA(errorInfo: any) {
116
- this.cacheErrorA.push(errorInfo)
117
- this.throttleProxyAddCacheErrorA()
118
-
119
- // 每 50 个触发一次强制发送事件
120
- if (this.cacheErrorA.length >= 50) {
121
- this.proxyAddCacheErrorA()
122
- this.proxyAddCacheErrorB()
123
- }
124
- }
125
- }
126
-
127
- export let batchError: BatchError
128
-
129
- /**
130
- * 初始化错误缓存
131
- */
132
- export function initBatchError() {
133
- batchError = new BatchError()
134
- }