@pluve/logger-sdk 0.0.26 → 0.0.28

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
  /** 是否正在上报 */
@@ -46,6 +47,8 @@ var LoggerSDK = class {
46
47
  // endpoint: options.endpoint,
47
48
  appId: `${options.appId}`,
48
49
  // 统一与 zadig 部署应用 APPID 保持一致
50
+ /** 应用版本 */
51
+ appVersion: options.appVersion || "unknown",
49
52
  env: options.env || "develop",
50
53
  /** 日志环境 */
51
54
  logStage: options.logStage,
@@ -64,7 +67,7 @@ var LoggerSDK = class {
64
67
  // 持久化存储配置
65
68
  enableStorage: options.enableBatch === true || options.enableStorage !== false,
66
69
  // 默认启用
67
- storagePrefix: options.storagePrefix || "logger_sdk",
70
+ storagePrefix: options.storagePrefix || `${options.appId}_logger_sdk`,
68
71
  // 重试配置
69
72
  enableRetry: options.enableRetry !== false,
70
73
  // 默认启用
@@ -79,19 +82,19 @@ var LoggerSDK = class {
79
82
  token: options.token,
80
83
  sampleRate: typeof options.sampleRate === "number" ? options.sampleRate : 1,
81
84
  levelSampleRate: options.levelSampleRate || {
82
- ERROR: 0.8,
83
- WARN: 0.5,
84
- INFO: 0.1,
85
- FATAL: 1
85
+ ERROR: 80,
86
+ WARN: 50,
87
+ INFO: 10,
88
+ FATAL: 100
86
89
  },
87
90
  sourceSampleRate: options.sourceSampleRate || {
88
- js: 0.8,
89
- promise: 0.5,
90
- resource: 0.2,
91
- custom: 1
91
+ js: 80,
92
+ promise: 50,
93
+ resource: 20,
94
+ custom: 100
92
95
  },
93
96
  pathSampleRate: options.pathSampleRate || {
94
- "/": 1
97
+ "/": 100
95
98
  },
96
99
  enableAutoCapture: options.enableAutoCapture !== false,
97
100
  // 默认启用
@@ -120,6 +123,7 @@ var LoggerSDK = class {
120
123
  this.transporter = void 0;
121
124
  this.sessionId = getSessionId();
122
125
  this.envTags = collectEnvironmentTags();
126
+ this.envTagsStr = this.flattenEnvTags();
123
127
  this.initSDK(this.opts, (data) => {
124
128
  var _a, _b, _c, _d, _e, _f;
125
129
  this.collectSwitch = data.collectSwitch;
@@ -136,16 +140,10 @@ var LoggerSDK = class {
136
140
  this.offJs = registerJsErrorCapture(!!((_d = this.opts) == null ? void 0 : _d.debug), this.trackInner.bind(this));
137
141
  }
138
142
  if (enableAuto && ac.promise !== false) {
139
- this.offPromise = registerPromiseErrorCapture(
140
- !!((_e = this.opts) == null ? void 0 : _e.debug),
141
- this.trackInner.bind(this)
142
- );
143
+ this.offPromise = registerPromiseErrorCapture(!!((_e = this.opts) == null ? void 0 : _e.debug), this.trackInner.bind(this));
143
144
  }
144
145
  if (enableAuto && ac.resource !== false) {
145
- this.offResource = registerResourceErrorCapture(
146
- !!((_f = this.opts) == null ? void 0 : _f.debug),
147
- this.trackInner.bind(this)
148
- );
146
+ this.offResource = registerResourceErrorCapture(!!((_f = this.opts) == null ? void 0 : _f.debug), this.trackInner.bind(this));
149
147
  }
150
148
  });
151
149
  }
@@ -190,6 +188,10 @@ var LoggerSDK = class {
190
188
  flattenEnvTags() {
191
189
  return Object.entries(this.envTags || {}).map(([k, v]) => `${k}=${v}`).join(",");
192
190
  }
191
+ buildLogMessage(logType, message) {
192
+ var _a, _b, _c;
193
+ 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()}`;
194
+ }
193
195
  async track({ message, error, traceId, logLevel = "INFO" }) {
194
196
  var _a, _b, _c;
195
197
  logDebug(!!((_a = this.opts) == null ? void 0 : _a.debug), "track", { message, error, traceId, logLevel });
@@ -236,7 +238,7 @@ var LoggerSDK = class {
236
238
  url: getCurrentUrl(),
237
239
  location: errorLocation,
238
240
  /** 异常信息 */
239
- message: `[message]: ${message}; [envTags]: ${this.flattenEnvTags()}; [t]: ${now()}`,
241
+ message: this.buildLogMessage("custom", message),
240
242
  /** 可选:堆栈信息(长字符串) */
241
243
  throwable: throwableStack,
242
244
  /** 可选:用户 ID(脱敏) */
@@ -292,7 +294,7 @@ var LoggerSDK = class {
292
294
  url: getCurrentUrl(),
293
295
  location: errorLocation,
294
296
  /** 异常信息 */
295
- message: `[message]: ${error.message}; [envTags]: ${this.flattenEnvTags()}; [t]: ${now()}`,
297
+ message: this.buildLogMessage(error.type, error.message),
296
298
  /** 可选:堆栈信息(长字符串) */
297
299
  throwable: throwableStack,
298
300
  /** 可选:用户 ID(脱敏) */
@@ -304,11 +306,24 @@ var LoggerSDK = class {
304
306
  };
305
307
  this.doTrack(logEvent);
306
308
  }
309
+ getBaseRate(source) {
310
+ var _a, _b, _c, _d, _e, _f, _g, _h;
311
+ switch (source) {
312
+ case "js":
313
+ return ((_a = this.opts) == null ? void 0 : _a.sourceSampleRate.js) || ((_b = this.opts) == null ? void 0 : _b.sampleRate) || 100;
314
+ case "promise":
315
+ return ((_c = this.opts) == null ? void 0 : _c.sourceSampleRate.promise) || ((_d = this.opts) == null ? void 0 : _d.sampleRate) || 100;
316
+ case "resource":
317
+ return ((_e = this.opts) == null ? void 0 : _e.sourceSampleRate.resource) || ((_f = this.opts) == null ? void 0 : _f.sampleRate) || 100;
318
+ case "custom":
319
+ return ((_g = this.opts) == null ? void 0 : _g.sampleRate) || ((_h = this.opts) == null ? void 0 : _h.sourceSampleRate.custom) || 100;
320
+ }
321
+ }
307
322
  /**
308
323
  * 判断是否应该发送事件
309
324
  */
310
325
  shouldSend(level, source, url, traceId, message) {
311
- var _a, _b, _c, _d, _e, _f, _g;
326
+ var _a, _b, _c, _d, _e;
312
327
  if (level === "FATAL")
313
328
  return true;
314
329
  if (this.collectSwitch === 0) {
@@ -319,37 +334,14 @@ var LoggerSDK = class {
319
334
  logDebug(!!((_b = this.opts) == null ? void 0 : _b.debug), `Log level(${level}) not in collect log level, skip track`);
320
335
  return false;
321
336
  }
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)
337
+ const rate = Math.max(0, Math.min(100, this.getBaseRate(source)));
338
+ logDebug(!!((_c = this.opts) == null ? void 0 : _c.debug), "shouldSend rate: ", rate);
339
+ if (rate >= 100)
350
340
  return true;
351
- const seed = `${String(traceId || "")}|${String(message || "")}|${String(this.sessionId || "")}|${String(level)}|${String(source)}|${String(url)}`;
352
- const p = hashToProb(seed);
341
+ const seed = normalizeMessage(`${url}${traceId || ""}${message || ""}`);
342
+ logDebug(!!((_d = this.opts) == null ? void 0 : _d.debug), "shouldSend seed: ", seed);
343
+ const p = hashToProb(seed) * 100;
344
+ logDebug(!!((_e = this.opts) == null ? void 0 : _e.debug), "shouldSend p: ", p);
353
345
  return p < rate;
354
346
  }
355
347
  /**
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.26",
3
+ "version": "0.0.28",
4
4
  "description": "logger sdk",
5
5
  "keywords": [
6
6
  "logger"