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