web-tracing-core 2.1.0
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.
- package/__test__/css/performance.css +3 -0
- package/__test__/err-batch.spec.ts +47 -0
- package/__test__/err.spec.ts +82 -0
- package/__test__/event.spec.ts +62 -0
- package/__test__/html/performance.html +57 -0
- package/__test__/html/recordscreen.html +39 -0
- package/__test__/http.spec.ts +143 -0
- package/__test__/img/performance.png +0 -0
- package/__test__/js/performance.js +3 -0
- package/__test__/performance.spec.ts +112 -0
- package/__test__/recordscreen.spec.ts +50 -0
- package/__test__/utils/index.ts +99 -0
- package/__test__/utils/pollify.ts +14 -0
- package/__test__/utils.spec.ts +18 -0
- package/dist/LICENSE +21 -0
- package/dist/README.md +97 -0
- package/dist/index.cjs +15943 -0
- package/dist/index.d.ts +323 -0
- package/dist/index.iife.js +15946 -0
- package/dist/index.iife.min.js +28 -0
- package/dist/index.mjs +15913 -0
- package/dist/package.json +49 -0
- package/index.ts +75 -0
- package/package.json +49 -0
- package/src/common/config.ts +13 -0
- package/src/common/constant.ts +57 -0
- package/src/common/index.ts +2 -0
- package/src/lib/base.ts +129 -0
- package/src/lib/err-batch.ts +134 -0
- package/src/lib/err.ts +323 -0
- package/src/lib/event-dwell.ts +63 -0
- package/src/lib/event.ts +252 -0
- package/src/lib/eventBus.ts +97 -0
- package/src/lib/exportMethods.ts +208 -0
- package/src/lib/http.ts +197 -0
- package/src/lib/intersectionObserver.ts +164 -0
- package/src/lib/line-status.ts +45 -0
- package/src/lib/options.ts +325 -0
- package/src/lib/performance.ts +302 -0
- package/src/lib/pv.ts +199 -0
- package/src/lib/recordscreen.ts +169 -0
- package/src/lib/replace.ts +371 -0
- package/src/lib/sendData.ts +264 -0
- package/src/observer/computed.ts +52 -0
- package/src/observer/config.ts +1 -0
- package/src/observer/dep.ts +21 -0
- package/src/observer/index.ts +91 -0
- package/src/observer/ref.ts +80 -0
- package/src/observer/types.ts +22 -0
- package/src/observer/watch.ts +19 -0
- package/src/observer/watcher.ts +88 -0
- package/src/types/index.ts +126 -0
- package/src/utils/debug.ts +17 -0
- package/src/utils/element.ts +47 -0
- package/src/utils/fingerprintjs.ts +2132 -0
- package/src/utils/getIps.ts +127 -0
- package/src/utils/global.ts +49 -0
- package/src/utils/index.ts +551 -0
- package/src/utils/is.ts +78 -0
- package/src/utils/localStorage.ts +70 -0
- package/src/utils/session.ts +27 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ref as _ref } from './ref'
|
|
2
|
+
import { computed as _computed } from './computed'
|
|
3
|
+
import { watch as _watch } from './watch'
|
|
4
|
+
import { ObserverValue, AnyFun, voidFun } from './types'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 响应式
|
|
8
|
+
* 说明:与vue用法相似,但不提供多样的写法,只完成了基础用法,observer文件并不引用其他文件,为了方便移植
|
|
9
|
+
* 完成功能:ref computed watch
|
|
10
|
+
* 兼容性:需要支持proxy,如不支持则响应式无效
|
|
11
|
+
*
|
|
12
|
+
* 不支持proxy时各个函数表现:
|
|
13
|
+
* ref:返回 { value: target } 对象
|
|
14
|
+
* computed:返回 { value: fun() } 对象
|
|
15
|
+
* watch:返回空函数
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
function hasProxy(): boolean {
|
|
19
|
+
return !!window.Proxy
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function ref<T>(target: T) {
|
|
23
|
+
return hasProxy() ? _ref<T>(target) : { value: target }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function computed<T>(fun: AnyFun) {
|
|
27
|
+
return hasProxy() ? _computed<T>(fun) : { value: fun() }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function watch<T>(target: ObserverValue<T>, fun: voidFun<T>) {
|
|
31
|
+
return hasProxy() ? _watch<T>(target, fun) : () => ({})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { ref, computed, watch }
|
|
35
|
+
|
|
36
|
+
// ---------------- demo 1 ----------------
|
|
37
|
+
// const data = {
|
|
38
|
+
// name: 'aaa',
|
|
39
|
+
// age: 1,
|
|
40
|
+
// cheng: {
|
|
41
|
+
// a: 1,
|
|
42
|
+
// b: 1,
|
|
43
|
+
// c: 1
|
|
44
|
+
// }
|
|
45
|
+
// }
|
|
46
|
+
// const a = ref(data)
|
|
47
|
+
// const b = ref({
|
|
48
|
+
// name: 'bbb',
|
|
49
|
+
// age: 2
|
|
50
|
+
// })
|
|
51
|
+
// const c = ref({
|
|
52
|
+
// name: 'ccc',
|
|
53
|
+
// age: 3
|
|
54
|
+
// })
|
|
55
|
+
// const d = computed<number>(() => a.value.age + b.value.age + c.value.age)
|
|
56
|
+
|
|
57
|
+
// watch(d, val => {
|
|
58
|
+
// console.log('val', val)
|
|
59
|
+
// })
|
|
60
|
+
|
|
61
|
+
// setTimeout(() => {
|
|
62
|
+
// a.value.age = 11
|
|
63
|
+
// console.log('d', d.value)
|
|
64
|
+
// }, 1000)
|
|
65
|
+
|
|
66
|
+
// ---------------- demo 2 ----------------
|
|
67
|
+
// const a = ref(1)
|
|
68
|
+
// const b = ref(2)
|
|
69
|
+
// const c = ref(3)
|
|
70
|
+
|
|
71
|
+
// const d = computed<number>(() => a.value + b.value) // 3
|
|
72
|
+
// const e = computed<number>(() => d.value + c.value) // 6
|
|
73
|
+
// const f = computed<number>(() => e.value + d.value) // 9
|
|
74
|
+
|
|
75
|
+
// c.value = 6
|
|
76
|
+
|
|
77
|
+
// setTimeout(() => {
|
|
78
|
+
// console.log('f', f.value) // 12
|
|
79
|
+
// }, 1000)
|
|
80
|
+
|
|
81
|
+
// ---------------- demo 3 ----------------
|
|
82
|
+
// const a = ref(1)
|
|
83
|
+
// const b = ref(2)
|
|
84
|
+
// const c = 3
|
|
85
|
+
|
|
86
|
+
// const d = computed<number>(() => a.value + b.value) // 3
|
|
87
|
+
// const e = computed<number>(() => d.value + c) // 6
|
|
88
|
+
|
|
89
|
+
// setTimeout(() => {
|
|
90
|
+
// console.log('e', e.value) // 6
|
|
91
|
+
// }, 1000)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Dep } from './dep'
|
|
2
|
+
import { ObserverValue, AnyFun } from './types'
|
|
3
|
+
import { OBSERVERSIGNBOARD } from './config'
|
|
4
|
+
|
|
5
|
+
function isRegExp(value: any) {
|
|
6
|
+
return Object.prototype.toString.call(value) === `[object RegExp]`
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
class Observer<T> {
|
|
10
|
+
target: ObserverValue<T>
|
|
11
|
+
constructor(target: ObserverValue<T>) {
|
|
12
|
+
this.target = target
|
|
13
|
+
}
|
|
14
|
+
defineReactive() {
|
|
15
|
+
const dep = new Dep()
|
|
16
|
+
const handlers = getHandlers(
|
|
17
|
+
() => {
|
|
18
|
+
dep.addSub()
|
|
19
|
+
},
|
|
20
|
+
(oldValue: any) => {
|
|
21
|
+
dep.notify(oldValue)
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
return new Proxy<ObserverValue<T>>(this.target, handlers)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getHandlers(
|
|
29
|
+
getCallBack?: AnyFun,
|
|
30
|
+
setCallBack?: AnyFun
|
|
31
|
+
): ProxyHandler<ObserverValue<any>> {
|
|
32
|
+
const proxyCache = new WeakMap<ObserverValue<any>, any>()
|
|
33
|
+
const handlers: ProxyHandler<ObserverValue<any>> = {
|
|
34
|
+
get(target, key: string, receiver) {
|
|
35
|
+
// console.log(`读取属性:${key}`)
|
|
36
|
+
const value = Reflect.get(target, key, receiver)
|
|
37
|
+
getCallBack && getCallBack()
|
|
38
|
+
if (typeof value === 'object' && value !== null && !isRegExp(value)) {
|
|
39
|
+
let proxy = proxyCache.get(value)
|
|
40
|
+
if (!proxy) {
|
|
41
|
+
proxy = new Proxy(value, handlers)
|
|
42
|
+
proxyCache.set(value, proxy)
|
|
43
|
+
}
|
|
44
|
+
return proxy
|
|
45
|
+
}
|
|
46
|
+
return value
|
|
47
|
+
},
|
|
48
|
+
set(target, key: string, value, receiver) {
|
|
49
|
+
const oldValue = Reflect.get(target, key, receiver)
|
|
50
|
+
if (oldValue === value) return oldValue
|
|
51
|
+
// console.log(`设置属性:${key}=${value}, oldValue:${oldValue}`)
|
|
52
|
+
const beforeTarget = JSON.parse(JSON.stringify(target))
|
|
53
|
+
const result = Reflect.set(target, key, value, receiver)
|
|
54
|
+
setCallBack && setCallBack(beforeTarget)
|
|
55
|
+
return result
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return handlers
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const refMap = new WeakMap<any, ObserverValue<any>>()
|
|
62
|
+
|
|
63
|
+
export function ref<T>(target: T) {
|
|
64
|
+
const newObj: any = { value: target }
|
|
65
|
+
newObj[OBSERVERSIGNBOARD] = true
|
|
66
|
+
|
|
67
|
+
const ob = new Observer<T>(newObj)
|
|
68
|
+
const proxy = ob.defineReactive()
|
|
69
|
+
|
|
70
|
+
refMap.set(ob, proxy)
|
|
71
|
+
return proxy
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function isRef(ref: any) {
|
|
75
|
+
return !!ref[OBSERVERSIGNBOARD]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function unRef(ref: any) {
|
|
79
|
+
return isRef(ref) ? ref.value : ref
|
|
80
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface ObserverValue<T> {
|
|
2
|
+
value: T
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export type AnyFun = {
|
|
6
|
+
(...args: any[]): any
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type voidFun<T> = {
|
|
10
|
+
(...args: T[]): void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type Options = {
|
|
14
|
+
computed?: boolean
|
|
15
|
+
watch?: boolean
|
|
16
|
+
callback?: AnyFun
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type Proxy = {
|
|
20
|
+
value: any
|
|
21
|
+
dirty: boolean
|
|
22
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Watcher } from './watcher'
|
|
2
|
+
import { isRef } from './ref'
|
|
3
|
+
import { ObserverValue, AnyFun, voidFun } from './types'
|
|
4
|
+
|
|
5
|
+
function watchInit(callback: AnyFun, getter: AnyFun) {
|
|
6
|
+
new Watcher('', { watch: true, callback }, getter)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function watch<T>(target: ObserverValue<T>, fun: voidFun<T>) {
|
|
10
|
+
if (!isRef(target)) return
|
|
11
|
+
watchInit(
|
|
12
|
+
(newValue: T, oldValue: T) => {
|
|
13
|
+
fun(newValue, oldValue)
|
|
14
|
+
},
|
|
15
|
+
function () {
|
|
16
|
+
return target.value
|
|
17
|
+
}
|
|
18
|
+
)
|
|
19
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Dep } from './dep'
|
|
2
|
+
import { computedMap } from './computed'
|
|
3
|
+
import { AnyFun, Options, Proxy } from './types'
|
|
4
|
+
|
|
5
|
+
const targetStack: Watcher[] = []
|
|
6
|
+
function pushTarget(_target: Watcher) {
|
|
7
|
+
if (Dep.target) targetStack.push(Dep.target)
|
|
8
|
+
Dep.target = _target
|
|
9
|
+
}
|
|
10
|
+
function popTarget() {
|
|
11
|
+
Dep.target = targetStack.pop()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class Watcher {
|
|
15
|
+
vm: any
|
|
16
|
+
computed: boolean
|
|
17
|
+
watch: boolean
|
|
18
|
+
proxy: Proxy
|
|
19
|
+
dep: Dep | undefined
|
|
20
|
+
getter: AnyFun | undefined
|
|
21
|
+
callback: AnyFun | undefined
|
|
22
|
+
constructor(vm: any, options: Options, getter?: AnyFun) {
|
|
23
|
+
const { computed, watch, callback } = options
|
|
24
|
+
this.getter = getter // 获取值函数
|
|
25
|
+
this.computed = computed || false // 是否为计算属性
|
|
26
|
+
this.watch = watch || false // 是否为监听属性
|
|
27
|
+
this.callback = callback // 回调函数,专门给watch用的
|
|
28
|
+
this.proxy = {
|
|
29
|
+
value: '', // 存储这个属性的值,在不需要更新的时候会直接取这个值
|
|
30
|
+
dirty: true // 表示这个属性是否脏了(脏了代表需要重新运算更新这个值)
|
|
31
|
+
}
|
|
32
|
+
this.vm = vm
|
|
33
|
+
|
|
34
|
+
if (computed) {
|
|
35
|
+
this.dep = new Dep()
|
|
36
|
+
} else if (watch) {
|
|
37
|
+
this.watchGet()
|
|
38
|
+
} else {
|
|
39
|
+
this.get()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
update(oldValue: any) {
|
|
43
|
+
if (this.computed) {
|
|
44
|
+
// 更新计算属性(不涉及渲染)
|
|
45
|
+
this.dep!.notify()
|
|
46
|
+
} else if (this.watch) {
|
|
47
|
+
// 触发watch
|
|
48
|
+
// this.watchGet()
|
|
49
|
+
if (oldValue !== this.proxy.value) {
|
|
50
|
+
this.callback && this.callback(this.proxy.value, oldValue)
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
// 更新data, 触发依赖其的属性更新
|
|
54
|
+
this.get()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
get() {
|
|
58
|
+
// 存入当前上下文到依赖(表示当前是哪个属性在依赖其他属性,这样在其他属性发生变化时就知道应该通知谁了)
|
|
59
|
+
pushTarget(this)
|
|
60
|
+
|
|
61
|
+
// 目前只有计算属性才会调用 get 方法
|
|
62
|
+
const value = this.computed ? computedMap.get(this.vm)!.call(this.vm) : ''
|
|
63
|
+
if (value !== this.proxy.value) {
|
|
64
|
+
this.proxy.dirty = false // 标记为不是脏的数据
|
|
65
|
+
this.proxy.value = value // 缓存数据,在数据不脏的时候直接拿这个缓存值
|
|
66
|
+
}
|
|
67
|
+
popTarget() // 取出依赖
|
|
68
|
+
return value
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 监听属性专用 - 拿到最新值并添加依赖
|
|
72
|
+
*/
|
|
73
|
+
watchGet() {
|
|
74
|
+
pushTarget(this) // 将当前上下文放入 Dep.target
|
|
75
|
+
this.proxy.dirty = false // 设定不为脏数据
|
|
76
|
+
if (this.getter) {
|
|
77
|
+
this.proxy.value = this.getter() // 设定值(在这个过程中就给上了依赖)
|
|
78
|
+
}
|
|
79
|
+
popTarget() // 取出上面放入 Dep.target 的上下文
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 计算属性专用 - 添加依赖
|
|
83
|
+
* 其他值用到了这个计算属性就会被记录添加到依赖中
|
|
84
|
+
*/
|
|
85
|
+
depend() {
|
|
86
|
+
this.dep!.addSub()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { EventBus } from '../lib/eventBus'
|
|
2
|
+
import type { BaseInfo } from '../lib/base'
|
|
3
|
+
import type { ObserverValue } from '../observer/types'
|
|
4
|
+
|
|
5
|
+
export type WebTracing = {
|
|
6
|
+
eventBus: EventBus
|
|
7
|
+
baseInfo: BaseInfo
|
|
8
|
+
sendData: any
|
|
9
|
+
lineStatus: any
|
|
10
|
+
options: ObserverValue<InternalOptions> // 配置信息
|
|
11
|
+
firstScreen: any // 首屏信息
|
|
12
|
+
intersection: any // 曝光采集
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface Pv {
|
|
16
|
+
core?: boolean // 是否发送页面跳转相关数据
|
|
17
|
+
}
|
|
18
|
+
interface Performance {
|
|
19
|
+
core?: boolean // 是否采集静态资源、接口的相关数据
|
|
20
|
+
firstResource?: boolean // 是否采集首次进入页面的数据
|
|
21
|
+
server?: boolean // 是否采集接口请求
|
|
22
|
+
}
|
|
23
|
+
interface Error {
|
|
24
|
+
core?: boolean // 是否采集异常数据
|
|
25
|
+
server?: boolean // 是否采集报错接口数据
|
|
26
|
+
}
|
|
27
|
+
interface Event {
|
|
28
|
+
core?: boolean // 是否采集点击事件
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* sdk内部配置
|
|
33
|
+
*/
|
|
34
|
+
export type InternalOptions = {
|
|
35
|
+
dsn: string // 上报地址
|
|
36
|
+
appName: string // 应用名称
|
|
37
|
+
appCode: string // 应用code
|
|
38
|
+
appVersion: string // 应用版本
|
|
39
|
+
userUuid: string // 用户id(外部填充进来的id)
|
|
40
|
+
sdkUserUuid: string // 用户id(sdk内部生成的id)
|
|
41
|
+
debug: boolean // 是否开启调试模式(控制台会输出sdk动作)
|
|
42
|
+
pv: Pv
|
|
43
|
+
performance: Performance
|
|
44
|
+
error: Error
|
|
45
|
+
event: Event
|
|
46
|
+
ext: AnyObj // 自定义全局附加参数(放在baseInfo中)
|
|
47
|
+
tracesSampleRate: number // 抽样发送
|
|
48
|
+
cacheMaxLength: number // 上报数据最大缓存数
|
|
49
|
+
cacheWatingTime: number // 上报数据最大等待时间
|
|
50
|
+
ignoreErrors: Array<string | RegExp> // 错误类型事件过滤
|
|
51
|
+
ignoreRequest: Array<string | RegExp> // 请求类型事件过滤
|
|
52
|
+
scopeError: boolean // 当某个时间段报错时,会将此类错误转为特殊错误类型,会新增错误持续时间范围
|
|
53
|
+
localization: boolean // 是否本地化:sdk不再主动发送事件,事件都存储在本地,由用户手动调用方法发送
|
|
54
|
+
sendTypeByXmlBody?: boolean // 是否强制指定发送形式为xml,body请求方式
|
|
55
|
+
// whiteScreen: boolean // 开启白屏检测
|
|
56
|
+
beforePushEventList: AnyFun[] // 添加到行为列表前的 hook (在这里面可以给出错误类型,然后就能达到用户想拿到是何种事件类型的触发)
|
|
57
|
+
beforeSendData: AnyFun[] // 数据上报前的 hook
|
|
58
|
+
afterSendData: AnyFun[] // 数据上报后的 hook
|
|
59
|
+
localizationOverFlow: VoidFun // 本地化存储溢出后的回调
|
|
60
|
+
recordScreen: boolean // 是否启动录屏
|
|
61
|
+
timeout?: number // 日志上报超时时间(毫秒)
|
|
62
|
+
maxQueueLength?: number // 上报接口异常,日志队列最大缓存数
|
|
63
|
+
checkRecoverInterval?: number // 多长时间检测一次上报接口是否恢复(分钟)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* sdk初始化入参配置
|
|
68
|
+
*/
|
|
69
|
+
export type InitOptions = {
|
|
70
|
+
dsn: string // 上报地址
|
|
71
|
+
appName: string // 应用名称
|
|
72
|
+
appCode?: string // 应用code
|
|
73
|
+
appVersion?: string // 应用版本
|
|
74
|
+
userUuid?: string // 用户id(外部填充进来的id)
|
|
75
|
+
debug?: boolean // 是否开启调试模式(控制台会输出sdk动作)
|
|
76
|
+
pv?: Pv | boolean
|
|
77
|
+
performance?: Performance | boolean
|
|
78
|
+
error?: Error | boolean
|
|
79
|
+
event?: Event | boolean
|
|
80
|
+
ext?: { [key: string]: any } // 自定义全局附加参数(放在baseInfo中)
|
|
81
|
+
tracesSampleRate?: number // 抽样发送
|
|
82
|
+
cacheMaxLength?: number // 上报数据最大缓存数
|
|
83
|
+
cacheWatingTime?: number // 上报数据最大等待时间
|
|
84
|
+
ignoreErrors?: Array<string | RegExp> // 错误类型事件过滤
|
|
85
|
+
ignoreRequest?: Array<string | RegExp> // 请求类型事件过滤
|
|
86
|
+
scopeError?: boolean // 当某个时间段报错时,会将此类错误转为特殊错误类型,会新增错误持续时间范围
|
|
87
|
+
localization?: boolean // 是否本地化:sdk不再主动发送事件,事件都存储在本地,由用户手动调用方法发送
|
|
88
|
+
sendTypeByXmlBody?: boolean // 是否强制指定发送形式为xml,body请求方式
|
|
89
|
+
// whiteScreen?: boolean // 开启白屏检测
|
|
90
|
+
beforePushEventList?: (data: any) => any // 添加到行为列表前的 hook (在这里面可以给出错误类型,然后就能达到用户想拿到是何种事件类型的触发)
|
|
91
|
+
beforeSendData?: (data: any) => any // 数据上报前的 hook
|
|
92
|
+
afterSendData?: (data: any) => void // 数据上报后的 hook
|
|
93
|
+
recordScreen?: boolean // 是否启动录屏
|
|
94
|
+
timeout?: number // 日志上报超时时间(毫秒)
|
|
95
|
+
maxQueueLength?: number // 上报接口异常,日志队列最大缓存数
|
|
96
|
+
checkRecoverInterval?: number // 多长时间检测一次上报接口是否恢复(分钟)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export type ElementOrList = Element | Element[]
|
|
100
|
+
export interface TargetGather {
|
|
101
|
+
target: ElementOrList
|
|
102
|
+
threshold: number
|
|
103
|
+
params?: AnyObj
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface RecordEventScope {
|
|
107
|
+
scope: string
|
|
108
|
+
eventList: any[]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export type VoidFun = {
|
|
112
|
+
(...args: any[]): void
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export type AnyFun = {
|
|
116
|
+
(...args: any[]): any
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export type AnyObj<T = any> = {
|
|
120
|
+
[key: string]: T
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface SendData {
|
|
124
|
+
baseInfo: object
|
|
125
|
+
eventInfo: unknown[]
|
|
126
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { options } from '../lib/options'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 控制台输出信息
|
|
5
|
+
* @param args 输出信息
|
|
6
|
+
*/
|
|
7
|
+
export function debug(...args: any[]): void {
|
|
8
|
+
if (options.value.debug) console.log('@web-tracing: ', ...args)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 控制台输出错误信息
|
|
13
|
+
* @param args 错误信息
|
|
14
|
+
*/
|
|
15
|
+
export function logError(...args: any[]): void {
|
|
16
|
+
console.error('@web-tracing: ', ...args)
|
|
17
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 判断元素是否含有目标属性
|
|
3
|
+
*/
|
|
4
|
+
export function getElByAttr(list: Element[], key: string): Element | undefined {
|
|
5
|
+
return list.find(item => item.hasAttribute && item.hasAttribute(key))
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 是否为简单的标签
|
|
10
|
+
* 简单标签数组:['em', 'b', 'strong', 'span', 'img', 'i', 'code']
|
|
11
|
+
*/
|
|
12
|
+
export function isSimpleEl(children: Element[]): boolean {
|
|
13
|
+
if (children.length > 0) {
|
|
14
|
+
const arr = ['em', 'b', 'strong', 'span', 'img', 'i', 'code']
|
|
15
|
+
const a = children.filter(
|
|
16
|
+
({ tagName }) => arr.indexOf(tagName.toLowerCase()) >= 0
|
|
17
|
+
)
|
|
18
|
+
return a.length === children.length
|
|
19
|
+
}
|
|
20
|
+
return true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 获取元素的关系字符串(从子级一直递归到最外层)
|
|
25
|
+
* 例如两层div的关系会得到字符串: div>div
|
|
26
|
+
*/
|
|
27
|
+
export function getNodeXPath(node: Element, curPath = ''): string {
|
|
28
|
+
if (!node) return curPath
|
|
29
|
+
const parent = node.parentElement
|
|
30
|
+
const { id } = node
|
|
31
|
+
const tagName = node.tagName.toLowerCase()
|
|
32
|
+
const path = curPath ? `>${curPath}` : ''
|
|
33
|
+
|
|
34
|
+
if (
|
|
35
|
+
!parent ||
|
|
36
|
+
parent === document.documentElement ||
|
|
37
|
+
parent === document.body
|
|
38
|
+
) {
|
|
39
|
+
return `${tagName}${path}`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (id) {
|
|
43
|
+
return `#${id}${path}` // 知道了id 就不需要获取上下级关系了(id是唯一的)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return getNodeXPath(parent, `${tagName}${path}`)
|
|
47
|
+
}
|