@be-link/cls-logger 1.0.1-beta.9 → 1.0.4
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/README.md +115 -31
- package/dist/ClsLogger.d.ts.map +1 -1
- package/dist/ClsLoggerCore.d.ts +4 -3
- package/dist/ClsLoggerCore.d.ts.map +1 -1
- package/dist/behaviorMonitor.d.ts.map +1 -1
- package/dist/errorMonitor.d.ts.map +1 -1
- package/dist/index.esm.js +176 -44
- package/dist/index.js +176 -44
- package/dist/index.umd.js +176 -44
- package/dist/mini.esm.js +111 -19
- package/dist/mini.js +111 -19
- package/dist/performanceMonitor.d.ts.map +1 -1
- package/dist/types.d.ts +19 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/web.esm.js +111 -19
- package/dist/web.js +111 -19
- package/package.json +1 -1
package/dist/index.umd.js
CHANGED
|
@@ -564,6 +564,19 @@
|
|
|
564
564
|
return '';
|
|
565
565
|
}
|
|
566
566
|
}
|
|
567
|
+
function getMpPagePath() {
|
|
568
|
+
try {
|
|
569
|
+
const pages = globalThis.getCurrentPages?.();
|
|
570
|
+
if (Array.isArray(pages) && pages.length > 0) {
|
|
571
|
+
const page = pages[pages.length - 1];
|
|
572
|
+
return page.route || page.__route__ || '';
|
|
573
|
+
}
|
|
574
|
+
return '';
|
|
575
|
+
}
|
|
576
|
+
catch {
|
|
577
|
+
return '';
|
|
578
|
+
}
|
|
579
|
+
}
|
|
567
580
|
function normalizeErrorLike(err, maxTextLength) {
|
|
568
581
|
if (err && typeof err === 'object') {
|
|
569
582
|
const anyErr = err;
|
|
@@ -723,6 +736,7 @@
|
|
|
723
736
|
return;
|
|
724
737
|
const e = normalizeErrorLike(msg, options.maxTextLength);
|
|
725
738
|
const payload = {
|
|
739
|
+
pagePath: getMpPagePath(),
|
|
726
740
|
source: 'wx.onError',
|
|
727
741
|
message: e.message,
|
|
728
742
|
errorName: e.name,
|
|
@@ -749,6 +763,7 @@
|
|
|
749
763
|
return;
|
|
750
764
|
const e = normalizeErrorLike(res?.reason, options.maxTextLength);
|
|
751
765
|
const payload = {
|
|
766
|
+
pagePath: getMpPagePath(),
|
|
752
767
|
source: 'wx.onUnhandledRejection',
|
|
753
768
|
message: e.message,
|
|
754
769
|
errorName: e.name,
|
|
@@ -780,6 +795,7 @@
|
|
|
780
795
|
if (sampleHit$1(options.sampleRate)) {
|
|
781
796
|
const e = normalizeErrorLike(args?.[0], options.maxTextLength);
|
|
782
797
|
const payload = {
|
|
798
|
+
pagePath: getMpPagePath(),
|
|
783
799
|
source: 'App.onError',
|
|
784
800
|
message: e.message,
|
|
785
801
|
errorName: e.name,
|
|
@@ -803,6 +819,7 @@
|
|
|
803
819
|
const reason = args?.[0]?.reason ?? args?.[0];
|
|
804
820
|
const e = normalizeErrorLike(reason, options.maxTextLength);
|
|
805
821
|
const payload = {
|
|
822
|
+
pagePath: getMpPagePath(),
|
|
806
823
|
source: 'App.onUnhandledRejection',
|
|
807
824
|
message: e.message,
|
|
808
825
|
errorName: e.name,
|
|
@@ -1110,18 +1127,28 @@
|
|
|
1110
1127
|
continue;
|
|
1111
1128
|
// Page Render: firstRender
|
|
1112
1129
|
if (entry.entryType === 'render' && entry.name === 'firstRender') {
|
|
1130
|
+
const duration = typeof entry.duration === 'number'
|
|
1131
|
+
? entry.duration
|
|
1132
|
+
: typeof entry.startTime === 'number' && typeof entry.endTime === 'number'
|
|
1133
|
+
? entry.endTime - entry.startTime
|
|
1134
|
+
: 0;
|
|
1113
1135
|
report(options.reportType, {
|
|
1114
1136
|
metric: 'page-render',
|
|
1115
|
-
duration
|
|
1137
|
+
duration,
|
|
1116
1138
|
pagePath: entry.path || '',
|
|
1117
1139
|
unit: 'ms',
|
|
1118
1140
|
});
|
|
1119
1141
|
}
|
|
1120
1142
|
// Route Switch: route
|
|
1121
1143
|
else if (entry.entryType === 'navigation' && entry.name === 'route') {
|
|
1144
|
+
const duration = typeof entry.duration === 'number'
|
|
1145
|
+
? entry.duration
|
|
1146
|
+
: typeof entry.startTime === 'number' && typeof entry.endTime === 'number'
|
|
1147
|
+
? entry.endTime - entry.startTime
|
|
1148
|
+
: 0;
|
|
1122
1149
|
report(options.reportType, {
|
|
1123
1150
|
metric: 'route',
|
|
1124
|
-
duration
|
|
1151
|
+
duration,
|
|
1125
1152
|
pagePath: entry.path || '',
|
|
1126
1153
|
unit: 'ms',
|
|
1127
1154
|
});
|
|
@@ -1465,7 +1492,7 @@
|
|
|
1465
1492
|
const tag = (el.tagName || '').toLowerCase();
|
|
1466
1493
|
const trackId = getAttr(el, clickTrackIdAttr);
|
|
1467
1494
|
// 过滤无效点击:白名单 tag + 没有 trackId
|
|
1468
|
-
if (clickWhiteList.includes(tag)
|
|
1495
|
+
if (clickWhiteList.includes(tag) || !trackId)
|
|
1469
1496
|
return;
|
|
1470
1497
|
void uvStatePromise.then(({ uvId, meta }) => {
|
|
1471
1498
|
if (destroyed)
|
|
@@ -1506,8 +1533,12 @@
|
|
|
1506
1533
|
g.Page = function patchedPage(conf) {
|
|
1507
1534
|
const originalOnShow = conf?.onShow;
|
|
1508
1535
|
conf.onShow = function (...args) {
|
|
1509
|
-
if (pvEnabled)
|
|
1510
|
-
|
|
1536
|
+
if (pvEnabled) {
|
|
1537
|
+
const pagePath = getPagePath();
|
|
1538
|
+
if (pagePath?.length > 0) {
|
|
1539
|
+
reportPv(pagePath);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1511
1542
|
return typeof originalOnShow === 'function' ? originalOnShow.apply(this, args) : undefined;
|
|
1512
1543
|
};
|
|
1513
1544
|
// 点击:wrap 页面 methods(bindtap 等会调用到这里的 handler)
|
|
@@ -1861,6 +1892,7 @@
|
|
|
1861
1892
|
this.endpoint = 'ap-shanghai.cls.tencentcs.com';
|
|
1862
1893
|
this.retryTimes = 10;
|
|
1863
1894
|
this.source = '127.0.0.1';
|
|
1895
|
+
this.enabled = true;
|
|
1864
1896
|
this.projectId = '';
|
|
1865
1897
|
this.projectName = '';
|
|
1866
1898
|
this.appId = '';
|
|
@@ -1891,9 +1923,14 @@
|
|
|
1891
1923
|
* 子类可按需重写(默认检测 wx)
|
|
1892
1924
|
*/
|
|
1893
1925
|
detectEnvType() {
|
|
1894
|
-
const
|
|
1895
|
-
|
|
1926
|
+
const g = globalThis;
|
|
1927
|
+
// 微信、支付宝、字节跳动、UniApp 等小程序环境通常都有特定全局变量
|
|
1928
|
+
if ((g.wx && typeof g.wx.getSystemInfoSync === 'function') ||
|
|
1929
|
+
(g.my && typeof g.my.getSystemInfoSync === 'function') ||
|
|
1930
|
+
(g.tt && typeof g.tt.getSystemInfoSync === 'function') ||
|
|
1931
|
+
(g.uni && typeof g.uni.getSystemInfoSync === 'function')) {
|
|
1896
1932
|
return 'miniprogram';
|
|
1933
|
+
}
|
|
1897
1934
|
return 'browser';
|
|
1898
1935
|
}
|
|
1899
1936
|
init(options) {
|
|
@@ -1931,6 +1968,7 @@
|
|
|
1931
1968
|
this.appId = options.appId ?? this.appId;
|
|
1932
1969
|
this.appVersion = options.appVersion ?? this.appVersion;
|
|
1933
1970
|
this.envType = nextEnvType;
|
|
1971
|
+
this.enabled = options.enabled ?? true;
|
|
1934
1972
|
// 可选:外部注入 SDK(优先级:sdkLoader > sdk)
|
|
1935
1973
|
this.sdkLoaderOverride = options.sdkLoader ?? this.sdkLoaderOverride;
|
|
1936
1974
|
this.sdkOverride = options.sdk ?? this.sdkOverride;
|
|
@@ -1947,15 +1985,17 @@
|
|
|
1947
1985
|
void this.getInstance().catch(() => {
|
|
1948
1986
|
// ignore
|
|
1949
1987
|
});
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1988
|
+
if (this.enabled) {
|
|
1989
|
+
// 启动时尝试发送失败缓存
|
|
1990
|
+
this.flushFailed();
|
|
1991
|
+
// 初始化后立即启动请求监听
|
|
1992
|
+
this.startRequestMonitor(options.requestMonitor);
|
|
1993
|
+
// 初始化后立即启动错误监控/性能监控
|
|
1994
|
+
this.startErrorMonitor(options.errorMonitor);
|
|
1995
|
+
this.startPerformanceMonitor(options.performanceMonitor);
|
|
1996
|
+
// 初始化后立即启动行为埋点(PV/UV/点击)
|
|
1997
|
+
this.startBehaviorMonitor(options.behaviorMonitor);
|
|
1998
|
+
}
|
|
1959
1999
|
}
|
|
1960
2000
|
getBaseFields() {
|
|
1961
2001
|
let auto = undefined;
|
|
@@ -2080,6 +2120,8 @@
|
|
|
2080
2120
|
* - 最终会把 fields 展开成 CLS 的 content(key/value 都会转成 string)
|
|
2081
2121
|
*/
|
|
2082
2122
|
put(fields, options = {}) {
|
|
2123
|
+
if (!this.enabled)
|
|
2124
|
+
return;
|
|
2083
2125
|
if (!fields)
|
|
2084
2126
|
return;
|
|
2085
2127
|
if (!this.topicId) {
|
|
@@ -2138,6 +2180,8 @@
|
|
|
2138
2180
|
* - 埋点入参必须是一维(扁平)Object,非原始值会被 stringify
|
|
2139
2181
|
*/
|
|
2140
2182
|
enqueue(fields, options = {}) {
|
|
2183
|
+
if (!this.enabled)
|
|
2184
|
+
return;
|
|
2141
2185
|
if (!fields)
|
|
2142
2186
|
return;
|
|
2143
2187
|
const time = Date.now();
|
|
@@ -2176,6 +2220,8 @@
|
|
|
2176
2220
|
* 批量上报(每条 item.data 展开为 log content)
|
|
2177
2221
|
*/
|
|
2178
2222
|
putBatch(queue) {
|
|
2223
|
+
if (!this.enabled)
|
|
2224
|
+
return;
|
|
2179
2225
|
if (!queue || queue.length === 0)
|
|
2180
2226
|
return;
|
|
2181
2227
|
if (!this.topicId) {
|
|
@@ -2219,6 +2265,8 @@
|
|
|
2219
2265
|
* 参考《一、概述》:统一上报入口(内存队列 + 批量发送)
|
|
2220
2266
|
*/
|
|
2221
2267
|
report(log) {
|
|
2268
|
+
if (!this.enabled)
|
|
2269
|
+
return;
|
|
2222
2270
|
if (!log?.type)
|
|
2223
2271
|
return;
|
|
2224
2272
|
if (!this.topicId) {
|
|
@@ -2266,15 +2314,57 @@
|
|
|
2266
2314
|
return nowTs + this.batchIntervalMs;
|
|
2267
2315
|
}
|
|
2268
2316
|
info(message, data = {}) {
|
|
2269
|
-
|
|
2317
|
+
let msg = '';
|
|
2318
|
+
let extra = {};
|
|
2319
|
+
if (message instanceof Error) {
|
|
2320
|
+
msg = message.message;
|
|
2321
|
+
extra = {
|
|
2322
|
+
stack: message.stack,
|
|
2323
|
+
name: message.name,
|
|
2324
|
+
...data,
|
|
2325
|
+
};
|
|
2326
|
+
}
|
|
2327
|
+
else {
|
|
2328
|
+
msg = String(message);
|
|
2329
|
+
extra = data;
|
|
2330
|
+
}
|
|
2331
|
+
const payload = normalizeFlatFields({ message: msg, ...extra }, 'info');
|
|
2270
2332
|
this.report({ type: 'info', data: payload, timestamp: Date.now() });
|
|
2271
2333
|
}
|
|
2272
2334
|
warn(message, data = {}) {
|
|
2273
|
-
|
|
2335
|
+
let msg = '';
|
|
2336
|
+
let extra = {};
|
|
2337
|
+
if (message instanceof Error) {
|
|
2338
|
+
msg = message.message;
|
|
2339
|
+
extra = {
|
|
2340
|
+
stack: message.stack,
|
|
2341
|
+
name: message.name,
|
|
2342
|
+
...data,
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2345
|
+
else {
|
|
2346
|
+
msg = String(message);
|
|
2347
|
+
extra = data;
|
|
2348
|
+
}
|
|
2349
|
+
const payload = normalizeFlatFields({ message: msg, ...extra }, 'warn');
|
|
2274
2350
|
this.report({ type: 'warn', data: payload, timestamp: Date.now() });
|
|
2275
2351
|
}
|
|
2276
2352
|
error(message, data = {}) {
|
|
2277
|
-
|
|
2353
|
+
let msg = '';
|
|
2354
|
+
let extra = {};
|
|
2355
|
+
if (message instanceof Error) {
|
|
2356
|
+
msg = message.message;
|
|
2357
|
+
extra = {
|
|
2358
|
+
stack: message.stack,
|
|
2359
|
+
name: message.name,
|
|
2360
|
+
...data,
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2363
|
+
else {
|
|
2364
|
+
msg = String(message);
|
|
2365
|
+
extra = data;
|
|
2366
|
+
}
|
|
2367
|
+
const payload = normalizeFlatFields({ message: msg, ...extra }, 'error');
|
|
2278
2368
|
this.report({ type: 'error', data: payload, timestamp: Date.now() });
|
|
2279
2369
|
}
|
|
2280
2370
|
track(trackType, data = {}) {
|
|
@@ -2381,6 +2471,8 @@
|
|
|
2381
2471
|
writeStringStorage(this.failedCacheKey, JSON.stringify(next));
|
|
2382
2472
|
}
|
|
2383
2473
|
flushFailed() {
|
|
2474
|
+
if (!this.enabled)
|
|
2475
|
+
return;
|
|
2384
2476
|
const raw = readStringStorage(this.failedCacheKey);
|
|
2385
2477
|
if (!raw)
|
|
2386
2478
|
return;
|
|
@@ -2496,38 +2588,78 @@
|
|
|
2496
2588
|
}
|
|
2497
2589
|
}
|
|
2498
2590
|
const isMini = this.envType === 'miniprogram';
|
|
2499
|
-
//
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2591
|
+
// 3) 尝试 require / 全局变量
|
|
2592
|
+
// Mini Program: 尝试直接 require
|
|
2593
|
+
if (isMini) {
|
|
2594
|
+
// 显式使用字面量 require,帮助打包工具识别依赖(尤其是 CJS 构建模式下)
|
|
2595
|
+
try {
|
|
2596
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
2597
|
+
const req = typeof require === 'function' ? require('tencentcloud-cls-sdk-js-mini') : null;
|
|
2598
|
+
const reqSdk = normalizeSdk(req);
|
|
2599
|
+
if (reqSdk) {
|
|
2600
|
+
this.sdk = reqSdk;
|
|
2601
|
+
return reqSdk;
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
catch {
|
|
2605
|
+
// ignore
|
|
2606
|
+
}
|
|
2607
|
+
// 尝试使用 tryRequire(作为补充)
|
|
2608
|
+
const reqMod = tryRequire('tencentcloud-cls-sdk-js-mini');
|
|
2609
|
+
const reqSdk = normalizeSdk(reqMod);
|
|
2610
|
+
if (reqSdk) {
|
|
2611
|
+
this.sdk = reqSdk;
|
|
2612
|
+
return reqSdk;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
else {
|
|
2616
|
+
// Web: 优先读全局变量 (UMD)
|
|
2504
2617
|
const g = readGlobal('tencentcloudClsSdkJsWeb');
|
|
2505
2618
|
const sdk = normalizeSdk(g);
|
|
2506
2619
|
if (sdk) {
|
|
2507
2620
|
this.sdk = sdk;
|
|
2508
2621
|
return sdk;
|
|
2509
2622
|
}
|
|
2623
|
+
// Web: 尝试 require
|
|
2624
|
+
const reqMod = tryRequire('tencentcloud-cls-sdk-js-web');
|
|
2625
|
+
const reqSdk = normalizeSdk(reqMod);
|
|
2626
|
+
if (reqSdk) {
|
|
2627
|
+
this.sdk = reqSdk;
|
|
2628
|
+
return reqSdk;
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
// 4) 动态 import
|
|
2632
|
+
// 使用字符串字面量,确保 Bundler 能正确识别并进行 Code Splitting
|
|
2633
|
+
if (isMini) {
|
|
2634
|
+
this.sdkPromise = import('tencentcloud-cls-sdk-js-mini')
|
|
2635
|
+
.then((m) => {
|
|
2636
|
+
const sdk = normalizeSdk(m);
|
|
2637
|
+
if (!sdk)
|
|
2638
|
+
throw new Error(`ClsLogger.loadSdk: invalid sdk module for mini`);
|
|
2639
|
+
this.sdk = sdk;
|
|
2640
|
+
return sdk;
|
|
2641
|
+
})
|
|
2642
|
+
.catch((err) => {
|
|
2643
|
+
this.sdkPromise = null;
|
|
2644
|
+
console.error('[ClsLogger] Failed to load mini sdk:', err);
|
|
2645
|
+
throw err;
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
else {
|
|
2649
|
+
this.sdkPromise = import('tencentcloud-cls-sdk-js-web')
|
|
2650
|
+
.then((m) => {
|
|
2651
|
+
const sdk = normalizeSdk(m);
|
|
2652
|
+
if (!sdk)
|
|
2653
|
+
throw new Error(`ClsLogger.loadSdk: invalid sdk module for web`);
|
|
2654
|
+
this.sdk = sdk;
|
|
2655
|
+
return sdk;
|
|
2656
|
+
})
|
|
2657
|
+
.catch((err) => {
|
|
2658
|
+
this.sdkPromise = null;
|
|
2659
|
+
console.error('[ClsLogger] Failed to load web sdk:', err);
|
|
2660
|
+
throw err;
|
|
2661
|
+
});
|
|
2510
2662
|
}
|
|
2511
|
-
// 尽量同步 require
|
|
2512
|
-
const reqMod = tryRequire(isMini ? MINI_SDK : WEB_SDK);
|
|
2513
|
-
const reqSdk = normalizeSdk(reqMod);
|
|
2514
|
-
if (reqSdk) {
|
|
2515
|
-
this.sdk = reqSdk;
|
|
2516
|
-
return reqSdk;
|
|
2517
|
-
}
|
|
2518
|
-
// 动态 import
|
|
2519
|
-
this.sdkPromise = (isMini ? import(MINI_SDK) : import(WEB_SDK))
|
|
2520
|
-
.then((m) => {
|
|
2521
|
-
const sdk = normalizeSdk(m);
|
|
2522
|
-
if (!sdk)
|
|
2523
|
-
throw new Error(`ClsLogger.loadSdk: invalid sdk module for ${isMini ? MINI_SDK : WEB_SDK}`);
|
|
2524
|
-
this.sdk = sdk;
|
|
2525
|
-
return sdk;
|
|
2526
|
-
})
|
|
2527
|
-
.catch((err) => {
|
|
2528
|
-
this.sdkPromise = null;
|
|
2529
|
-
throw err;
|
|
2530
|
-
});
|
|
2531
2663
|
return this.sdkPromise;
|
|
2532
2664
|
}
|
|
2533
2665
|
}
|
package/dist/mini.esm.js
CHANGED
|
@@ -560,6 +560,19 @@ function getPagePath$1() {
|
|
|
560
560
|
return '';
|
|
561
561
|
}
|
|
562
562
|
}
|
|
563
|
+
function getMpPagePath() {
|
|
564
|
+
try {
|
|
565
|
+
const pages = globalThis.getCurrentPages?.();
|
|
566
|
+
if (Array.isArray(pages) && pages.length > 0) {
|
|
567
|
+
const page = pages[pages.length - 1];
|
|
568
|
+
return page.route || page.__route__ || '';
|
|
569
|
+
}
|
|
570
|
+
return '';
|
|
571
|
+
}
|
|
572
|
+
catch {
|
|
573
|
+
return '';
|
|
574
|
+
}
|
|
575
|
+
}
|
|
563
576
|
function normalizeErrorLike(err, maxTextLength) {
|
|
564
577
|
if (err && typeof err === 'object') {
|
|
565
578
|
const anyErr = err;
|
|
@@ -719,6 +732,7 @@ function installMiniProgramErrorMonitor(report, options) {
|
|
|
719
732
|
return;
|
|
720
733
|
const e = normalizeErrorLike(msg, options.maxTextLength);
|
|
721
734
|
const payload = {
|
|
735
|
+
pagePath: getMpPagePath(),
|
|
722
736
|
source: 'wx.onError',
|
|
723
737
|
message: e.message,
|
|
724
738
|
errorName: e.name,
|
|
@@ -745,6 +759,7 @@ function installMiniProgramErrorMonitor(report, options) {
|
|
|
745
759
|
return;
|
|
746
760
|
const e = normalizeErrorLike(res?.reason, options.maxTextLength);
|
|
747
761
|
const payload = {
|
|
762
|
+
pagePath: getMpPagePath(),
|
|
748
763
|
source: 'wx.onUnhandledRejection',
|
|
749
764
|
message: e.message,
|
|
750
765
|
errorName: e.name,
|
|
@@ -776,6 +791,7 @@ function installMiniProgramErrorMonitor(report, options) {
|
|
|
776
791
|
if (sampleHit$1(options.sampleRate)) {
|
|
777
792
|
const e = normalizeErrorLike(args?.[0], options.maxTextLength);
|
|
778
793
|
const payload = {
|
|
794
|
+
pagePath: getMpPagePath(),
|
|
779
795
|
source: 'App.onError',
|
|
780
796
|
message: e.message,
|
|
781
797
|
errorName: e.name,
|
|
@@ -799,6 +815,7 @@ function installMiniProgramErrorMonitor(report, options) {
|
|
|
799
815
|
const reason = args?.[0]?.reason ?? args?.[0];
|
|
800
816
|
const e = normalizeErrorLike(reason, options.maxTextLength);
|
|
801
817
|
const payload = {
|
|
818
|
+
pagePath: getMpPagePath(),
|
|
802
819
|
source: 'App.onUnhandledRejection',
|
|
803
820
|
message: e.message,
|
|
804
821
|
errorName: e.name,
|
|
@@ -1106,18 +1123,28 @@ function installMiniProgramPerformanceMonitor(report, options) {
|
|
|
1106
1123
|
continue;
|
|
1107
1124
|
// Page Render: firstRender
|
|
1108
1125
|
if (entry.entryType === 'render' && entry.name === 'firstRender') {
|
|
1126
|
+
const duration = typeof entry.duration === 'number'
|
|
1127
|
+
? entry.duration
|
|
1128
|
+
: typeof entry.startTime === 'number' && typeof entry.endTime === 'number'
|
|
1129
|
+
? entry.endTime - entry.startTime
|
|
1130
|
+
: 0;
|
|
1109
1131
|
report(options.reportType, {
|
|
1110
1132
|
metric: 'page-render',
|
|
1111
|
-
duration
|
|
1133
|
+
duration,
|
|
1112
1134
|
pagePath: entry.path || '',
|
|
1113
1135
|
unit: 'ms',
|
|
1114
1136
|
});
|
|
1115
1137
|
}
|
|
1116
1138
|
// Route Switch: route
|
|
1117
1139
|
else if (entry.entryType === 'navigation' && entry.name === 'route') {
|
|
1140
|
+
const duration = typeof entry.duration === 'number'
|
|
1141
|
+
? entry.duration
|
|
1142
|
+
: typeof entry.startTime === 'number' && typeof entry.endTime === 'number'
|
|
1143
|
+
? entry.endTime - entry.startTime
|
|
1144
|
+
: 0;
|
|
1118
1145
|
report(options.reportType, {
|
|
1119
1146
|
metric: 'route',
|
|
1120
|
-
duration
|
|
1147
|
+
duration,
|
|
1121
1148
|
pagePath: entry.path || '',
|
|
1122
1149
|
unit: 'ms',
|
|
1123
1150
|
});
|
|
@@ -1461,7 +1488,7 @@ function installBehaviorMonitor(report, envType, options = {}) {
|
|
|
1461
1488
|
const tag = (el.tagName || '').toLowerCase();
|
|
1462
1489
|
const trackId = getAttr(el, clickTrackIdAttr);
|
|
1463
1490
|
// 过滤无效点击:白名单 tag + 没有 trackId
|
|
1464
|
-
if (clickWhiteList.includes(tag)
|
|
1491
|
+
if (clickWhiteList.includes(tag) || !trackId)
|
|
1465
1492
|
return;
|
|
1466
1493
|
void uvStatePromise.then(({ uvId, meta }) => {
|
|
1467
1494
|
if (destroyed)
|
|
@@ -1502,8 +1529,12 @@ function installBehaviorMonitor(report, envType, options = {}) {
|
|
|
1502
1529
|
g.Page = function patchedPage(conf) {
|
|
1503
1530
|
const originalOnShow = conf?.onShow;
|
|
1504
1531
|
conf.onShow = function (...args) {
|
|
1505
|
-
if (pvEnabled)
|
|
1506
|
-
|
|
1532
|
+
if (pvEnabled) {
|
|
1533
|
+
const pagePath = getPagePath();
|
|
1534
|
+
if (pagePath?.length > 0) {
|
|
1535
|
+
reportPv(pagePath);
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1507
1538
|
return typeof originalOnShow === 'function' ? originalOnShow.apply(this, args) : undefined;
|
|
1508
1539
|
};
|
|
1509
1540
|
// 点击:wrap 页面 methods(bindtap 等会调用到这里的 handler)
|
|
@@ -1857,6 +1888,7 @@ class ClsLoggerCore {
|
|
|
1857
1888
|
this.endpoint = 'ap-shanghai.cls.tencentcs.com';
|
|
1858
1889
|
this.retryTimes = 10;
|
|
1859
1890
|
this.source = '127.0.0.1';
|
|
1891
|
+
this.enabled = true;
|
|
1860
1892
|
this.projectId = '';
|
|
1861
1893
|
this.projectName = '';
|
|
1862
1894
|
this.appId = '';
|
|
@@ -1887,9 +1919,14 @@ class ClsLoggerCore {
|
|
|
1887
1919
|
* 子类可按需重写(默认检测 wx)
|
|
1888
1920
|
*/
|
|
1889
1921
|
detectEnvType() {
|
|
1890
|
-
const
|
|
1891
|
-
|
|
1922
|
+
const g = globalThis;
|
|
1923
|
+
// 微信、支付宝、字节跳动、UniApp 等小程序环境通常都有特定全局变量
|
|
1924
|
+
if ((g.wx && typeof g.wx.getSystemInfoSync === 'function') ||
|
|
1925
|
+
(g.my && typeof g.my.getSystemInfoSync === 'function') ||
|
|
1926
|
+
(g.tt && typeof g.tt.getSystemInfoSync === 'function') ||
|
|
1927
|
+
(g.uni && typeof g.uni.getSystemInfoSync === 'function')) {
|
|
1892
1928
|
return 'miniprogram';
|
|
1929
|
+
}
|
|
1893
1930
|
return 'browser';
|
|
1894
1931
|
}
|
|
1895
1932
|
init(options) {
|
|
@@ -1927,6 +1964,7 @@ class ClsLoggerCore {
|
|
|
1927
1964
|
this.appId = options.appId ?? this.appId;
|
|
1928
1965
|
this.appVersion = options.appVersion ?? this.appVersion;
|
|
1929
1966
|
this.envType = nextEnvType;
|
|
1967
|
+
this.enabled = options.enabled ?? true;
|
|
1930
1968
|
// 可选:外部注入 SDK(优先级:sdkLoader > sdk)
|
|
1931
1969
|
this.sdkLoaderOverride = options.sdkLoader ?? this.sdkLoaderOverride;
|
|
1932
1970
|
this.sdkOverride = options.sdk ?? this.sdkOverride;
|
|
@@ -1943,15 +1981,17 @@ class ClsLoggerCore {
|
|
|
1943
1981
|
void this.getInstance().catch(() => {
|
|
1944
1982
|
// ignore
|
|
1945
1983
|
});
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1984
|
+
if (this.enabled) {
|
|
1985
|
+
// 启动时尝试发送失败缓存
|
|
1986
|
+
this.flushFailed();
|
|
1987
|
+
// 初始化后立即启动请求监听
|
|
1988
|
+
this.startRequestMonitor(options.requestMonitor);
|
|
1989
|
+
// 初始化后立即启动错误监控/性能监控
|
|
1990
|
+
this.startErrorMonitor(options.errorMonitor);
|
|
1991
|
+
this.startPerformanceMonitor(options.performanceMonitor);
|
|
1992
|
+
// 初始化后立即启动行为埋点(PV/UV/点击)
|
|
1993
|
+
this.startBehaviorMonitor(options.behaviorMonitor);
|
|
1994
|
+
}
|
|
1955
1995
|
}
|
|
1956
1996
|
getBaseFields() {
|
|
1957
1997
|
let auto = undefined;
|
|
@@ -2076,6 +2116,8 @@ class ClsLoggerCore {
|
|
|
2076
2116
|
* - 最终会把 fields 展开成 CLS 的 content(key/value 都会转成 string)
|
|
2077
2117
|
*/
|
|
2078
2118
|
put(fields, options = {}) {
|
|
2119
|
+
if (!this.enabled)
|
|
2120
|
+
return;
|
|
2079
2121
|
if (!fields)
|
|
2080
2122
|
return;
|
|
2081
2123
|
if (!this.topicId) {
|
|
@@ -2134,6 +2176,8 @@ class ClsLoggerCore {
|
|
|
2134
2176
|
* - 埋点入参必须是一维(扁平)Object,非原始值会被 stringify
|
|
2135
2177
|
*/
|
|
2136
2178
|
enqueue(fields, options = {}) {
|
|
2179
|
+
if (!this.enabled)
|
|
2180
|
+
return;
|
|
2137
2181
|
if (!fields)
|
|
2138
2182
|
return;
|
|
2139
2183
|
const time = Date.now();
|
|
@@ -2172,6 +2216,8 @@ class ClsLoggerCore {
|
|
|
2172
2216
|
* 批量上报(每条 item.data 展开为 log content)
|
|
2173
2217
|
*/
|
|
2174
2218
|
putBatch(queue) {
|
|
2219
|
+
if (!this.enabled)
|
|
2220
|
+
return;
|
|
2175
2221
|
if (!queue || queue.length === 0)
|
|
2176
2222
|
return;
|
|
2177
2223
|
if (!this.topicId) {
|
|
@@ -2215,6 +2261,8 @@ class ClsLoggerCore {
|
|
|
2215
2261
|
* 参考《一、概述》:统一上报入口(内存队列 + 批量发送)
|
|
2216
2262
|
*/
|
|
2217
2263
|
report(log) {
|
|
2264
|
+
if (!this.enabled)
|
|
2265
|
+
return;
|
|
2218
2266
|
if (!log?.type)
|
|
2219
2267
|
return;
|
|
2220
2268
|
if (!this.topicId) {
|
|
@@ -2262,15 +2310,57 @@ class ClsLoggerCore {
|
|
|
2262
2310
|
return nowTs + this.batchIntervalMs;
|
|
2263
2311
|
}
|
|
2264
2312
|
info(message, data = {}) {
|
|
2265
|
-
|
|
2313
|
+
let msg = '';
|
|
2314
|
+
let extra = {};
|
|
2315
|
+
if (message instanceof Error) {
|
|
2316
|
+
msg = message.message;
|
|
2317
|
+
extra = {
|
|
2318
|
+
stack: message.stack,
|
|
2319
|
+
name: message.name,
|
|
2320
|
+
...data,
|
|
2321
|
+
};
|
|
2322
|
+
}
|
|
2323
|
+
else {
|
|
2324
|
+
msg = String(message);
|
|
2325
|
+
extra = data;
|
|
2326
|
+
}
|
|
2327
|
+
const payload = normalizeFlatFields({ message: msg, ...extra }, 'info');
|
|
2266
2328
|
this.report({ type: 'info', data: payload, timestamp: Date.now() });
|
|
2267
2329
|
}
|
|
2268
2330
|
warn(message, data = {}) {
|
|
2269
|
-
|
|
2331
|
+
let msg = '';
|
|
2332
|
+
let extra = {};
|
|
2333
|
+
if (message instanceof Error) {
|
|
2334
|
+
msg = message.message;
|
|
2335
|
+
extra = {
|
|
2336
|
+
stack: message.stack,
|
|
2337
|
+
name: message.name,
|
|
2338
|
+
...data,
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
else {
|
|
2342
|
+
msg = String(message);
|
|
2343
|
+
extra = data;
|
|
2344
|
+
}
|
|
2345
|
+
const payload = normalizeFlatFields({ message: msg, ...extra }, 'warn');
|
|
2270
2346
|
this.report({ type: 'warn', data: payload, timestamp: Date.now() });
|
|
2271
2347
|
}
|
|
2272
2348
|
error(message, data = {}) {
|
|
2273
|
-
|
|
2349
|
+
let msg = '';
|
|
2350
|
+
let extra = {};
|
|
2351
|
+
if (message instanceof Error) {
|
|
2352
|
+
msg = message.message;
|
|
2353
|
+
extra = {
|
|
2354
|
+
stack: message.stack,
|
|
2355
|
+
name: message.name,
|
|
2356
|
+
...data,
|
|
2357
|
+
};
|
|
2358
|
+
}
|
|
2359
|
+
else {
|
|
2360
|
+
msg = String(message);
|
|
2361
|
+
extra = data;
|
|
2362
|
+
}
|
|
2363
|
+
const payload = normalizeFlatFields({ message: msg, ...extra }, 'error');
|
|
2274
2364
|
this.report({ type: 'error', data: payload, timestamp: Date.now() });
|
|
2275
2365
|
}
|
|
2276
2366
|
track(trackType, data = {}) {
|
|
@@ -2377,6 +2467,8 @@ class ClsLoggerCore {
|
|
|
2377
2467
|
writeStringStorage(this.failedCacheKey, JSON.stringify(next));
|
|
2378
2468
|
}
|
|
2379
2469
|
flushFailed() {
|
|
2470
|
+
if (!this.enabled)
|
|
2471
|
+
return;
|
|
2380
2472
|
const raw = readStringStorage(this.failedCacheKey);
|
|
2381
2473
|
if (!raw)
|
|
2382
2474
|
return;
|