@be-link/cls-logger 1.0.1-beta.3 → 1.0.1-beta.5
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/ClsLogger.d.ts +14 -2
- package/dist/ClsLogger.d.ts.map +1 -1
- package/dist/errorMonitor.d.ts.map +1 -1
- package/dist/index.esm.js +217 -32
- package/dist/index.js +217 -32
- package/dist/index.umd.js +221 -34
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
package/dist/ClsLogger.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { AsyncClient } from 'tencentcloud-cls-sdk-js-web';
|
|
2
1
|
import type { ClsLoggerInitOptions, FlatFields, PutOptions, QueueItem, ReportLog } from './types';
|
|
3
2
|
export declare class ClsLogger {
|
|
3
|
+
private sdk;
|
|
4
|
+
private sdkPromise;
|
|
4
5
|
private client;
|
|
6
|
+
private clientPromise;
|
|
5
7
|
private topicId;
|
|
6
8
|
private endpoint;
|
|
7
9
|
private retryTimes;
|
|
@@ -42,7 +44,15 @@ export declare class ClsLogger {
|
|
|
42
44
|
* - 如需重启:可再次调用 init(或自行调用 init 后的默认启动逻辑)
|
|
43
45
|
*/
|
|
44
46
|
stopBehaviorMonitor(): void;
|
|
45
|
-
|
|
47
|
+
/**
|
|
48
|
+
* 获取 CLS client(按环境懒加载 SDK)
|
|
49
|
+
* - browser: 优先走 UMD 全局变量 `tencentcloudClsSdkJsWeb`
|
|
50
|
+
* - miniprogram: 优先走 require(webpack/taro 可解析),否则 fallback import()
|
|
51
|
+
*/
|
|
52
|
+
getInstance(): Promise<{
|
|
53
|
+
PutLogs: (request: unknown) => Promise<unknown> | unknown;
|
|
54
|
+
}>;
|
|
55
|
+
private loadSdk;
|
|
46
56
|
private detectEnvType;
|
|
47
57
|
/**
|
|
48
58
|
* 直接上报:埋点入参必须是一维(扁平)Object
|
|
@@ -50,6 +60,7 @@ export declare class ClsLogger {
|
|
|
50
60
|
* - 最终会把 fields 展开成 CLS 的 content(key/value 都会转成 string)
|
|
51
61
|
*/
|
|
52
62
|
put(fields: FlatFields, options?: PutOptions): void;
|
|
63
|
+
private putAsync;
|
|
53
64
|
/**
|
|
54
65
|
* 直接上报:把 data 序列化后放入指定 key(默认 “日志内容”)
|
|
55
66
|
*/
|
|
@@ -67,6 +78,7 @@ export declare class ClsLogger {
|
|
|
67
78
|
* 批量上报(每条 item.data 展开为 log content)
|
|
68
79
|
*/
|
|
69
80
|
putBatch(queue: QueueItem[]): void;
|
|
81
|
+
private putBatchAsync;
|
|
70
82
|
/**
|
|
71
83
|
* 参考《一、概述》:统一上报入口(内存队列 + 批量发送)
|
|
72
84
|
*/
|
package/dist/ClsLogger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClsLogger.d.ts","sourceRoot":"","sources":["../src/ClsLogger.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ClsLogger.d.ts","sourceRoot":"","sources":["../src/ClsLogger.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorMonitor.d.ts","sourceRoot":"","sources":["../src/errorMonitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG/D,KAAK,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"errorMonitor.d.ts","sourceRoot":"","sources":["../src/errorMonitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG/D,KAAK,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;AA4QzD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,GAAE,OAAO,GAAG,mBAAmB,GAAG,SAAc,GAAG,IAAI,CAqBhH"}
|
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { AsyncClient, LogGroup, Log, PutLogsRequest } from 'tencentcloud-cls-sdk-js-web';
|
|
2
|
-
|
|
3
1
|
function isPlainObject(value) {
|
|
4
2
|
return Object.prototype.toString.call(value) === '[object Object]';
|
|
5
3
|
}
|
|
@@ -536,6 +534,8 @@ function installRequestMonitor(report, opts = {}) {
|
|
|
536
534
|
}
|
|
537
535
|
|
|
538
536
|
const DEFAULT_MAX_TEXT = 4000;
|
|
537
|
+
const DEFAULT_DEDUPE_WINDOW_MS = 3000;
|
|
538
|
+
const DEFAULT_DEDUPE_MAX_KEYS = 200;
|
|
539
539
|
function truncate$2(s, maxLen) {
|
|
540
540
|
if (!s)
|
|
541
541
|
return s;
|
|
@@ -569,6 +569,54 @@ function normalizeErrorLike(err, maxTextLength) {
|
|
|
569
569
|
const message = truncate$2(stringifyLogValue(err), maxTextLength);
|
|
570
570
|
return { message, name: '', stack: '' };
|
|
571
571
|
}
|
|
572
|
+
function createDedupeGuard(options) {
|
|
573
|
+
const cache = new Map(); // key -> lastReportAt
|
|
574
|
+
const maxKeys = Math.max(0, options.dedupeMaxKeys);
|
|
575
|
+
const windowMs = Math.max(0, options.dedupeWindowMs);
|
|
576
|
+
function touch(key, now) {
|
|
577
|
+
// refresh insertion order
|
|
578
|
+
if (cache.has(key))
|
|
579
|
+
cache.delete(key);
|
|
580
|
+
cache.set(key, now);
|
|
581
|
+
if (maxKeys > 0) {
|
|
582
|
+
while (cache.size > maxKeys) {
|
|
583
|
+
const first = cache.keys().next().value;
|
|
584
|
+
if (!first)
|
|
585
|
+
break;
|
|
586
|
+
cache.delete(first);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return (key) => {
|
|
591
|
+
if (!key)
|
|
592
|
+
return true;
|
|
593
|
+
if (windowMs <= 0 || maxKeys === 0)
|
|
594
|
+
return true;
|
|
595
|
+
const now = Date.now();
|
|
596
|
+
const last = cache.get(key);
|
|
597
|
+
if (typeof last === 'number' && now - last < windowMs)
|
|
598
|
+
return false;
|
|
599
|
+
touch(key, now);
|
|
600
|
+
return true;
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
function buildErrorKey(type, payload) {
|
|
604
|
+
// 使用最核心、最稳定的字段构造签名,避免把瞬态字段(如 time)带入导致失效
|
|
605
|
+
const parts = [
|
|
606
|
+
type,
|
|
607
|
+
String(payload.source ?? ''),
|
|
608
|
+
String(payload.pagePath ?? ''),
|
|
609
|
+
String(payload.message ?? ''),
|
|
610
|
+
String(payload.errorName ?? ''),
|
|
611
|
+
String(payload.stack ?? ''),
|
|
612
|
+
String(payload.filename ?? ''),
|
|
613
|
+
String(payload.lineno ?? ''),
|
|
614
|
+
String(payload.colno ?? ''),
|
|
615
|
+
String(payload.tagName ?? ''),
|
|
616
|
+
String(payload.resourceUrl ?? ''),
|
|
617
|
+
];
|
|
618
|
+
return parts.join('|');
|
|
619
|
+
}
|
|
572
620
|
function installBrowserErrorMonitor(report, options) {
|
|
573
621
|
if (typeof window === 'undefined')
|
|
574
622
|
return;
|
|
@@ -576,6 +624,7 @@ function installBrowserErrorMonitor(report, options) {
|
|
|
576
624
|
if (w.__beLinkClsLoggerErrorInstalled__)
|
|
577
625
|
return;
|
|
578
626
|
w.__beLinkClsLoggerErrorInstalled__ = true;
|
|
627
|
+
const shouldReport = createDedupeGuard(options);
|
|
579
628
|
window.addEventListener('error', (event) => {
|
|
580
629
|
try {
|
|
581
630
|
if (!sampleHit$1(options.sampleRate))
|
|
@@ -598,6 +647,8 @@ function installBrowserErrorMonitor(report, options) {
|
|
|
598
647
|
if (e.stack)
|
|
599
648
|
payload.stack = e.stack;
|
|
600
649
|
}
|
|
650
|
+
if (!shouldReport(buildErrorKey(options.reportType, payload)))
|
|
651
|
+
return;
|
|
601
652
|
report(options.reportType, payload);
|
|
602
653
|
return;
|
|
603
654
|
}
|
|
@@ -609,6 +660,8 @@ function installBrowserErrorMonitor(report, options) {
|
|
|
609
660
|
payload.source = 'resource.error';
|
|
610
661
|
payload.tagName = tagName;
|
|
611
662
|
payload.resourceUrl = truncate$2(url, 2000);
|
|
663
|
+
if (!shouldReport(buildErrorKey(options.reportType, payload)))
|
|
664
|
+
return;
|
|
612
665
|
report(options.reportType, payload);
|
|
613
666
|
}
|
|
614
667
|
}
|
|
@@ -629,6 +682,8 @@ function installBrowserErrorMonitor(report, options) {
|
|
|
629
682
|
errorName: e.name,
|
|
630
683
|
stack: e.stack,
|
|
631
684
|
};
|
|
685
|
+
if (!shouldReport(buildErrorKey(options.reportType, payload)))
|
|
686
|
+
return;
|
|
632
687
|
report(options.reportType, payload);
|
|
633
688
|
}
|
|
634
689
|
catch {
|
|
@@ -641,6 +696,7 @@ function installMiniProgramErrorMonitor(report, options) {
|
|
|
641
696
|
if (g.__beLinkClsLoggerMpErrorInstalled__)
|
|
642
697
|
return;
|
|
643
698
|
g.__beLinkClsLoggerMpErrorInstalled__ = true;
|
|
699
|
+
const shouldReport = createDedupeGuard(options);
|
|
644
700
|
const wxAny = globalThis.wx;
|
|
645
701
|
// wx.* 事件(兼容在 App 已经创建后的场景)
|
|
646
702
|
try {
|
|
@@ -649,10 +705,13 @@ function installMiniProgramErrorMonitor(report, options) {
|
|
|
649
705
|
try {
|
|
650
706
|
if (!sampleHit$1(options.sampleRate))
|
|
651
707
|
return;
|
|
652
|
-
|
|
708
|
+
const payload = {
|
|
653
709
|
source: 'wx.onError',
|
|
654
710
|
message: truncate$2(String(msg ?? ''), options.maxTextLength),
|
|
655
|
-
}
|
|
711
|
+
};
|
|
712
|
+
if (!shouldReport(buildErrorKey(options.reportType, payload)))
|
|
713
|
+
return;
|
|
714
|
+
report(options.reportType, payload);
|
|
656
715
|
}
|
|
657
716
|
catch {
|
|
658
717
|
// ignore
|
|
@@ -670,12 +729,15 @@ function installMiniProgramErrorMonitor(report, options) {
|
|
|
670
729
|
if (!sampleHit$1(options.sampleRate))
|
|
671
730
|
return;
|
|
672
731
|
const e = normalizeErrorLike(res?.reason, options.maxTextLength);
|
|
673
|
-
|
|
732
|
+
const payload = {
|
|
674
733
|
source: 'wx.onUnhandledRejection',
|
|
675
734
|
message: e.message,
|
|
676
735
|
errorName: e.name,
|
|
677
736
|
stack: e.stack,
|
|
678
|
-
}
|
|
737
|
+
};
|
|
738
|
+
if (!shouldReport(buildErrorKey(options.reportType, payload)))
|
|
739
|
+
return;
|
|
740
|
+
report(options.reportType, payload);
|
|
679
741
|
}
|
|
680
742
|
catch {
|
|
681
743
|
// ignore
|
|
@@ -697,10 +759,12 @@ function installMiniProgramErrorMonitor(report, options) {
|
|
|
697
759
|
next.onError = function (...args) {
|
|
698
760
|
try {
|
|
699
761
|
if (sampleHit$1(options.sampleRate)) {
|
|
700
|
-
|
|
762
|
+
const payload = {
|
|
701
763
|
source: 'App.onError',
|
|
702
764
|
message: truncate$2(String(args?.[0] ?? ''), options.maxTextLength),
|
|
703
|
-
}
|
|
765
|
+
};
|
|
766
|
+
if (shouldReport(buildErrorKey(options.reportType, payload)))
|
|
767
|
+
report(options.reportType, payload);
|
|
704
768
|
}
|
|
705
769
|
}
|
|
706
770
|
catch {
|
|
@@ -716,12 +780,14 @@ function installMiniProgramErrorMonitor(report, options) {
|
|
|
716
780
|
if (sampleHit$1(options.sampleRate)) {
|
|
717
781
|
const reason = args?.[0]?.reason ?? args?.[0];
|
|
718
782
|
const e = normalizeErrorLike(reason, options.maxTextLength);
|
|
719
|
-
|
|
783
|
+
const payload = {
|
|
720
784
|
source: 'App.onUnhandledRejection',
|
|
721
785
|
message: e.message,
|
|
722
786
|
errorName: e.name,
|
|
723
787
|
stack: e.stack,
|
|
724
|
-
}
|
|
788
|
+
};
|
|
789
|
+
if (shouldReport(buildErrorKey(options.reportType, payload)))
|
|
790
|
+
report(options.reportType, payload);
|
|
725
791
|
}
|
|
726
792
|
}
|
|
727
793
|
catch {
|
|
@@ -750,6 +816,8 @@ function installErrorMonitor(report, opts = {}) {
|
|
|
750
816
|
sampleRate: raw.sampleRate ?? 1,
|
|
751
817
|
captureResourceError: raw.captureResourceError ?? true,
|
|
752
818
|
maxTextLength: raw.maxTextLength ?? DEFAULT_MAX_TEXT,
|
|
819
|
+
dedupeWindowMs: raw.dedupeWindowMs ?? DEFAULT_DEDUPE_WINDOW_MS,
|
|
820
|
+
dedupeMaxKeys: raw.dedupeMaxKeys ?? DEFAULT_DEDUPE_MAX_KEYS,
|
|
753
821
|
};
|
|
754
822
|
if (isMiniProgramEnv()) {
|
|
755
823
|
installMiniProgramErrorMonitor(report, options);
|
|
@@ -1826,6 +1894,27 @@ function createAutoDeviceInfoBaseFields(envType, opts) {
|
|
|
1826
1894
|
};
|
|
1827
1895
|
}
|
|
1828
1896
|
|
|
1897
|
+
function readGlobal(key) {
|
|
1898
|
+
try {
|
|
1899
|
+
const g = globalThis;
|
|
1900
|
+
return g[key] ?? null;
|
|
1901
|
+
}
|
|
1902
|
+
catch {
|
|
1903
|
+
return null;
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
function tryRequire(moduleName) {
|
|
1907
|
+
try {
|
|
1908
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
1909
|
+
const req = (typeof require === 'function' ? require : null);
|
|
1910
|
+
if (!req)
|
|
1911
|
+
return null;
|
|
1912
|
+
return req(moduleName);
|
|
1913
|
+
}
|
|
1914
|
+
catch {
|
|
1915
|
+
return null;
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1829
1918
|
function enterClsSendingGuard() {
|
|
1830
1919
|
const g = globalThis;
|
|
1831
1920
|
const next = (g.__beLinkClsLoggerSendingCount__ ?? 0) + 1;
|
|
@@ -1837,7 +1926,10 @@ function enterClsSendingGuard() {
|
|
|
1837
1926
|
}
|
|
1838
1927
|
class ClsLogger {
|
|
1839
1928
|
constructor() {
|
|
1929
|
+
this.sdk = null;
|
|
1930
|
+
this.sdkPromise = null;
|
|
1840
1931
|
this.client = null;
|
|
1932
|
+
this.clientPromise = null;
|
|
1841
1933
|
this.topicId = null;
|
|
1842
1934
|
this.endpoint = 'ap-shanghai.cls.tencentcs.com';
|
|
1843
1935
|
this.retryTimes = 10;
|
|
@@ -1879,6 +1971,19 @@ class ClsLogger {
|
|
|
1879
1971
|
console.warn('ClsLogger.init 没有传 topicID/topic_id');
|
|
1880
1972
|
return;
|
|
1881
1973
|
}
|
|
1974
|
+
const nextEnvType = options.envType ?? this.detectEnvType();
|
|
1975
|
+
// envType/endpoint/retryTimes 变化时:重置 client(以及可能的 sdk)
|
|
1976
|
+
const envChanged = nextEnvType !== this.envType;
|
|
1977
|
+
const endpointChanged = endpoint !== this.endpoint;
|
|
1978
|
+
const retryChanged = retryTimes !== this.retryTimes;
|
|
1979
|
+
if (envChanged || endpointChanged || retryChanged) {
|
|
1980
|
+
this.client = null;
|
|
1981
|
+
this.clientPromise = null;
|
|
1982
|
+
}
|
|
1983
|
+
if (envChanged) {
|
|
1984
|
+
this.sdk = null;
|
|
1985
|
+
this.sdkPromise = null;
|
|
1986
|
+
}
|
|
1882
1987
|
this.topicId = topicId;
|
|
1883
1988
|
this.endpoint = endpoint;
|
|
1884
1989
|
this.retryTimes = retryTimes;
|
|
@@ -1889,7 +1994,7 @@ class ClsLogger {
|
|
|
1889
1994
|
this.projectName = options.projectName ?? this.projectName;
|
|
1890
1995
|
this.appId = options.appId ?? this.appId;
|
|
1891
1996
|
this.appVersion = options.appVersion ?? this.appVersion;
|
|
1892
|
-
this.envType =
|
|
1997
|
+
this.envType = nextEnvType;
|
|
1893
1998
|
this.userGenerateBaseFields = options.generateBaseFields ?? this.userGenerateBaseFields;
|
|
1894
1999
|
this.autoGenerateBaseFields = createAutoDeviceInfoBaseFields(this.envType, options.deviceInfo);
|
|
1895
2000
|
this.storageKey = options.storageKey ?? this.storageKey;
|
|
@@ -1899,8 +2004,10 @@ class ClsLogger {
|
|
|
1899
2004
|
this.startupDelayMs = options.batch?.startupDelayMs ?? this.startupDelayMs;
|
|
1900
2005
|
this.failedCacheKey = options.failedCacheKey ?? this.failedCacheKey;
|
|
1901
2006
|
this.failedCacheMax = options.failedCacheMax ?? this.failedCacheMax;
|
|
1902
|
-
//
|
|
1903
|
-
this.getInstance()
|
|
2007
|
+
// 预热(避免首条日志触发 import/初始化开销)
|
|
2008
|
+
void this.getInstance().catch(() => {
|
|
2009
|
+
// ignore
|
|
2010
|
+
});
|
|
1904
2011
|
// 启动时尝试发送失败缓存
|
|
1905
2012
|
this.flushFailed();
|
|
1906
2013
|
// 初始化后立即启动请求监听
|
|
@@ -2004,14 +2111,70 @@ class ClsLogger {
|
|
|
2004
2111
|
this.behaviorMonitorCleanup = null;
|
|
2005
2112
|
this.behaviorMonitorStarted = false;
|
|
2006
2113
|
}
|
|
2007
|
-
|
|
2114
|
+
/**
|
|
2115
|
+
* 获取 CLS client(按环境懒加载 SDK)
|
|
2116
|
+
* - browser: 优先走 UMD 全局变量 `tencentcloudClsSdkJsWeb`
|
|
2117
|
+
* - miniprogram: 优先走 require(webpack/taro 可解析),否则 fallback import()
|
|
2118
|
+
*/
|
|
2119
|
+
async getInstance() {
|
|
2008
2120
|
if (this.client)
|
|
2009
2121
|
return this.client;
|
|
2010
|
-
this.
|
|
2011
|
-
|
|
2012
|
-
|
|
2122
|
+
if (this.clientPromise)
|
|
2123
|
+
return this.clientPromise;
|
|
2124
|
+
this.clientPromise = this.loadSdk()
|
|
2125
|
+
.then(({ AsyncClient }) => {
|
|
2126
|
+
const client = new AsyncClient({
|
|
2127
|
+
endpoint: this.endpoint,
|
|
2128
|
+
retry_times: this.retryTimes,
|
|
2129
|
+
});
|
|
2130
|
+
this.client = client;
|
|
2131
|
+
return client;
|
|
2132
|
+
})
|
|
2133
|
+
.catch((err) => {
|
|
2134
|
+
// 失败后允许下次重试
|
|
2135
|
+
this.clientPromise = null;
|
|
2136
|
+
throw err;
|
|
2137
|
+
});
|
|
2138
|
+
return this.clientPromise;
|
|
2139
|
+
}
|
|
2140
|
+
async loadSdk() {
|
|
2141
|
+
if (this.sdk)
|
|
2142
|
+
return this.sdk;
|
|
2143
|
+
if (this.sdkPromise)
|
|
2144
|
+
return this.sdkPromise;
|
|
2145
|
+
const isMini = this.envType === 'miniprogram';
|
|
2146
|
+
const moduleName = isMini ? 'tencentcloud-cls-sdk-js-mini' : 'tencentcloud-cls-sdk-js-web';
|
|
2147
|
+
// UMD(浏览器脚本)优先读全局变量
|
|
2148
|
+
if (!isMini) {
|
|
2149
|
+
const g = readGlobal('tencentcloudClsSdkJsWeb');
|
|
2150
|
+
if (g?.AsyncClient && g?.Log && g?.LogGroup && g?.PutLogsRequest) {
|
|
2151
|
+
this.sdk = g;
|
|
2152
|
+
return this.sdk;
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
// 尽量同步 require(小程序/webpack 里最稳),失败再走 import()
|
|
2156
|
+
const reqMod = tryRequire(moduleName);
|
|
2157
|
+
if (reqMod?.AsyncClient && reqMod?.Log && reqMod?.LogGroup && reqMod?.PutLogsRequest) {
|
|
2158
|
+
this.sdk = reqMod;
|
|
2159
|
+
return this.sdk;
|
|
2160
|
+
}
|
|
2161
|
+
this.sdkPromise = import(moduleName)
|
|
2162
|
+
.then((m) => {
|
|
2163
|
+
const mod = (m?.default && m.default.AsyncClient ? m.default : m);
|
|
2164
|
+
const sdk = {
|
|
2165
|
+
AsyncClient: mod.AsyncClient,
|
|
2166
|
+
Log: mod.Log,
|
|
2167
|
+
LogGroup: mod.LogGroup,
|
|
2168
|
+
PutLogsRequest: mod.PutLogsRequest,
|
|
2169
|
+
};
|
|
2170
|
+
this.sdk = sdk;
|
|
2171
|
+
return sdk;
|
|
2172
|
+
})
|
|
2173
|
+
.catch((err) => {
|
|
2174
|
+
this.sdkPromise = null;
|
|
2175
|
+
throw err;
|
|
2013
2176
|
});
|
|
2014
|
-
return this.
|
|
2177
|
+
return this.sdkPromise;
|
|
2015
2178
|
}
|
|
2016
2179
|
detectEnvType() {
|
|
2017
2180
|
const wxAny = globalThis.wx;
|
|
@@ -2043,22 +2206,33 @@ class ClsLogger {
|
|
|
2043
2206
|
appVersion: this.appVersion || undefined,
|
|
2044
2207
|
...normalizedFields,
|
|
2045
2208
|
});
|
|
2046
|
-
|
|
2047
|
-
|
|
2209
|
+
// 同步 API:内部异步发送,避免把网络异常冒泡到业务(尤其小程序)
|
|
2210
|
+
void this.putAsync(finalFields).catch(() => {
|
|
2211
|
+
// ignore
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
async putAsync(finalFields) {
|
|
2215
|
+
if (!this.topicId)
|
|
2216
|
+
return;
|
|
2217
|
+
const sdk = await this.loadSdk();
|
|
2218
|
+
const client = await this.getInstance();
|
|
2219
|
+
const logGroup = new sdk.LogGroup('127.0.0.1');
|
|
2048
2220
|
logGroup.setSource(this.source);
|
|
2049
|
-
const log = new Log(Date.now());
|
|
2221
|
+
const log = new sdk.Log(Date.now());
|
|
2050
2222
|
for (const key of Object.keys(finalFields)) {
|
|
2051
2223
|
log.addContent(key, stringifyLogValue(finalFields[key]));
|
|
2052
2224
|
}
|
|
2053
2225
|
logGroup.addLog(log);
|
|
2054
|
-
const request = new PutLogsRequest(this.topicId, logGroup);
|
|
2226
|
+
const request = new sdk.PutLogsRequest(this.topicId, logGroup);
|
|
2055
2227
|
const exit = enterClsSendingGuard();
|
|
2228
|
+
let p;
|
|
2056
2229
|
try {
|
|
2057
|
-
client.PutLogs(request);
|
|
2230
|
+
p = client.PutLogs(request);
|
|
2058
2231
|
}
|
|
2059
2232
|
finally {
|
|
2060
2233
|
exit();
|
|
2061
2234
|
}
|
|
2235
|
+
await p;
|
|
2062
2236
|
}
|
|
2063
2237
|
/**
|
|
2064
2238
|
* 直接上报:把 data 序列化后放入指定 key(默认 “日志内容”)
|
|
@@ -2117,11 +2291,19 @@ class ClsLogger {
|
|
|
2117
2291
|
console.warn('ClsLogger.putBatch:未初始化 topic_id');
|
|
2118
2292
|
return;
|
|
2119
2293
|
}
|
|
2120
|
-
|
|
2121
|
-
|
|
2294
|
+
void this.putBatchAsync(queue).catch(() => {
|
|
2295
|
+
// ignore
|
|
2296
|
+
});
|
|
2297
|
+
}
|
|
2298
|
+
async putBatchAsync(queue) {
|
|
2299
|
+
if (!this.topicId)
|
|
2300
|
+
return;
|
|
2301
|
+
const sdk = await this.loadSdk();
|
|
2302
|
+
const client = await this.getInstance();
|
|
2303
|
+
const logGroup = new sdk.LogGroup('127.0.0.1');
|
|
2122
2304
|
logGroup.setSource(this.source);
|
|
2123
2305
|
for (const item of queue) {
|
|
2124
|
-
const log = new Log(item.time);
|
|
2306
|
+
const log = new sdk.Log(item.time);
|
|
2125
2307
|
const data = item.data ?? {};
|
|
2126
2308
|
for (const key of Object.keys(data)) {
|
|
2127
2309
|
log.addContent(key, stringifyLogValue(data[key]));
|
|
@@ -2130,14 +2312,16 @@ class ClsLogger {
|
|
|
2130
2312
|
}
|
|
2131
2313
|
if (logGroup.getLogs().length === 0)
|
|
2132
2314
|
return;
|
|
2133
|
-
const request = new PutLogsRequest(this.topicId, logGroup);
|
|
2315
|
+
const request = new sdk.PutLogsRequest(this.topicId, logGroup);
|
|
2134
2316
|
const exit = enterClsSendingGuard();
|
|
2317
|
+
let p;
|
|
2135
2318
|
try {
|
|
2136
|
-
client.PutLogs(request);
|
|
2319
|
+
p = client.PutLogs(request);
|
|
2137
2320
|
}
|
|
2138
2321
|
finally {
|
|
2139
2322
|
exit();
|
|
2140
2323
|
}
|
|
2324
|
+
await p;
|
|
2141
2325
|
}
|
|
2142
2326
|
/**
|
|
2143
2327
|
* 参考《一、概述》:统一上报入口(内存队列 + 批量发送)
|
|
@@ -2250,12 +2434,13 @@ class ClsLogger {
|
|
|
2250
2434
|
async sendReportLogs(logs) {
|
|
2251
2435
|
if (!this.topicId)
|
|
2252
2436
|
return;
|
|
2253
|
-
const
|
|
2254
|
-
const
|
|
2437
|
+
const sdk = await this.loadSdk();
|
|
2438
|
+
const client = await this.getInstance();
|
|
2439
|
+
const logGroup = new sdk.LogGroup('127.0.0.1');
|
|
2255
2440
|
logGroup.setSource(this.source);
|
|
2256
2441
|
for (const item of logs) {
|
|
2257
2442
|
const fields = this.buildReportFields(item);
|
|
2258
|
-
const log = new Log(fields.timestamp);
|
|
2443
|
+
const log = new sdk.Log(fields.timestamp);
|
|
2259
2444
|
for (const key of Object.keys(fields)) {
|
|
2260
2445
|
if (key === 'timestamp')
|
|
2261
2446
|
continue;
|
|
@@ -2263,7 +2448,7 @@ class ClsLogger {
|
|
|
2263
2448
|
}
|
|
2264
2449
|
logGroup.addLog(log);
|
|
2265
2450
|
}
|
|
2266
|
-
const request = new PutLogsRequest(this.topicId, logGroup);
|
|
2451
|
+
const request = new sdk.PutLogsRequest(this.topicId, logGroup);
|
|
2267
2452
|
// 只在“发起网络请求”的同步阶段打标记,避免 requestMonitor 监控 CLS 上报请求导致递归
|
|
2268
2453
|
const exit = enterClsSendingGuard();
|
|
2269
2454
|
let p;
|