@xiaohao0725/logs-sdk 0.3.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/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # 日志管理平台 Node.js SDK
2
+
3
+ [English Documentation](https://github.com/xiaohao0725/logs-sdk-js/blob/main/README_EN.md) | [NPM](https://www.npmjs.com/package/@xiaohao0725/logs-sdk)
4
+
5
+ `@xiaohao0725/logs-sdk` 是日志管理平台的 Node.js / TypeScript SDK,提供 Express 和 Koa 中间件,一行代码即可自动采集 HTTP 请求的完整日志(请求/响应头体、客户端信息、设备信息、错误堆栈等),异步批量上报,对业务性能零影响。
6
+
7
+ ## 功能特性
8
+
9
+ - ✅ **一行代码接入**:`app.use(logger.expressMiddleware())` / `app.use(logger.koaMiddleware())`
10
+ - ✅ **完整采集**:60+ 字段——请求头/体、响应头/体、客户端 IP/端口/类型、设备信息、TLS 版本、API 版本
11
+ - ✅ **自动识别**:客户端类型(Web / 小程序 / App / 服务端 / 其他)、请求来源(Referer / 微服务调用链)
12
+ - ✅ **错误捕获**:HTTP 5xx 自动标记 + 错误堆栈采集
13
+ - ✅ **UUID v7**:32 位十六进制无连字符,天然按时间排序
14
+ - ✅ **敏感脱敏**:Authorization / Cookie 自动脱敏,不记录明文
15
+ - ✅ **异步非阻塞**:环形缓冲区 + 后台定时刷新,不阻塞业务请求
16
+ - ✅ **离线缓存**:网络故障时自动缓存到本地文件,恢复后自动重传
17
+ - ✅ **优雅关闭**:`close()` 确保缓冲日志全部上报
18
+ - ✅ **TypeScript**:完整类型定义,IDE 智能提示
19
+
20
+ ## 安装
21
+
22
+ ```bash
23
+ npm install @xiaohao0725/logs-sdk
24
+ ```
25
+
26
+ 要求 Node.js 18+。
27
+
28
+ ## 快速开始
29
+
30
+ ### Express
31
+
32
+ ```typescript
33
+ import express from 'express';
34
+ import { LogSDK } from '@xiaohao0725/logs-sdk';
35
+
36
+ const app = express();
37
+
38
+ // ① 创建客户端
39
+ const logger = new LogSDK({
40
+ endpoint: 'https://api.logs.codexs.cn/api/v1/ingest/logs',
41
+ apiKey: 'clog_pk_xxx',
42
+ apiSecret: 'clog_sk_xxx',
43
+ projectSlug: 'my-project',
44
+ environment: 'production',
45
+ });
46
+
47
+ // ② 重传离线缓存的日志
48
+ await logger.flushOffline();
49
+
50
+ // ③ 注册 Express 中间件——一行代码接入
51
+ app.use(logger.expressMiddleware());
52
+
53
+ app.get('/api/hello', (req, res) => {
54
+ res.json({ message: 'hello' });
55
+ });
56
+
57
+ app.listen(3000);
58
+ ```
59
+
60
+ ### Koa
61
+
62
+ ```typescript
63
+ import Koa from 'koa';
64
+ import { LogSDK } from '@xiaohao0725/logs-sdk';
65
+
66
+ const app = new Koa();
67
+ const logger = new LogSDK({...});
68
+
69
+ // Koa 中间件
70
+ app.use(logger.koaMiddleware());
71
+ ```
72
+
73
+ ## 配置参数
74
+
75
+ | 参数 | 类型 | 默认值 | 说明 |
76
+ |------|------|--------|------|
77
+ | `endpoint` | `string` | **必填** | 日志上报地址 |
78
+ | `apiKey` | `string` | **必填** | SDK 认证密钥(公钥) |
79
+ | `apiSecret` | `string` | **必填** | SDK 认证密钥(私钥) |
80
+ | `projectSlug` | `string` | **必填** | 项目短标识 |
81
+ | `environment` | `string` | `"production"` | 运行环境:production / staging / development |
82
+ | `serviceName` | `string` | `""` | 微服务名称 |
83
+ | `bufferSize` | `number` | `1000` | 本地环形缓冲区容量,满 80% 自动 flush |
84
+ | `flushInterval` | `number` | `5` | 定时刷新间隔(秒) |
85
+ | `maxRetries` | `number` | `3` | 最大重试次数,指数退避 |
86
+ | `maxBodySize` | `number` | `4096` | 请求/响应体最大采集大小(字节) |
87
+ | `maxStackSize` | `number` | `8192` | 错误堆栈最大采集大小(字节) |
88
+
89
+ ## 采集字段一览
90
+
91
+ 与 Go SDK 完全对齐,详见 [LogEntry 类型定义](./src/types.ts)。
92
+
93
+ | 分类 | 字段 |
94
+ |------|------|
95
+ | 请求 | `method`, `scheme`, `full_url`, `host_header`, `path`, `query_string`, `origin`, `request_headers`, `request_body`, `request_body_size`, `content_type` |
96
+ | 响应 | `status_code`, `response_headers`, `response_body`, `response_body_size` |
97
+ | 客户端 | `client_ip`, `client_ip_chain`, `client_type`, `client_port` |
98
+ | 设备 | `user_agent`, `device_type`, `browser`, `browser_version`, `os_name`, `os_version` |
99
+ | TLS/协议 | `tls_version`, `tls_cipher`, `proto`, `api_version`, `referer` |
100
+ | 追踪 | `trace_id`, `span_id`, `parent_span_id`, `user_id`, `session_id`, `request_id` |
101
+ | 错误 | `is_error`, `error_type`, `error_message`, `error_stack` |
102
+
103
+ ## 架构设计
104
+
105
+ ```
106
+ HTTP 请求进入
107
+
108
+ ├─ ① expressMiddleware() / koaMiddleware()
109
+ │ ├─ 生成 UUID v7(32 位无连字符)
110
+ │ ├─ 读取请求体(缓存以支持后续中间件读取)
111
+ │ └─ 记录开始时间(hrtime)
112
+
113
+ ├─ ② 业务 Handler
114
+
115
+ ├─ ③ 劫持 res.end 捕获响应体
116
+ │ └─ 构建 LogEntry(60+ 字段)
117
+
118
+ ├─ ④ 写入环形缓冲区(非阻塞)
119
+
120
+ └─ ⑤ 后台定时刷新(每 5s 或缓冲 80% 满)
121
+ └─ 批量 POST 到 Ingestion API → 重试 → 失败则离线缓存
122
+ ```
123
+
124
+ ## 离线缓存
125
+
126
+ 网络故障时,SDK 自动将日志保存到系统临时目录:
127
+
128
+ ```
129
+ $TMPDIR/logs-sdk-offline/
130
+ ├── offline-2026-06-21T12-00-00.json
131
+ ├── offline-2026-06-21T12-00-05.json
132
+ └── ...
133
+ ```
134
+
135
+ - 最大缓存 50MB,超过自动清理旧文件
136
+ - 超过 24 小时的缓存自动删除
137
+ - 调用 `flushOffline()` 或 `close()` 时自动重传
138
+
139
+ ## 版本历史
140
+
141
+ | 版本 | 日期 | 变更 |
142
+ |------|------|------|
143
+ | v0.3.0 | 2026-06-21 | 新增 TLS/协议/API版本/Referer/耗时分解/request_id 等 8 字段 |
144
+ | v0.2.0 | 2026-06-21 | 新增离线缓存(断网本地存储,恢复自动重传) |
145
+ | v0.1.0 | 2026-06-21 | 初始版本:Express/Koa 中间件、异步缓冲、重试 |
146
+
147
+ ## License
148
+
149
+ UNLICENSED — 内部使用
@@ -0,0 +1,19 @@
1
+ import type { LogEntry } from './types';
2
+ export type FlushCallback = (entries: LogEntry[]) => void;
3
+ export declare class RingBuffer {
4
+ private buf;
5
+ private capacity;
6
+ private head;
7
+ private tail;
8
+ private count;
9
+ private flushFn;
10
+ constructor(capacity: number, flushFn: FlushCallback);
11
+ /** 追加一条日志到缓冲区 */
12
+ push(entry: LogEntry): void;
13
+ /** 取出所有待上报日志并清空缓冲 */
14
+ flush(): LogEntry[];
15
+ get length(): number;
16
+ /** 内部排空方法 */
17
+ private drain;
18
+ }
19
+ //# sourceMappingURL=buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../src/buffer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;AAE1D,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAsB;IACjC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,OAAO,CAAgB;gBAEnB,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa;IAMpD,iBAAiB;IACjB,IAAI,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAY3B,qBAAqB;IACrB,KAAK,IAAI,QAAQ,EAAE;IAInB,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,aAAa;IACb,OAAO,CAAC,KAAK;CAad"}
package/dist/buffer.js ADDED
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RingBuffer = void 0;
4
+ class RingBuffer {
5
+ buf;
6
+ capacity;
7
+ head = 0;
8
+ tail = 0;
9
+ count = 0;
10
+ flushFn;
11
+ constructor(capacity, flushFn) {
12
+ this.capacity = Math.max(capacity, 100);
13
+ this.buf = new Array(this.capacity).fill(null);
14
+ this.flushFn = flushFn;
15
+ }
16
+ /** 追加一条日志到缓冲区 */
17
+ push(entry) {
18
+ this.buf[this.head] = entry;
19
+ this.head = (this.head + 1) % this.capacity;
20
+ this.count++;
21
+ // 缓冲使用率达 80% 自动触发 flush
22
+ if (this.count >= Math.floor(this.capacity * 0.8)) {
23
+ const entries = this.drain();
24
+ this.flushFn(entries);
25
+ }
26
+ }
27
+ /** 取出所有待上报日志并清空缓冲 */
28
+ flush() {
29
+ return this.drain();
30
+ }
31
+ get length() {
32
+ return this.count;
33
+ }
34
+ /** 内部排空方法 */
35
+ drain() {
36
+ const entries = [];
37
+ while (this.count > 0) {
38
+ const entry = this.buf[this.tail];
39
+ if (entry) {
40
+ entries.push(entry);
41
+ }
42
+ this.buf[this.tail] = null; // 帮助 GC
43
+ this.tail = (this.tail + 1) % this.capacity;
44
+ this.count--;
45
+ }
46
+ return entries;
47
+ }
48
+ }
49
+ exports.RingBuffer = RingBuffer;
50
+ //# sourceMappingURL=buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.js","sourceRoot":"","sources":["../src/buffer.ts"],"names":[],"mappings":";;;AAKA,MAAa,UAAU;IACb,GAAG,CAAsB;IACzB,QAAQ,CAAS;IACjB,IAAI,GAAG,CAAC,CAAC;IACT,IAAI,GAAG,CAAC,CAAC;IACT,KAAK,GAAG,CAAC,CAAC;IACV,OAAO,CAAgB;IAE/B,YAAY,QAAgB,EAAE,OAAsB;QAClD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,GAAG,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,iBAAiB;IACjB,IAAI,CAAC,KAAe;QAClB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QAEb,wBAAwB;QACxB,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,EAAE,CAAC;YAClD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,KAAK;QACH,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,aAAa;IACL,KAAK;QACX,MAAM,OAAO,GAAe,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,QAAQ;YACpC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAlDD,gCAkDC"}
@@ -0,0 +1,31 @@
1
+ import type { LogEntry, LogSDKConfig, ResolvedConfig } from './types';
2
+ export declare class LogSDK {
3
+ private config;
4
+ private buffer;
5
+ private flushTimer;
6
+ private closed;
7
+ private offlineCache;
8
+ private hostname;
9
+ private pid;
10
+ constructor(config: LogSDKConfig);
11
+ /** 异步发送一条日志到缓冲区(非阻塞) */
12
+ send(entry: LogEntry): void;
13
+ /** 优雅关闭,等待缓冲日志全部上报 */
14
+ close(): Promise<void>;
15
+ /** 获取 Express 中间件(动态导入,避免不安装 express 时出错) */
16
+ expressMiddleware(): any;
17
+ /** 获取 Koa 中间件 */
18
+ koaMiddleware(): any;
19
+ /** 异步发送一批日志(包装重试) */
20
+ private flushEntries;
21
+ /** 重传离线缓存的日志 */
22
+ flushOffline(): Promise<void>;
23
+ /** HTTP POST 批量发送日志 */
24
+ private sendBatch;
25
+ /** 以下方法公开给 middleware 使用 */
26
+ get configResolved(): ResolvedConfig;
27
+ get host(): string;
28
+ }
29
+ /** 生成 UUID v7(32 位十六进制无连字符) */
30
+ export declare function newLogUUID(): string;
31
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAItE,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,GAAG,CAAS;gBAER,MAAM,EAAE,YAAY;IAsBhC,wBAAwB;IACxB,IAAI,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAe3B,sBAAsB;IAChB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB5B,6CAA6C;IAC7C,iBAAiB;IAMjB,iBAAiB;IACjB,aAAa;IAQb,qBAAqB;YACP,YAAY;IAW1B,gBAAgB;IACV,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAOnC,uBAAuB;YACT,SAAS;IA6BvB,4BAA4B;IAC5B,IAAI,cAAc,IAAI,cAAc,CAEnC;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAmBD,+BAA+B;AAC/B,wBAAgB,UAAU,IAAI,MAAM,CAEnC"}
package/dist/client.js ADDED
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.LogSDK = void 0;
37
+ exports.newLogUUID = newLogUUID;
38
+ // 核心客户端 — 管理配置、缓冲、定时刷新和 HTTP 上报
39
+ const os = __importStar(require("os"));
40
+ const uuid_1 = require("uuid");
41
+ const buffer_1 = require("./buffer");
42
+ const offline_1 = require("./offline");
43
+ const retry_1 = require("./retry");
44
+ const VERSION = '0.1.0';
45
+ class LogSDK {
46
+ config;
47
+ buffer;
48
+ flushTimer = null;
49
+ closed = false;
50
+ offlineCache;
51
+ hostname;
52
+ pid;
53
+ constructor(config) {
54
+ this.config = resolveConfig(config);
55
+ this.offlineCache = new offline_1.OfflineCache();
56
+ this.hostname = os.hostname();
57
+ this.pid = String(process.pid);
58
+ // 创建环形缓冲区
59
+ this.buffer = new buffer_1.RingBuffer(this.config.bufferSize, (entries) => {
60
+ this.flushEntries(entries).catch(() => {
61
+ // 失败在 flushEntries 内部已打日志
62
+ });
63
+ });
64
+ // 启动定时 flush
65
+ this.flushTimer = setInterval(() => {
66
+ const entries = this.buffer.flush();
67
+ if (entries.length > 0) {
68
+ this.flushEntries(entries);
69
+ }
70
+ }, this.config.flushInterval * 1000);
71
+ }
72
+ /** 异步发送一条日志到缓冲区(非阻塞) */
73
+ send(entry) {
74
+ if (this.closed) {
75
+ console.warn('[logs-sdk] Client 已关闭,日志将被丢弃');
76
+ return;
77
+ }
78
+ // 补充来源信息
79
+ entry.host = this.hostname;
80
+ entry.process_id = this.pid;
81
+ entry.environment = this.config.environment;
82
+ entry.project_slug = this.config.projectSlug;
83
+ entry.service_name = this.config.serviceName || '';
84
+ this.buffer.push(entry);
85
+ }
86
+ /** 优雅关闭,等待缓冲日志全部上报 */
87
+ async close() {
88
+ this.closed = true;
89
+ if (this.flushTimer) {
90
+ clearInterval(this.flushTimer);
91
+ this.flushTimer = null;
92
+ }
93
+ // 最终刷新
94
+ const remaining = this.buffer.flush();
95
+ if (remaining.length > 0) {
96
+ try {
97
+ await this.sendBatch(remaining);
98
+ }
99
+ catch (err) {
100
+ console.error(`[logs-sdk] 关闭时上报失败:`, err, '— 保存到离线缓存');
101
+ this.offlineCache.save(remaining);
102
+ }
103
+ }
104
+ // 尝试重传离线缓存
105
+ await this.flushOffline();
106
+ }
107
+ /** 获取 Express 中间件(动态导入,避免不安装 express 时出错) */
108
+ expressMiddleware() {
109
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
110
+ const { createExpressMiddleware } = require('./middleware/express');
111
+ return createExpressMiddleware(this);
112
+ }
113
+ /** 获取 Koa 中间件 */
114
+ koaMiddleware() {
115
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
116
+ const { createKoaMiddleware } = require('./middleware/koa');
117
+ return createKoaMiddleware(this);
118
+ }
119
+ // ──────────────── 内部方法 ────────────────
120
+ /** 异步发送一批日志(包装重试) */
121
+ async flushEntries(entries) {
122
+ try {
123
+ await (0, retry_1.retryWithBackoff)(() => this.sendBatch(entries), {
124
+ maxRetries: this.config.maxRetries,
125
+ });
126
+ }
127
+ catch (err) {
128
+ console.error(`[logs-sdk] 上报失败 (数量=${entries.length}):`, err, '— 保存到离线缓存');
129
+ this.offlineCache.save(entries);
130
+ }
131
+ }
132
+ /** 重传离线缓存的日志 */
133
+ async flushOffline() {
134
+ if (this.offlineCache.pendingCount() === 0)
135
+ return;
136
+ console.log(`[logs-sdk] 检测到 ${this.offlineCache.pendingCount()} 个离线缓存文件,开始重传...`);
137
+ await this.offlineCache.flushAll((entries) => this.sendBatch(entries));
138
+ console.log('[logs-sdk] 离线缓存重传完成');
139
+ }
140
+ /** HTTP POST 批量发送日志 */
141
+ async sendBatch(entries) {
142
+ const body = JSON.stringify({ logs: entries });
143
+ const controller = new AbortController();
144
+ const timeout = setTimeout(() => controller.abort(), 15000);
145
+ try {
146
+ const resp = await fetch(this.config.endpoint, {
147
+ method: 'POST',
148
+ headers: {
149
+ 'Content-Type': 'application/json',
150
+ 'X-API-Key': this.config.apiKey,
151
+ 'X-API-Secret': this.config.apiSecret,
152
+ 'X-SDK-Version': VERSION,
153
+ 'X-SDK-Type': 'node',
154
+ 'User-Agent': `logs-sdk-js/${VERSION}`,
155
+ },
156
+ body,
157
+ signal: controller.signal,
158
+ });
159
+ if (resp.status !== 200 && resp.status !== 201) {
160
+ throw new Error(`服务端返回异常状态码: ${resp.status}`);
161
+ }
162
+ }
163
+ finally {
164
+ clearTimeout(timeout);
165
+ }
166
+ }
167
+ /** 以下方法公开给 middleware 使用 */
168
+ get configResolved() {
169
+ return this.config;
170
+ }
171
+ get host() {
172
+ return this.hostname;
173
+ }
174
+ }
175
+ exports.LogSDK = LogSDK;
176
+ /** 合并默认配置 */
177
+ function resolveConfig(cfg) {
178
+ return {
179
+ endpoint: cfg.endpoint,
180
+ apiKey: cfg.apiKey,
181
+ apiSecret: cfg.apiSecret,
182
+ projectSlug: cfg.projectSlug,
183
+ environment: cfg.environment || 'production',
184
+ serviceName: cfg.serviceName || '',
185
+ bufferSize: cfg.bufferSize || 1000,
186
+ flushInterval: cfg.flushInterval || 5,
187
+ maxRetries: cfg.maxRetries || 3,
188
+ maxBodySize: cfg.maxBodySize || 4096,
189
+ maxStackSize: cfg.maxStackSize || 8192,
190
+ };
191
+ }
192
+ /** 生成 UUID v7(32 位十六进制无连字符) */
193
+ function newLogUUID() {
194
+ return (0, uuid_1.v7)().replaceAll('-', '');
195
+ }
196
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { LogSDK, newLogUUID } from './client';
2
+ export { RingBuffer } from './buffer';
3
+ export { OfflineCache } from './offline';
4
+ export { retryWithBackoff } from './retry';
5
+ export type { LogSDKConfig, LogEntry, ClientType, ErrorType, ResolvedConfig, } from './types';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,YAAY,EACV,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,SAAS,EACT,cAAc,GACf,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ // 日志管理平台 Node.js SDK 入口
3
+ // 提供 Express/Koa 中间件,一行代码接入日志采集
4
+ //
5
+ // 使用方法:
6
+ //
7
+ // import { LogSDK } from '@xiaohao0725/logs-sdk';
8
+ //
9
+ // const logger = new LogSDK({
10
+ // endpoint: 'https://api.logs.codexs.cn/api/v1/ingest/logs',
11
+ // apiKey: 'clog_pk_xxx',
12
+ // apiSecret: 'clog_sk_xxx',
13
+ // projectSlug: 'my-project',
14
+ // environment: 'production',
15
+ // });
16
+ //
17
+ // app.use(logger.expressMiddleware()); // Express
18
+ // app.use(logger.koaMiddleware()); // Koa
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.retryWithBackoff = exports.OfflineCache = exports.RingBuffer = exports.newLogUUID = exports.LogSDK = void 0;
21
+ var client_1 = require("./client");
22
+ Object.defineProperty(exports, "LogSDK", { enumerable: true, get: function () { return client_1.LogSDK; } });
23
+ Object.defineProperty(exports, "newLogUUID", { enumerable: true, get: function () { return client_1.newLogUUID; } });
24
+ var buffer_1 = require("./buffer");
25
+ Object.defineProperty(exports, "RingBuffer", { enumerable: true, get: function () { return buffer_1.RingBuffer; } });
26
+ var offline_1 = require("./offline");
27
+ Object.defineProperty(exports, "OfflineCache", { enumerable: true, get: function () { return offline_1.OfflineCache; } });
28
+ var retry_1 = require("./retry");
29
+ Object.defineProperty(exports, "retryWithBackoff", { enumerable: true, get: function () { return retry_1.retryWithBackoff; } });
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,wBAAwB;AACxB,gCAAgC;AAChC,EAAE;AACF,QAAQ;AACR,EAAE;AACF,oDAAoD;AACpD,EAAE;AACF,gCAAgC;AAChC,iEAAiE;AACjE,6BAA6B;AAC7B,gCAAgC;AAChC,iCAAiC;AACjC,iCAAiC;AACjC,QAAQ;AACR,EAAE;AACF,qDAAqD;AACrD,iDAAiD;;;AAEjD,mCAA8C;AAArC,gGAAA,MAAM,OAAA;AAAE,oGAAA,UAAU,OAAA;AAC3B,mCAAsC;AAA7B,oGAAA,UAAU,OAAA;AACnB,qCAAyC;AAAhC,uGAAA,YAAY,OAAA;AACrB,iCAA2C;AAAlC,yGAAA,gBAAgB,OAAA"}
@@ -0,0 +1,8 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ import type { LogSDK } from '../client';
3
+ /**
4
+ * 创建 Express 日志采集中间件。
5
+ * 自动采集:请求头/体、响应头/体、客户端信息、错误堆栈、耗时统计。
6
+ */
7
+ export declare function createExpressMiddleware(sdk: LogSDK): (req: Request, res: Response, next: NextFunction) => void;
8
+ //# sourceMappingURL=express.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAIxC;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,IAGzC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UA6CxD"}
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createExpressMiddleware = createExpressMiddleware;
4
+ const client_1 = require("../client");
5
+ /**
6
+ * 创建 Express 日志采集中间件。
7
+ * 自动采集:请求头/体、响应头/体、客户端信息、错误堆栈、耗时统计。
8
+ */
9
+ function createExpressMiddleware(sdk) {
10
+ const config = sdk.configResolved;
11
+ return (req, res, next) => {
12
+ const entryUUID = (0, client_1.newLogUUID)();
13
+ const startTime = Date.now();
14
+ const startHrTime = process.hrtime.bigint();
15
+ // 读取请求体
16
+ const reqBody = captureRequestBody(req, config.maxBodySize);
17
+ // 包装 res.end 以捕获响应体
18
+ const origEnd = res.end;
19
+ const origWrite = res.write;
20
+ const chunks = [];
21
+ res.write = ((chunk, encoding, callback) => {
22
+ if (chunk) {
23
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
24
+ }
25
+ return origWrite.call(res, chunk, encoding, callback);
26
+ });
27
+ res.end = ((chunk, encoding, callback) => {
28
+ if (chunk) {
29
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
30
+ }
31
+ const respBody = Buffer.concat(chunks).toString('utf-8');
32
+ const durationMs = Number(process.hrtime.bigint() - startHrTime) / 1_000_000;
33
+ const entry = buildExpressEntry(req, res, entryUUID, startTime, durationMs, reqBody, respBody, config, sdk.host);
34
+ if (res.statusCode >= 500) {
35
+ entry.is_error = true;
36
+ entry.tls_version = req.connection?.getTlsinfo?.()?.protocol || "";
37
+ entry.tls_cipher = req.connection?.getTlsinfo?.()?.cipher?.name || "";
38
+ entry.proto = String(req.httpVersion);
39
+ entry.api_version = extractAPIVersion(req.path);
40
+ entry.referer = req.get("referer") || "";
41
+ entry.request_id = entryUUID.slice(0, 8);
42
+ entry.error_type = 'http_error';
43
+ }
44
+ sdk.send(entry);
45
+ return origEnd.call(res, chunk, encoding, callback);
46
+ });
47
+ next();
48
+ };
49
+ }
50
+ /** 从 Express Request 构建 LogEntry */
51
+ function buildExpressEntry(req, res, uuid, startTime, durationMs, reqBody, respBody, config, host) {
52
+ const scheme = req.protocol || (req.secure ? 'https' : 'http');
53
+ const fullURL = `${scheme}://${req.hostname || req.get('host')}${req.originalUrl}`;
54
+ return {
55
+ uuid,
56
+ timestamp: new Date(startTime).toISOString(),
57
+ duration_ms: Math.round(durationMs),
58
+ method: req.method,
59
+ scheme,
60
+ full_url: fullURL,
61
+ host_header: req.get('host') || '',
62
+ path: req.path,
63
+ query_string: Object.keys(req.query).length > 0 ? JSON.stringify(req.query) : '',
64
+ origin: detectOrigin(req),
65
+ request_headers: sanitizeHeaders(req.headers),
66
+ request_body: truncate(reqBody, config.maxBodySize),
67
+ request_body_size: Buffer.byteLength(reqBody),
68
+ content_type: req.get('content-type') || '',
69
+ status_code: res.statusCode,
70
+ response_headers: sanitizeHeaders(res.getHeaders()),
71
+ response_body: truncate(respBody, config.maxBodySize),
72
+ response_body_size: Buffer.byteLength(respBody),
73
+ client_ip: realClientIP(req),
74
+ client_ip_chain: req.get('x-forwarded-for') || '',
75
+ client_type: detectClientType(req),
76
+ client_port: 0,
77
+ user_agent: req.get('user-agent') || '',
78
+ is_error: false,
79
+ error_message: '',
80
+ error_type: '',
81
+ error_stack: '',
82
+ trace_id: req.get('x-trace-id') || uuid,
83
+ span_id: uuid,
84
+ parent_span_id: req.get('x-parent-span-id') || '',
85
+ user_id: req.get('x-user-id') || '',
86
+ session_id: req.get('x-session-id') || '',
87
+ project_slug: config.projectSlug,
88
+ environment: config.environment,
89
+ service_name: config.serviceName || '',
90
+ host,
91
+ process_id: String(process.pid),
92
+ tags: {},
93
+ };
94
+ }
95
+ function realClientIP(req) {
96
+ const xff = req.get('x-forwarded-for');
97
+ if (xff)
98
+ return xff.split(',')[0].trim();
99
+ const xri = req.get('x-real-ip');
100
+ if (xri)
101
+ return xri;
102
+ return req.ip || req.socket.remoteAddress || '';
103
+ }
104
+ function detectClientType(req) {
105
+ const ct = req.get('x-client-type');
106
+ if (ct)
107
+ return ct;
108
+ const ua = (req.get('user-agent') || '').toLowerCase();
109
+ if (ua.includes('micromessenger') || ua.includes('miniprogram'))
110
+ return 'miniprogram';
111
+ if (req.get('x-caller-service'))
112
+ return 'server';
113
+ const referer = req.get('referer');
114
+ const origin = req.get('origin');
115
+ if ((referer || origin) && (ua.includes('mozilla') || ua.includes('chrome') || ua.includes('safari') || ua.includes('firefox'))) {
116
+ return 'web';
117
+ }
118
+ return 'other';
119
+ }
120
+ function detectOrigin(req) {
121
+ switch (detectClientType(req)) {
122
+ case 'web': return (req.get('referer') || req.get('origin') || '');
123
+ case 'miniprogram': return `miniprogram:${req.get('x-miniprogram-appid') || ''}${req.get('x-miniprogram-path') || ''}`;
124
+ case 'app': return `app:${req.get('x-app-name') || ''}/${req.get('x-app-version') || ''}/${req.get('x-app-scene') || ''}`;
125
+ case 'server': return `server:${req.get('x-caller-service') || ''}/${req.get('x-caller-version') || ''}`;
126
+ default: return 'unknown';
127
+ }
128
+ }
129
+ function sanitizeHeaders(headers) {
130
+ const safe = {};
131
+ for (const [k, v] of Object.entries(headers)) {
132
+ if (v === undefined || v === null)
133
+ continue;
134
+ const val = Array.isArray(v) ? v.join(', ') : String(v);
135
+ if (['authorization', 'cookie', 'set-cookie'].includes(k.toLowerCase())) {
136
+ safe[k] = val.length > 20 ? val.slice(0, 15) + '...' : '***';
137
+ continue;
138
+ }
139
+ safe[k] = val;
140
+ }
141
+ return JSON.stringify(safe);
142
+ }
143
+ function captureRequestBody(req, maxSize) {
144
+ try {
145
+ if (req.body) {
146
+ if (typeof req.body === 'string')
147
+ return truncate(req.body, maxSize);
148
+ return truncate(JSON.stringify(req.body), maxSize);
149
+ }
150
+ }
151
+ catch { /* 忽略无法读取的请求体 */ }
152
+ return '';
153
+ }
154
+ function truncate(s, maxLen) {
155
+ if (s.length <= maxLen)
156
+ return s;
157
+ return s.slice(0, maxLen) + '...[truncated]';
158
+ }
159
+ function extractAPIVersion(path) { const m = path.match(/\/api\/(v\d+)\//); return m ? m[1] : ""; }
160
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Context, Next } from 'koa';
2
+ import type { LogSDK } from '../client';
3
+ /**
4
+ * 创建 Koa 日志采集中间件。
5
+ */
6
+ export declare function createKoaMiddleware(sdk: LogSDK): (ctx: Context, next: Next) => Promise<void>;
7
+ //# sourceMappingURL=koa.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"koa.d.ts","sourceRoot":"","sources":["../../src/middleware/koa.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAIxC;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,IAG/B,KAAK,OAAO,EAAE,MAAM,IAAI,mBAwCvC"}
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createKoaMiddleware = createKoaMiddleware;
4
+ const client_1 = require("../client");
5
+ /**
6
+ * 创建 Koa 日志采集中间件。
7
+ */
8
+ function createKoaMiddleware(sdk) {
9
+ const config = sdk.configResolved;
10
+ return async (ctx, next) => {
11
+ const entryUUID = (0, client_1.newLogUUID)();
12
+ const startTime = Date.now();
13
+ const startHrTime = process.hrtime.bigint();
14
+ const reqBody = captureKoaRequestBody(ctx, config.maxBodySize);
15
+ // 捕获响应体
16
+ const chunks = [];
17
+ const origWrite = ctx.res.write;
18
+ const origEnd = ctx.res.end;
19
+ ctx.res.write = ((chunk, encoding, callback) => {
20
+ if (chunk)
21
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
22
+ return origWrite.call(ctx.res, chunk, encoding, callback);
23
+ });
24
+ ctx.res.end = ((chunk, encoding, callback) => {
25
+ if (chunk)
26
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
27
+ const respBody = Buffer.concat(chunks).toString('utf-8');
28
+ const durationMs = Number(process.hrtime.bigint() - startHrTime) / 1_000_000;
29
+ const entry = buildKoaEntry(ctx, entryUUID, startTime, durationMs, reqBody, respBody, config, sdk.host);
30
+ entry.tls_version = ctx.req.connection?.getTlsinfo?.()?.protocol || "";
31
+ entry.tls_cipher = ctx.req.connection?.getTlsinfo?.()?.cipher?.name || "";
32
+ entry.proto = String(ctx.req.httpVersion);
33
+ entry.api_version = extractKoaVersion(ctx.path);
34
+ entry.referer = ctx.get("referer") || "";
35
+ entry.request_id = entryUUID.slice(0, 8);
36
+ if (ctx.status >= 500) {
37
+ entry.is_error = true;
38
+ entry.error_type = 'http_error';
39
+ }
40
+ sdk.send(entry);
41
+ return origEnd.call(ctx.res, chunk, encoding, callback);
42
+ });
43
+ await next();
44
+ };
45
+ }
46
+ function buildKoaEntry(ctx, uuid, startTime, durationMs, reqBody, respBody, config, host) {
47
+ const scheme = ctx.protocol || (ctx.secure ? 'https' : 'http');
48
+ const fullURL = `${scheme}://${ctx.host}${ctx.url}`;
49
+ return {
50
+ uuid,
51
+ timestamp: new Date(startTime).toISOString(),
52
+ duration_ms: Math.round(durationMs),
53
+ method: ctx.method,
54
+ scheme,
55
+ full_url: fullURL,
56
+ host_header: ctx.host || '',
57
+ path: ctx.path,
58
+ query_string: ctx.querystring || '',
59
+ origin: detectKoaOrigin(ctx),
60
+ request_headers: sanitizeKoaHeaders(ctx.headers),
61
+ request_body: truncate(reqBody, config.maxBodySize),
62
+ request_body_size: Buffer.byteLength(reqBody),
63
+ content_type: ctx.get('content-type') || '',
64
+ status_code: ctx.status,
65
+ response_headers: sanitizeKoaHeaders(ctx.response.headers),
66
+ response_body: truncate(respBody, config.maxBodySize),
67
+ response_body_size: Buffer.byteLength(respBody),
68
+ client_ip: ctx.ip || ctx.request.ip || '',
69
+ client_ip_chain: ctx.get('x-forwarded-for') || '',
70
+ client_type: detectKoaClientType(ctx),
71
+ client_port: 0,
72
+ user_agent: ctx.get('user-agent') || '',
73
+ is_error: false,
74
+ error_message: '',
75
+ error_type: '',
76
+ error_stack: '',
77
+ trace_id: ctx.get('x-trace-id') || uuid,
78
+ span_id: uuid,
79
+ parent_span_id: ctx.get('x-parent-span-id') || '',
80
+ user_id: ctx.get('x-user-id') || '',
81
+ session_id: ctx.get('x-session-id') || '',
82
+ project_slug: config.projectSlug,
83
+ environment: config.environment,
84
+ service_name: config.serviceName || '',
85
+ host,
86
+ process_id: String(process.pid),
87
+ };
88
+ }
89
+ function detectKoaClientType(ctx) {
90
+ const ct = ctx.get('x-client-type');
91
+ if (ct)
92
+ return ct;
93
+ const ua = (ctx.get('user-agent') || '').toLowerCase();
94
+ if (ua.includes('micromessenger') || ua.includes('miniprogram'))
95
+ return 'miniprogram';
96
+ if (ctx.get('x-caller-service'))
97
+ return 'server';
98
+ const referer = ctx.get('referer');
99
+ const origin = ctx.get('origin');
100
+ if ((referer || origin) && (ua.includes('mozilla') || ua.includes('chrome') || ua.includes('safari') || ua.includes('firefox'))) {
101
+ return 'web';
102
+ }
103
+ return 'other';
104
+ }
105
+ function detectKoaOrigin(ctx) {
106
+ switch (detectKoaClientType(ctx)) {
107
+ case 'web': return (ctx.get('referer') || ctx.get('origin') || '');
108
+ case 'miniprogram': return `miniprogram:${ctx.get('x-miniprogram-appid') || ''}${ctx.get('x-miniprogram-path') || ''}`;
109
+ case 'app': return `app:${ctx.get('x-app-name') || ''}/${ctx.get('x-app-version') || ''}/${ctx.get('x-app-scene') || ''}`;
110
+ case 'server': return `server:${ctx.get('x-caller-service') || ''}/${ctx.get('x-caller-version') || ''}`;
111
+ default: return 'unknown';
112
+ }
113
+ }
114
+ function sanitizeKoaHeaders(headers) {
115
+ const safe = {};
116
+ for (const [k, v] of Object.entries(headers)) {
117
+ if (v === undefined || v === null)
118
+ continue;
119
+ const val = Array.isArray(v) ? v.join(', ') : String(v);
120
+ if (['authorization', 'cookie', 'set-cookie'].includes(k.toLowerCase())) {
121
+ safe[k] = val.length > 20 ? val.slice(0, 15) + '...' : '***';
122
+ continue;
123
+ }
124
+ safe[k] = val;
125
+ }
126
+ return JSON.stringify(safe);
127
+ }
128
+ function captureKoaRequestBody(ctx, maxSize) {
129
+ try {
130
+ const body = ctx.request.body;
131
+ if (body) {
132
+ if (typeof body === 'string')
133
+ return truncate(body, maxSize);
134
+ return truncate(JSON.stringify(body), maxSize);
135
+ }
136
+ }
137
+ catch { /* ignore */ }
138
+ return '';
139
+ }
140
+ function truncate(s, maxLen) {
141
+ if (s.length <= maxLen)
142
+ return s;
143
+ return s.slice(0, maxLen) + '...[truncated]';
144
+ }
145
+ function extractKoaVersion(path) { const m = path.match(/\/api\/(v\d+)\//); return m ? m[1] : ""; }
146
+ //# sourceMappingURL=koa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"koa.js","sourceRoot":"","sources":["../../src/middleware/koa.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { LogEntry } from './types';
2
+ export declare class OfflineCache {
3
+ private dir;
4
+ private maxSize;
5
+ private maxAge;
6
+ private enabled;
7
+ constructor(dir?: string);
8
+ /** 保存一批日志到离线缓存 */
9
+ save(entries: LogEntry[]): void;
10
+ /** 读取所有离线缓存,通过回调发送,成功则删除 */
11
+ flushAll(sendFn: (entries: LogEntry[]) => Promise<void>): Promise<void>;
12
+ /** 返回待重传的文件数 */
13
+ pendingCount(): number;
14
+ enable(): void;
15
+ disable(): void;
16
+ private cleanup;
17
+ }
18
+ //# sourceMappingURL=offline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offline.d.ts","sourceRoot":"","sources":["../src/offline.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAU;gBAEb,GAAG,CAAC,EAAE,MAAM;IAUxB,kBAAkB;IAClB,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI;IAY/B,4BAA4B;IACtB,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B7E,gBAAgB;IAChB,YAAY,IAAI,MAAM;IAMtB,MAAM;IACN,OAAO;IAEP,OAAO,CAAC,OAAO;CAsBhB"}
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.OfflineCache = void 0;
37
+ // 离线缓存 — 网络故障时缓存到本地文件,恢复后自动重传
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const os = __importStar(require("os"));
41
+ class OfflineCache {
42
+ dir;
43
+ maxSize;
44
+ maxAge;
45
+ enabled;
46
+ constructor(dir) {
47
+ this.dir = dir || path.join(os.tmpdir(), 'logs-sdk-offline');
48
+ this.maxSize = 50 * 1024 * 1024; // 50MB
49
+ this.maxAge = 24 * 60 * 60 * 1000; // 24h
50
+ this.enabled = true;
51
+ if (!fs.existsSync(this.dir)) {
52
+ fs.mkdirSync(this.dir, { recursive: true });
53
+ }
54
+ }
55
+ /** 保存一批日志到离线缓存 */
56
+ save(entries) {
57
+ if (!this.enabled || entries.length === 0)
58
+ return;
59
+ this.cleanup();
60
+ const filename = path.join(this.dir, `offline-${new Date().toISOString().replace(/[:.]/g, '-')}.json`);
61
+ try {
62
+ fs.writeFileSync(filename, JSON.stringify(entries), 'utf-8');
63
+ console.log(`[logs-sdk] 离线缓存已保存: ${filename} (${entries.length} 条)`);
64
+ }
65
+ catch (err) {
66
+ console.error('[logs-sdk] 离线缓存保存失败:', err);
67
+ }
68
+ }
69
+ /** 读取所有离线缓存,通过回调发送,成功则删除 */
70
+ async flushAll(sendFn) {
71
+ let files = [];
72
+ try {
73
+ files = fs.readdirSync(this.dir)
74
+ .filter(f => f.startsWith('offline-') && f.endsWith('.json'))
75
+ .map(f => path.join(this.dir, f));
76
+ }
77
+ catch {
78
+ return;
79
+ }
80
+ if (files.length === 0)
81
+ return;
82
+ for (const file of files) {
83
+ try {
84
+ const stat = fs.statSync(file);
85
+ if (Date.now() - stat.mtimeMs > this.maxAge) {
86
+ fs.unlinkSync(file);
87
+ console.log(`[logs-sdk] 过期离线缓存已删除: ${file}`);
88
+ continue;
89
+ }
90
+ const data = fs.readFileSync(file, 'utf-8');
91
+ const entries = JSON.parse(data);
92
+ await sendFn(entries);
93
+ fs.unlinkSync(file);
94
+ console.log(`[logs-sdk] 离线缓存已重传: ${file} (${entries.length} 条)`);
95
+ }
96
+ catch (err) {
97
+ console.error(`[logs-sdk] 离线缓存重传失败: ${file}`, err);
98
+ return; // 保留文件,下次重试
99
+ }
100
+ }
101
+ }
102
+ /** 返回待重传的文件数 */
103
+ pendingCount() {
104
+ try {
105
+ return fs.readdirSync(this.dir).filter(f => f.startsWith('offline-')).length;
106
+ }
107
+ catch {
108
+ return 0;
109
+ }
110
+ }
111
+ enable() { this.enabled = true; }
112
+ disable() { this.enabled = false; }
113
+ cleanup() {
114
+ let files = [];
115
+ try {
116
+ files = fs.readdirSync(this.dir).map(f => path.join(this.dir, f));
117
+ }
118
+ catch {
119
+ return;
120
+ }
121
+ let totalSize = 0;
122
+ const stats = [];
123
+ for (const f of files) {
124
+ try {
125
+ const st = fs.statSync(f);
126
+ totalSize += st.size;
127
+ stats.push({ file: f, mtime: st.mtimeMs, size: st.size });
128
+ }
129
+ catch { /* skip */ }
130
+ }
131
+ stats.sort((a, b) => a.mtime - b.mtime);
132
+ for (const s of stats) {
133
+ if (totalSize <= this.maxSize)
134
+ break;
135
+ try {
136
+ fs.unlinkSync(s.file);
137
+ totalSize -= s.size;
138
+ }
139
+ catch { /* skip */ }
140
+ }
141
+ }
142
+ }
143
+ exports.OfflineCache = OfflineCache;
144
+ //# sourceMappingURL=offline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offline.js","sourceRoot":"","sources":["../src/offline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface RetryConfig {
2
+ maxRetries: number;
3
+ baseDelay: number;
4
+ maxDelay: number;
5
+ }
6
+ /**
7
+ * 使用指数退避策略重试执行异步函数。
8
+ * 重试间隔: baseDelay * 2^attempt,最大不超过 maxDelay。
9
+ */
10
+ export declare function retryWithBackoff<T>(fn: () => Promise<T>, config?: Partial<RetryConfig>): Promise<T>;
11
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAQD;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAChC,OAAO,CAAC,CAAC,CAAC,CAqBZ"}
package/dist/retry.js ADDED
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ // 指数退避重试策略
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.retryWithBackoff = retryWithBackoff;
5
+ const defaultRetryConfig = {
6
+ maxRetries: 3,
7
+ baseDelay: 500, // 500ms
8
+ maxDelay: 10000, // 10s
9
+ };
10
+ /**
11
+ * 使用指数退避策略重试执行异步函数。
12
+ * 重试间隔: baseDelay * 2^attempt,最大不超过 maxDelay。
13
+ */
14
+ async function retryWithBackoff(fn, config = {}) {
15
+ const cfg = { ...defaultRetryConfig, ...config };
16
+ let lastError;
17
+ for (let attempt = 0; attempt <= cfg.maxRetries; attempt++) {
18
+ if (attempt > 0) {
19
+ const delay = Math.min(cfg.baseDelay * Math.pow(2, attempt - 1), cfg.maxDelay);
20
+ await sleep(delay);
21
+ }
22
+ try {
23
+ return await fn();
24
+ }
25
+ catch (err) {
26
+ lastError = err;
27
+ }
28
+ }
29
+ throw lastError;
30
+ }
31
+ function sleep(ms) {
32
+ return new Promise((resolve) => setTimeout(resolve, ms));
33
+ }
34
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":";AAAA,WAAW;;AAkBX,4CAwBC;AAlCD,MAAM,kBAAkB,GAAgB;IACtC,UAAU,EAAE,CAAC;IACb,SAAS,EAAE,GAAG,EAAI,QAAQ;IAC1B,QAAQ,EAAE,KAAK,EAAG,MAAM;CACzB,CAAC;AAEF;;;GAGG;AACI,KAAK,UAAU,gBAAgB,CACpC,EAAoB,EACpB,SAA+B,EAAE;IAEjC,MAAM,GAAG,GAAG,EAAE,GAAG,kBAAkB,EAAE,GAAG,MAAM,EAAE,CAAC;IACjD,IAAI,SAAkB,CAAC;IAEvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QAC3D,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,EACxC,GAAG,CAAC,QAAQ,CACb,CAAC;YACF,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QAED,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,CAAC;QAClB,CAAC;IACH,CAAC;IAED,MAAM,SAAS,CAAC;AAClB,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,83 @@
1
+ /** SDK 客户端配置 */
2
+ export interface LogSDKConfig {
3
+ /** 日志上报地址,如 "https://api.logs.codexs.cn/api/v1/ingest/logs" */
4
+ endpoint: string;
5
+ /** SDK 认证密钥(公钥) */
6
+ apiKey: string;
7
+ /** SDK 认证密钥(私钥),用于请求签名 */
8
+ apiSecret: string;
9
+ /** 项目短标识 */
10
+ projectSlug: string;
11
+ /** 当前运行环境:production/staging/development,默认 "production" */
12
+ environment?: 'production' | 'staging' | 'development';
13
+ /** 微服务名称 */
14
+ serviceName?: string;
15
+ /** 本地缓冲容量,默认 1000,满 80% 自动 flush */
16
+ bufferSize?: number;
17
+ /** 定时刷新间隔(秒),默认 5 */
18
+ flushInterval?: number;
19
+ /** 最大重试次数,默认 3 */
20
+ maxRetries?: number;
21
+ /** 请求/响应体最大采集大小(字节),默认 4096 */
22
+ maxBodySize?: number;
23
+ /** 错误堆栈最大采集大小(字节),默认 8192 */
24
+ maxStackSize?: number;
25
+ }
26
+ /** 客户端类型 */
27
+ export type ClientType = 'web' | 'miniprogram' | 'app' | 'server' | 'other';
28
+ /** 错误类型 */
29
+ export type ErrorType = 'panic' | 'business_error' | 'http_error' | 'timeout';
30
+ /** 日志条目 — 与 Go SDK / ClickHouse 表完全对齐 */
31
+ export interface LogEntry {
32
+ uuid: string;
33
+ timestamp: string;
34
+ duration_ms: number;
35
+ method: string;
36
+ scheme: string;
37
+ full_url: string;
38
+ host_header: string;
39
+ path: string;
40
+ query_string: string;
41
+ origin: string;
42
+ request_headers: string;
43
+ request_body: string;
44
+ request_body_size: number;
45
+ content_type: string;
46
+ status_code: number;
47
+ response_headers: string;
48
+ response_body: string;
49
+ response_body_size: number;
50
+ client_ip: string;
51
+ client_ip_chain: string;
52
+ client_type: ClientType;
53
+ client_port: number;
54
+ user_agent: string;
55
+ is_error: boolean;
56
+ error_message: string;
57
+ error_type: ErrorType | '';
58
+ error_stack: string;
59
+ panic_location?: string;
60
+ trace_id: string;
61
+ span_id: string;
62
+ parent_span_id: string;
63
+ user_id: string;
64
+ session_id: string;
65
+ project_slug: string;
66
+ environment: string;
67
+ service_name: string;
68
+ host: string;
69
+ process_id: string;
70
+ tls_version?: string;
71
+ tls_cipher?: string;
72
+ proto?: string;
73
+ api_version?: string;
74
+ referer?: string;
75
+ upstream_status?: number;
76
+ latency_breakdown?: string;
77
+ request_id?: string;
78
+ tags?: Record<string, unknown>;
79
+ }
80
+ /** 内部配置(已合并默认值) */
81
+ export interface ResolvedConfig extends Required<LogSDKConfig> {
82
+ }
83
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ // SDK 核心类型定义 — 与 Go SDK 完全对齐
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,6BAA6B"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@xiaohao0725/logs-sdk",
3
+ "version": "0.3.3",
4
+ "description": "日志管理平台 Node.js SDK,提供 Express/Koa 中间件,自动采集 HTTP 请求日志并上报",
5
+ "publishConfig": {
6
+ "access": "public",
7
+ "registry": "https://registry.npmjs.org"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "keywords": [
20
+ "logs",
21
+ "sdk",
22
+ "middleware",
23
+ "express",
24
+ "koa",
25
+ "logging"
26
+ ],
27
+ "license": "UNLICENSED",
28
+ "dependencies": {
29
+ "uuid": "^11.1.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/express": "^5.0.1",
33
+ "@types/koa": "^2.15.0",
34
+ "@types/node": "^24.12.3",
35
+ "@types/uuid": "^10.0.0",
36
+ "typescript": "~5.8.0"
37
+ },
38
+ "peerDependencies": {
39
+ "express": "^4.0.0 || ^5.0.0",
40
+ "koa": "^2.0.0"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "express": {
44
+ "optional": true
45
+ },
46
+ "koa": {
47
+ "optional": true
48
+ }
49
+ },
50
+ "engines": {
51
+ "node": ">=18.0.0"
52
+ }
53
+ }