@pluve/logger-sdk 0.0.25 → 0.0.27

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 CHANGED
@@ -1,10 +1,10 @@
1
- # Logger SDK v2 说明文档
1
+ # @pluve/logger-sdk 说明文档
2
2
 
3
3
  ## 概览
4
4
 
5
- - 跨环境支持:浏览器与微信小程序
5
+ - 环境支持:浏览器
6
6
  - 采集与采样:开关、日志等级白名单、分级/来源/路径采样率
7
- - 传输适配:Beacon、像素图 Image、微信 `wx.request`
7
+ - 传输适配:Beacon、像素图 Image
8
8
  - 批量与队列:批量阈值与定时器、队列持久化(localforage)
9
9
  - 重试策略:可配置最大次数与指数退避
10
10
  - 压缩能力:可选 gzip 压缩,优先使用浏览器 CompressionStream,回退 fflate.gzipSync
@@ -12,7 +12,7 @@
12
12
  ## 快速开始
13
13
 
14
14
  ```ts
15
- import { LoggerSDK } from '@pluve/logger-sdk';
15
+ import { LoggerSDK, SecurityType } from '@pluve/logger-sdk';
16
16
 
17
17
  const sdk = LoggerSDK.getInstance();
18
18
 
@@ -29,16 +29,17 @@ sdk.init({
29
29
  userId: 'u-001',
30
30
  storeCode: 's-001',
31
31
  token: '<token>',
32
+ securityType: SecurityType.BASE,
32
33
  sampleRate: 1,
33
34
  enableAutoCapture: true,
34
- autoCapture: { js: true, promise: true, resource: true, wechat: true },
35
+ autoCapture: { js: true, promise: true, resource: true },
35
36
  });
36
37
 
37
38
  // 业务日志
38
39
  sdk.track({
39
40
  message: '用户点击了购买按钮',
40
41
  traceId: 'trace-xyz',
41
- logLevel: 'INFO',
42
+ logLevel: 'ERROR',
42
43
  });
43
44
 
44
45
  // 动态设置
@@ -51,14 +52,20 @@ sdk.setStage('testing');
51
52
 
52
53
  - enableGzip:是否启用 gzip 压缩(默认 true)
53
54
  - enableBatch:是否启用批量上报(默认需显式开启)
54
- - batchSize:批量阈值(默认 10
55
+ - batchSize:批量阈值(默认 20
55
56
  - batchInterval:批量定时器间隔(默认 15000ms)
56
57
  - maxPixelUrlLen:像素图 URL 最大长度(默认 8192)
57
58
  - enableStorage:队列持久化开关(默认 true)
58
- - enableRetry/maxRetries/retryDelay/retryBackoff:重试相关配置
59
+ - storeCode:店铺编码(可选)
60
+ - securityType:安全类型(默认 SecurityType.BASE / 'BASE')
61
+ - SecurityType.ACCOUNT_CENTER / '2B':账号中心
62
+ - SecurityType.EHP / 'EHP':EHP 医疗
63
+ - SecurityType.CUSTOMER / 'CUSTOMER':C 端会员(预留)
64
+ - SecurityType.BASE / 'BASE':兜底 MD5
65
+ - token:鉴权 Token
59
66
  - sampleRate/levelSampleRate/sourceSampleRate/pathSampleRate:采样配置
60
67
  - enableAutoCapture:自动采集总开关(默认开启)
61
- - autoCapture:细粒度开关 { js, promise, resource, wechat }
68
+ - autoCapture:细粒度开关 { js, promise, resource }
62
69
 
63
70
  说明:
64
71
 
@@ -80,11 +87,7 @@ sdk.setStage('testing');
80
87
  ## 传输适配
81
88
 
82
89
  - TransportAdapter 根据环境选择传输器:
83
- - 微信:WechatTransport(wx.request POST,支持 gzip)
84
90
  - 浏览器:优先 BeaconTransport(sendBeacon Blob),否则 PixelImageTransport(Image GET)
85
- - WechatTransport
86
- - 请求体字符串化 safeStringify
87
- - enableGzip 时使用 gzipCompress 生成 Base64,Content-Type 设为 `application/json; charset=utf-8`
88
91
  - PixelImageTransport
89
92
  - 字符串化 items,enableGzip 时压缩为 Base64;非 gzip 情况下优先使用全局 Base64,其次 btoa,再次 encodeURIComponent;URL 参数附带 `gzip=1`
90
93
  - 构造像素上报 URL(含 appId、appStage、items、cacheBuster)
@@ -95,7 +98,6 @@ sdk.setStage('testing');
95
98
  代码参考:
96
99
 
97
100
  - 适配器选择:[transportAdapter.ts](./src/transport/transportAdapter.ts)
98
- - WeChat:[wechatTransport.ts](./src/transport/wechatTransport.ts)
99
101
  - Pixel Image:[pixelImageTransport.ts](./src/transport/pixelImageTransport.ts)
100
102
  - Beacon:[beaconTransport.ts](./src/transport/beaconTransport.ts)
101
103
 
@@ -145,8 +147,8 @@ sdk.setStage('testing');
145
147
  ## 流程图
146
148
 
147
149
  - 完整 Mermaid 流程图见文件:
148
- - [logger-sdk.mermaid](./src/logger-sdk.mermaid)
149
- - [logger-sdk.svg](./src/logger-sdk.svg)
150
+ - [logger-sdk.mermaid](./docs/logger-sdk.mermaid)
151
+ - [logger-sdk.svg](./docs/logger-sdk.svg)
150
152
 
151
153
  ## 类型与打包
152
154
 
@@ -173,17 +175,6 @@ sdk.setStage('testing');
173
175
 
174
176
  ## 编码细节(传输 × 压缩)
175
177
 
176
- - WechatTransport(POST)
177
- - 未压缩
178
- - Body:JSON(safeStringify(payload))
179
- - Header:Content-Type: application/json;token: <opts.token>
180
- - items:字符串化后的数组(message/throwable 等为字符串)
181
- - Endpoint:[config.getReportApi](.src/config/index.ts)
182
- - 启用压缩
183
- - items:safeStringify(items) 后使用 [gzipCompress](.src/compress/compression.ts) 生成 Base64
184
- - Body:JSON(...payload, items: Base64)
185
- - Header:Content-Type: application/json; charset=utf-8;token: <opts.token>
186
-
187
178
  - BeaconTransport(sendBeacon)
188
179
  - 未压缩
189
180
  - Body:JSON(safeStringify(payload))
@@ -21,6 +21,7 @@ var LoggerSDK = class {
21
21
  this.closed = false;
22
22
  /** 预收集的环境信息 tags(仅用于初始化上报) */
23
23
  this.envTags = {};
24
+ this.envTagsStr = "";
24
25
  /** 是否已初始化 */
25
26
  this.initialized = false;
26
27
  /** 是否正在上报 */
@@ -64,7 +65,7 @@ var LoggerSDK = class {
64
65
  // 持久化存储配置
65
66
  enableStorage: options.enableBatch === true || options.enableStorage !== false,
66
67
  // 默认启用
67
- storagePrefix: options.storagePrefix || "logger_sdk",
68
+ storagePrefix: options.storagePrefix || `${options.appId}_logger_sdk`,
68
69
  // 重试配置
69
70
  enableRetry: options.enableRetry !== false,
70
71
  // 默认启用
@@ -79,19 +80,19 @@ var LoggerSDK = class {
79
80
  token: options.token,
80
81
  sampleRate: typeof options.sampleRate === "number" ? options.sampleRate : 1,
81
82
  levelSampleRate: options.levelSampleRate || {
82
- ERROR: 0.8,
83
- WARN: 0.5,
84
- INFO: 0.1,
85
- FATAL: 1
83
+ ERROR: 80,
84
+ WARN: 50,
85
+ INFO: 10,
86
+ FATAL: 100
86
87
  },
87
88
  sourceSampleRate: options.sourceSampleRate || {
88
- js: 0.8,
89
- promise: 0.5,
90
- resource: 0.2,
91
- custom: 1
89
+ js: 80,
90
+ promise: 50,
91
+ resource: 20,
92
+ custom: 100
92
93
  },
93
94
  pathSampleRate: options.pathSampleRate || {
94
- "/": 1
95
+ "/": 100
95
96
  },
96
97
  enableAutoCapture: options.enableAutoCapture !== false,
97
98
  // 默认启用
@@ -120,6 +121,7 @@ var LoggerSDK = class {
120
121
  this.transporter = void 0;
121
122
  this.sessionId = getSessionId();
122
123
  this.envTags = collectEnvironmentTags();
124
+ this.envTagsStr = this.flattenEnvTags();
123
125
  this.initSDK(this.opts, (data) => {
124
126
  var _a, _b, _c, _d, _e, _f;
125
127
  this.collectSwitch = data.collectSwitch;
@@ -136,16 +138,10 @@ var LoggerSDK = class {
136
138
  this.offJs = registerJsErrorCapture(!!((_d = this.opts) == null ? void 0 : _d.debug), this.trackInner.bind(this));
137
139
  }
138
140
  if (enableAuto && ac.promise !== false) {
139
- this.offPromise = registerPromiseErrorCapture(
140
- !!((_e = this.opts) == null ? void 0 : _e.debug),
141
- this.trackInner.bind(this)
142
- );
141
+ this.offPromise = registerPromiseErrorCapture(!!((_e = this.opts) == null ? void 0 : _e.debug), this.trackInner.bind(this));
143
142
  }
144
143
  if (enableAuto && ac.resource !== false) {
145
- this.offResource = registerResourceErrorCapture(
146
- !!((_f = this.opts) == null ? void 0 : _f.debug),
147
- this.trackInner.bind(this)
148
- );
144
+ this.offResource = registerResourceErrorCapture(!!((_f = this.opts) == null ? void 0 : _f.debug), this.trackInner.bind(this));
149
145
  }
150
146
  });
151
147
  }
@@ -190,6 +186,10 @@ var LoggerSDK = class {
190
186
  flattenEnvTags() {
191
187
  return Object.entries(this.envTags || {}).map(([k, v]) => `${k}=${v}`).join(",");
192
188
  }
189
+ buildLogMessage(logType, message) {
190
+ var _a, _b, _c;
191
+ return `[logType]: ${logType}; [appVersion]: ${((_a = this.opts) == null ? void 0 : _a.appVersion) || "unknown"}; [userId]: ${((_b = this.opts) == null ? void 0 : _b.userId) || "unknown"}; [storeCode]: ${((_c = this.opts) == null ? void 0 : _c.storeCode) || "unknown"}; [message]: ${message}; [envTags]: ${this.envTagsStr}; [t]: ${now()}`;
192
+ }
193
193
  async track({ message, error, traceId, logLevel = "INFO" }) {
194
194
  var _a, _b, _c;
195
195
  logDebug(!!((_a = this.opts) == null ? void 0 : _a.debug), "track", { message, error, traceId, logLevel });
@@ -236,7 +236,7 @@ var LoggerSDK = class {
236
236
  url: getCurrentUrl(),
237
237
  location: errorLocation,
238
238
  /** 异常信息 */
239
- message: `[message]: ${message}; [envTags]: ${this.flattenEnvTags()}; [t]: ${now()}`,
239
+ message: this.buildLogMessage("custom", message),
240
240
  /** 可选:堆栈信息(长字符串) */
241
241
  throwable: throwableStack,
242
242
  /** 可选:用户 ID(脱敏) */
@@ -292,7 +292,7 @@ var LoggerSDK = class {
292
292
  url: getCurrentUrl(),
293
293
  location: errorLocation,
294
294
  /** 异常信息 */
295
- message: `[message]: ${error.message}; [envTags]: ${this.flattenEnvTags()}; [t]: ${now()}`,
295
+ message: this.buildLogMessage(error.type, error.message),
296
296
  /** 可选:堆栈信息(长字符串) */
297
297
  throwable: throwableStack,
298
298
  /** 可选:用户 ID(脱敏) */
@@ -304,11 +304,24 @@ var LoggerSDK = class {
304
304
  };
305
305
  this.doTrack(logEvent);
306
306
  }
307
+ getBaseRate(source) {
308
+ var _a, _b, _c, _d, _e, _f, _g, _h;
309
+ switch (source) {
310
+ case "js":
311
+ return ((_a = this.opts) == null ? void 0 : _a.sourceSampleRate.js) || ((_b = this.opts) == null ? void 0 : _b.sampleRate) || 100;
312
+ case "promise":
313
+ return ((_c = this.opts) == null ? void 0 : _c.sourceSampleRate.promise) || ((_d = this.opts) == null ? void 0 : _d.sampleRate) || 100;
314
+ case "resource":
315
+ return ((_e = this.opts) == null ? void 0 : _e.sourceSampleRate.resource) || ((_f = this.opts) == null ? void 0 : _f.sampleRate) || 100;
316
+ case "custom":
317
+ return ((_g = this.opts) == null ? void 0 : _g.sampleRate) || ((_h = this.opts) == null ? void 0 : _h.sourceSampleRate.custom) || 100;
318
+ }
319
+ }
307
320
  /**
308
321
  * 判断是否应该发送事件
309
322
  */
310
323
  shouldSend(level, source, url, traceId, message) {
311
- var _a, _b, _c, _d, _e, _f, _g;
324
+ var _a, _b, _c, _d, _e;
312
325
  if (level === "FATAL")
313
326
  return true;
314
327
  if (this.collectSwitch === 0) {
@@ -319,37 +332,14 @@ var LoggerSDK = class {
319
332
  logDebug(!!((_b = this.opts) == null ? void 0 : _b.debug), `Log level(${level}) not in collect log level, skip track`);
320
333
  return false;
321
334
  }
322
- const levelRate = (_d = (_c = this.opts) == null ? void 0 : _c.levelSampleRate) == null ? void 0 : _d[level];
323
- const sourceRate = (_f = (_e = this.opts) == null ? void 0 : _e.sourceSampleRate) == null ? void 0 : _f[source];
324
- let pathRate;
325
- const pathMap = ((_g = this.opts) == null ? void 0 : _g.pathSampleRate) || {};
326
- const prefixes = Object.keys(pathMap);
327
- if (prefixes.length) {
328
- let best = "";
329
- for (let i = 0; i < prefixes.length; i += 1) {
330
- const p2 = prefixes[i];
331
- if (url.startsWith(p2) && p2.length >= best.length)
332
- best = p2;
333
- }
334
- if (best)
335
- pathRate = pathMap[best];
336
- }
337
- const baseRate = (() => {
338
- var _a2;
339
- if (typeof levelRate === "number")
340
- return levelRate;
341
- if (typeof sourceRate === "number")
342
- return sourceRate;
343
- if (typeof pathRate === "number")
344
- return pathRate;
345
- const sr = (_a2 = this.opts) == null ? void 0 : _a2.sampleRate;
346
- return typeof sr === "number" ? sr : 1;
347
- })();
348
- const rate = Math.max(0, Math.min(1, baseRate));
349
- if (rate >= 1)
335
+ const rate = Math.max(0, Math.min(100, this.getBaseRate(source)));
336
+ logDebug(!!((_c = this.opts) == null ? void 0 : _c.debug), "shouldSend rate: ", rate);
337
+ if (rate >= 100)
350
338
  return true;
351
- const seed = `${String(traceId || "")}|${String(message || "")}|${String(this.sessionId || "")}|${String(level)}|${String(source)}|${String(url)}`;
352
- const p = hashToProb(seed);
339
+ const seed = normalizeMessage(`${url}${traceId || ""}${message || ""}`);
340
+ logDebug(!!((_d = this.opts) == null ? void 0 : _d.debug), "shouldSend seed: ", seed);
341
+ const p = hashToProb(seed) * 100;
342
+ logDebug(!!((_e = this.opts) == null ? void 0 : _e.debug), "shouldSend p: ", p);
353
343
  return p < rate;
354
344
  }
355
345
  /**
package/dist/esm/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  // src/index.ts
2
2
  import { LoggerSDK } from "./core/loggerSDK";
3
+ import { SecurityType } from "./types/securityType";
3
4
  export {
4
- LoggerSDK
5
+ LoggerSDK,
6
+ SecurityType
5
7
  };
@@ -11,6 +11,7 @@ export declare class LoggerSDK {
11
11
  private closed;
12
12
  /** 预收集的环境信息 tags(仅用于初始化上报) */
13
13
  private envTags;
14
+ private envTagsStr;
14
15
  /** 是否已初始化 */
15
16
  private initialized;
16
17
  /** 初始化时生成并锁定的会话标识 */
@@ -50,8 +51,10 @@ export declare class LoggerSDK {
50
51
  /** 设置日志 stage(env) */
51
52
  setStage(stage: Env): void;
52
53
  private flattenEnvTags;
54
+ private buildLogMessage;
53
55
  track({ message, error, traceId, logLevel }: TrackOptions): Promise<void>;
54
56
  private trackInner;
57
+ private getBaseRate;
55
58
  /**
56
59
  * 判断是否应该发送事件
57
60
  */
@@ -1,4 +1,4 @@
1
1
  export { LoggerSDK } from './core/loggerSDK';
2
2
  export type { Env, Stage } from './types/env';
3
- export type { SecurityType } from './types/securityType';
3
+ export { SecurityType } from './types/securityType';
4
4
  export type { TrackOptions } from './types/trackOptions';
@@ -14,13 +14,13 @@ export interface SDKOptions {
14
14
  debug?: boolean;
15
15
  /** 是否启用批量上报,默认 true */
16
16
  enableBatch?: boolean;
17
- /** 批量上报最大数量,默认 10 */
17
+ /** 批量上报最大数量,默认 20 */
18
18
  batchSize?: number;
19
19
  /** 是否启用 gzip 压缩,默认 true (仅在批量模式下有效) */
20
20
  enableGzip?: boolean;
21
- /** 最大像素图 URL 长度,默认 1900 */
21
+ /** 最大像素图 URL 长度,默认 8192 */
22
22
  maxPixelUrlLen?: number;
23
- /** 批量上报时间间隔(毫秒),默认 5000 */
23
+ /** 批量上报时间间隔(毫秒),默认 15000 */
24
24
  batchInterval?: number;
25
25
  /** 队列最大长度,默认 100 */
26
26
  maxQueueSize?: number;
@@ -46,11 +46,11 @@ export interface SDKOptions {
46
46
  token: string;
47
47
  /** 全局采样率 0.0-1.0,默认 1.0(全量) */
48
48
  sampleRate?: number;
49
- /** 分级采样率,优先于全局采样率 */
49
+ /** 分级采样率,优先于全局采样率。默认 { ERROR: 0.8, WARN: 0.5, INFO: 0.1, FATAL: 1 } */
50
50
  levelSampleRate?: Partial<Record<LogEventLevel, number>>;
51
- /** 事件来源采样率(js/promise/resource/custom),优先于全局采样率 */
51
+ /** 事件来源采样率(js/promise/resource/custom),优先于全局采样率。默认 { js: 0.8, promise: 0.5, resource: 0.2, custom: 1 } */
52
52
  sourceSampleRate?: Partial<Record<'js' | 'promise' | 'resource' | 'custom', number>>;
53
- /** 页面路径采样率,key 为路径前缀,优先于全局采样率 */
53
+ /** 页面路径采样率,key 为路径前缀,优先于全局采样率。默认 { '/': 1 } */
54
54
  pathSampleRate?: Record<string, number>;
55
55
  autoCapture?: {
56
56
  js?: boolean;
@@ -58,4 +58,5 @@ export interface SDKOptions {
58
58
  resource?: boolean;
59
59
  };
60
60
  enableAutoCapture?: boolean;
61
+ appVersion?: string;
61
62
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluve/logger-sdk",
3
- "version": "0.0.25",
3
+ "version": "0.0.27",
4
4
  "description": "logger sdk",
5
5
  "keywords": [
6
6
  "logger"