@be-link/cls-logger 1.0.1-beta.8 → 1.0.3

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/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,
@@ -1090,140 +1107,68 @@
1090
1107
  }
1091
1108
  }
1092
1109
  }
1093
- function wrapMiniProgramRouteApi(report, reportType, apiName, options) {
1094
- const wxAny = globalThis.wx;
1095
- if (!wxAny || typeof wxAny[apiName] !== 'function')
1096
- return;
1097
- const flagKey = `__beLinkClsLoggerMpRouteWrapped__${apiName}`;
1098
- if (wxAny[flagKey])
1099
- return;
1100
- wxAny[flagKey] = true;
1101
- const raw = wxAny[apiName].bind(wxAny);
1102
- wxAny[apiName] = (opts) => {
1103
- const start = Date.now();
1104
- const url = opts?.url ? String(opts.url) : '';
1105
- const wrapCb = (cb, success) => {
1106
- return (...args) => {
1107
- try {
1108
- if (sampleHit(options.sampleRate)) {
1109
- report(reportType, {
1110
- metric: 'route',
1111
- api: apiName,
1112
- url,
1113
- duration: Date.now() - start,
1114
- success: success ? 1 : 0,
1115
- error: success ? '' : truncate$1(stringifyLogValue(args?.[0]), options.maxTextLength),
1116
- unit: 'ms',
1117
- });
1118
- }
1119
- }
1120
- catch {
1121
- // ignore
1122
- }
1123
- if (typeof cb === 'function')
1124
- return cb(...args);
1125
- return undefined;
1126
- };
1127
- };
1128
- const next = { ...(opts ?? {}) };
1129
- next.success = wrapCb(next.success, true);
1130
- next.fail = wrapCb(next.fail, false);
1131
- return raw(next);
1132
- };
1133
- }
1134
- function installMiniProgramPageRenderMonitor(report, reportType, options) {
1135
- const g = globalThis;
1136
- if (typeof g.Page !== 'function')
1137
- return;
1138
- if (g.__beLinkClsLoggerPageWrapped__)
1139
- return;
1140
- g.__beLinkClsLoggerPageWrapped__ = true;
1141
- const rawPage = g.Page;
1142
- g.Page = (pageOptions) => {
1143
- const next = { ...(pageOptions ?? {}) };
1144
- const rawOnLoad = next.onLoad;
1145
- const rawOnReady = next.onReady;
1146
- next.onLoad = function (...args) {
1147
- try {
1148
- this.__beLinkClsLoggerPageLoadTs__ = Date.now();
1149
- }
1150
- catch {
1151
- // ignore
1152
- }
1153
- if (typeof rawOnLoad === 'function')
1154
- return rawOnLoad.apply(this, args);
1155
- return undefined;
1156
- };
1157
- next.onReady = function (...args) {
1158
- try {
1159
- const start = this.__beLinkClsLoggerPageLoadTs__;
1160
- if (typeof start === 'number' && sampleHit(options.sampleRate)) {
1161
- report(reportType, {
1162
- metric: 'page-render',
1163
- route: this?.route ? String(this.route) : '',
1164
- duration: Date.now() - start,
1165
- unit: 'ms',
1166
- });
1167
- }
1168
- }
1169
- catch {
1170
- // ignore
1171
- }
1172
- if (typeof rawOnReady === 'function')
1173
- return rawOnReady.apply(this, args);
1174
- return undefined;
1175
- };
1176
- return rawPage(next);
1177
- };
1178
- }
1179
1110
  function installMiniProgramPerformanceMonitor(report, options) {
1180
1111
  const g = globalThis;
1112
+ const ctx = g.wx || g.Taro;
1113
+ if (!ctx || typeof ctx.getPerformance !== 'function')
1114
+ return;
1181
1115
  if (g.__beLinkClsLoggerMpPerfInstalled__)
1182
1116
  return;
1183
1117
  g.__beLinkClsLoggerMpPerfInstalled__ = true;
1184
- // 路由切换耗时(用 API 回调近似)
1185
- for (const apiName of ['navigateTo', 'redirectTo', 'switchTab', 'reLaunch']) {
1186
- try {
1187
- wrapMiniProgramRouteApi(report, options.reportType, apiName, options);
1188
- }
1189
- catch {
1190
- // ignore
1191
- }
1192
- }
1193
- // 页面渲染耗时(onLoad -> onReady)
1194
1118
  try {
1195
- installMiniProgramPageRenderMonitor(report, options.reportType, options);
1196
- }
1197
- catch {
1198
- // ignore
1199
- }
1200
- // wx.getPerformance()(若可用,尝试读取已有 entries)
1201
- try {
1202
- const wxAny = globalThis.wx;
1203
- if (wxAny && typeof wxAny.getPerformance === 'function') {
1204
- const perf = wxAny.getPerformance();
1205
- if (perf && isPlainObject(perf)) {
1206
- // 不同基础库实现差异较大:尽量容错
1207
- setTimeout(() => {
1208
- try {
1209
- if (!sampleHit(options.sampleRate))
1210
- return;
1211
- const entries = typeof perf.getEntries === 'function'
1212
- ? perf.getEntries()
1213
- : typeof perf.getEntriesByType === 'function'
1214
- ? perf.getEntriesByType('navigation')
1215
- : [];
1119
+ const perf = ctx.getPerformance();
1120
+ if (!perf || typeof perf.createObserver !== 'function')
1121
+ return;
1122
+ const observer = perf.createObserver((entryList) => {
1123
+ try {
1124
+ const entries = entryList.getEntries();
1125
+ for (const entry of entries) {
1126
+ if (!sampleHit(options.sampleRate))
1127
+ continue;
1128
+ // Page Render: firstRender
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;
1216
1135
  report(options.reportType, {
1217
- metric: 'mp-performance',
1218
- entries: truncate$1(stringifyLogValue(entries), options.maxTextLength),
1136
+ metric: 'page-render',
1137
+ duration,
1138
+ pagePath: entry.path || '',
1139
+ unit: 'ms',
1219
1140
  });
1220
1141
  }
1221
- catch {
1222
- // ignore
1142
+ // Route Switch: route
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;
1149
+ report(options.reportType, {
1150
+ metric: 'route',
1151
+ duration,
1152
+ pagePath: entry.path || '',
1153
+ unit: 'ms',
1154
+ });
1223
1155
  }
1224
- }, 0);
1156
+ // App Launch: appLaunch (Cold)
1157
+ else if (entry.entryType === 'navigation' && entry.name === 'appLaunch') {
1158
+ report(options.reportType, {
1159
+ metric: 'app-launch',
1160
+ duration: entry.duration,
1161
+ launchType: 'cold',
1162
+ unit: 'ms',
1163
+ });
1164
+ }
1165
+ }
1225
1166
  }
1226
- }
1167
+ catch {
1168
+ // ignore
1169
+ }
1170
+ });
1171
+ observer.observe({ entryTypes: ['navigation', 'render'] });
1227
1172
  }
1228
1173
  catch {
1229
1174
  // ignore
@@ -1547,7 +1492,7 @@
1547
1492
  const tag = (el.tagName || '').toLowerCase();
1548
1493
  const trackId = getAttr(el, clickTrackIdAttr);
1549
1494
  // 过滤无效点击:白名单 tag + 没有 trackId
1550
- if (clickWhiteList.includes(tag) && !trackId)
1495
+ if (clickWhiteList.includes(tag) || !trackId)
1551
1496
  return;
1552
1497
  void uvStatePromise.then(({ uvId, meta }) => {
1553
1498
  if (destroyed)
@@ -1588,8 +1533,12 @@
1588
1533
  g.Page = function patchedPage(conf) {
1589
1534
  const originalOnShow = conf?.onShow;
1590
1535
  conf.onShow = function (...args) {
1591
- if (pvEnabled)
1592
- reportPv(getPagePath());
1536
+ if (pvEnabled) {
1537
+ const pagePath = getPagePath();
1538
+ if (pagePath?.length > 0) {
1539
+ reportPv(pagePath);
1540
+ }
1541
+ }
1593
1542
  return typeof originalOnShow === 'function' ? originalOnShow.apply(this, args) : undefined;
1594
1543
  };
1595
1544
  // 点击:wrap 页面 methods(bindtap 等会调用到这里的 handler)
@@ -1973,9 +1922,14 @@
1973
1922
  * 子类可按需重写(默认检测 wx)
1974
1923
  */
1975
1924
  detectEnvType() {
1976
- const wxAny = globalThis.wx;
1977
- if (wxAny && typeof wxAny.getSystemInfoSync === 'function')
1925
+ const g = globalThis;
1926
+ // 微信、支付宝、字节跳动、UniApp 等小程序环境通常都有特定全局变量
1927
+ if ((g.wx && typeof g.wx.getSystemInfoSync === 'function') ||
1928
+ (g.my && typeof g.my.getSystemInfoSync === 'function') ||
1929
+ (g.tt && typeof g.tt.getSystemInfoSync === 'function') ||
1930
+ (g.uni && typeof g.uni.getSystemInfoSync === 'function')) {
1978
1931
  return 'miniprogram';
1932
+ }
1979
1933
  return 'browser';
1980
1934
  }
1981
1935
  init(options) {
@@ -2348,15 +2302,57 @@
2348
2302
  return nowTs + this.batchIntervalMs;
2349
2303
  }
2350
2304
  info(message, data = {}) {
2351
- const payload = normalizeFlatFields({ message, ...data }, 'info');
2305
+ let msg = '';
2306
+ let extra = {};
2307
+ if (message instanceof Error) {
2308
+ msg = message.message;
2309
+ extra = {
2310
+ stack: message.stack,
2311
+ name: message.name,
2312
+ ...data,
2313
+ };
2314
+ }
2315
+ else {
2316
+ msg = String(message);
2317
+ extra = data;
2318
+ }
2319
+ const payload = normalizeFlatFields({ message: msg, ...extra }, 'info');
2352
2320
  this.report({ type: 'info', data: payload, timestamp: Date.now() });
2353
2321
  }
2354
2322
  warn(message, data = {}) {
2355
- const payload = normalizeFlatFields({ message, ...data }, 'warn');
2323
+ let msg = '';
2324
+ let extra = {};
2325
+ if (message instanceof Error) {
2326
+ msg = message.message;
2327
+ extra = {
2328
+ stack: message.stack,
2329
+ name: message.name,
2330
+ ...data,
2331
+ };
2332
+ }
2333
+ else {
2334
+ msg = String(message);
2335
+ extra = data;
2336
+ }
2337
+ const payload = normalizeFlatFields({ message: msg, ...extra }, 'warn');
2356
2338
  this.report({ type: 'warn', data: payload, timestamp: Date.now() });
2357
2339
  }
2358
2340
  error(message, data = {}) {
2359
- const payload = normalizeFlatFields({ message, ...data }, 'error');
2341
+ let msg = '';
2342
+ let extra = {};
2343
+ if (message instanceof Error) {
2344
+ msg = message.message;
2345
+ extra = {
2346
+ stack: message.stack,
2347
+ name: message.name,
2348
+ ...data,
2349
+ };
2350
+ }
2351
+ else {
2352
+ msg = String(message);
2353
+ extra = data;
2354
+ }
2355
+ const payload = normalizeFlatFields({ message: msg, ...extra }, 'error');
2360
2356
  this.report({ type: 'error', data: payload, timestamp: Date.now() });
2361
2357
  }
2362
2358
  track(trackType, data = {}) {
@@ -2578,38 +2574,78 @@
2578
2574
  }
2579
2575
  }
2580
2576
  const isMini = this.envType === 'miniprogram';
2581
- // 静态字面量,方便打包器识别(但在此兼容入口里,仍然可能被一起分析)
2582
- const WEB_SDK = 'tencentcloud-cls-sdk-js-web';
2583
- const MINI_SDK = 'tencentcloud-cls-sdk-js-mini';
2584
- // UMD(浏览器脚本)优先读全局变量
2585
- if (!isMini) {
2577
+ // 3) 尝试 require / 全局变量
2578
+ // Mini Program: 尝试直接 require
2579
+ if (isMini) {
2580
+ // 显式使用字面量 require,帮助打包工具识别依赖(尤其是 CJS 构建模式下)
2581
+ try {
2582
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
2583
+ const req = typeof require === 'function' ? require('tencentcloud-cls-sdk-js-mini') : null;
2584
+ const reqSdk = normalizeSdk(req);
2585
+ if (reqSdk) {
2586
+ this.sdk = reqSdk;
2587
+ return reqSdk;
2588
+ }
2589
+ }
2590
+ catch {
2591
+ // ignore
2592
+ }
2593
+ // 尝试使用 tryRequire(作为补充)
2594
+ const reqMod = tryRequire('tencentcloud-cls-sdk-js-mini');
2595
+ const reqSdk = normalizeSdk(reqMod);
2596
+ if (reqSdk) {
2597
+ this.sdk = reqSdk;
2598
+ return reqSdk;
2599
+ }
2600
+ }
2601
+ else {
2602
+ // Web: 优先读全局变量 (UMD)
2586
2603
  const g = readGlobal('tencentcloudClsSdkJsWeb');
2587
2604
  const sdk = normalizeSdk(g);
2588
2605
  if (sdk) {
2589
2606
  this.sdk = sdk;
2590
2607
  return sdk;
2591
2608
  }
2609
+ // Web: 尝试 require
2610
+ const reqMod = tryRequire('tencentcloud-cls-sdk-js-web');
2611
+ const reqSdk = normalizeSdk(reqMod);
2612
+ if (reqSdk) {
2613
+ this.sdk = reqSdk;
2614
+ return reqSdk;
2615
+ }
2616
+ }
2617
+ // 4) 动态 import
2618
+ // 使用字符串字面量,确保 Bundler 能正确识别并进行 Code Splitting
2619
+ if (isMini) {
2620
+ this.sdkPromise = import('tencentcloud-cls-sdk-js-mini')
2621
+ .then((m) => {
2622
+ const sdk = normalizeSdk(m);
2623
+ if (!sdk)
2624
+ throw new Error(`ClsLogger.loadSdk: invalid sdk module for mini`);
2625
+ this.sdk = sdk;
2626
+ return sdk;
2627
+ })
2628
+ .catch((err) => {
2629
+ this.sdkPromise = null;
2630
+ console.error('[ClsLogger] Failed to load mini sdk:', err);
2631
+ throw err;
2632
+ });
2633
+ }
2634
+ else {
2635
+ this.sdkPromise = import('tencentcloud-cls-sdk-js-web')
2636
+ .then((m) => {
2637
+ const sdk = normalizeSdk(m);
2638
+ if (!sdk)
2639
+ throw new Error(`ClsLogger.loadSdk: invalid sdk module for web`);
2640
+ this.sdk = sdk;
2641
+ return sdk;
2642
+ })
2643
+ .catch((err) => {
2644
+ this.sdkPromise = null;
2645
+ console.error('[ClsLogger] Failed to load web sdk:', err);
2646
+ throw err;
2647
+ });
2592
2648
  }
2593
- // 尽量同步 require
2594
- const reqMod = tryRequire(isMini ? MINI_SDK : WEB_SDK);
2595
- const reqSdk = normalizeSdk(reqMod);
2596
- if (reqSdk) {
2597
- this.sdk = reqSdk;
2598
- return reqSdk;
2599
- }
2600
- // 动态 import
2601
- this.sdkPromise = (isMini ? import(MINI_SDK) : import(WEB_SDK))
2602
- .then((m) => {
2603
- const sdk = normalizeSdk(m);
2604
- if (!sdk)
2605
- throw new Error(`ClsLogger.loadSdk: invalid sdk module for ${isMini ? MINI_SDK : WEB_SDK}`);
2606
- this.sdk = sdk;
2607
- return sdk;
2608
- })
2609
- .catch((err) => {
2610
- this.sdkPromise = null;
2611
- throw err;
2612
- });
2613
2649
  return this.sdkPromise;
2614
2650
  }
2615
2651
  }