@done-coding/output-node 0.1.0 → 0.1.1
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 +67 -12
- package/es/index.mjs +203 -274
- package/package.json +6 -3
- package/types/index.d.ts +8 -46
package/README.md
CHANGED
|
@@ -16,7 +16,8 @@ Node.js 环境下的同构输出工具包,基于 @done-coding/output-core 核
|
|
|
16
16
|
- ⚡ **高性能** - 异步日志写入,可配置缓冲区大小
|
|
17
17
|
- 🔧 **完整的错误处理** - 输入验证、配置验证、文件权限检查
|
|
18
18
|
- 📦 **完整类型支持** - 100% TypeScript 类型定义和类型推导
|
|
19
|
-
-
|
|
19
|
+
- 🔇 **动态静默控制** - 支持运行时动态控制输出静默,基于类型的条件静默
|
|
20
|
+
- 🎯 **智能切换同步** - 支持控制台和日志文件之间的智能切换和同步
|
|
20
21
|
- 📋 **TABLE 类型特殊处理** - 智能表格数据展示和 JSON 序列化
|
|
21
22
|
|
|
22
23
|
## 快速开始
|
|
@@ -76,6 +77,22 @@ logger.error("发生错误");
|
|
|
76
77
|
5. **框架兼容** - 与现代框架(NestJS、Express 等)完美兼容
|
|
77
78
|
6. **极简 API** - 最少化的配置参数,易于使用
|
|
78
79
|
|
|
80
|
+
### 内置实现
|
|
81
|
+
|
|
82
|
+
#### 控制台输出驱动
|
|
83
|
+
|
|
84
|
+
- **基础实现**: `console.log` + `chalk` 颜色支持
|
|
85
|
+
- **颜色配置**: 支持自定义颜色映射和禁用颜色
|
|
86
|
+
- **TABLE 类型**: 自动调用 `console.table` 进行表格展示
|
|
87
|
+
- **错误处理**: 颜色格式化失败时自动降级到无颜色输出
|
|
88
|
+
|
|
89
|
+
#### 日志文件输出驱动
|
|
90
|
+
|
|
91
|
+
- **基础实现**: `pino` + `sonic-boom` 高性能日志写入
|
|
92
|
+
- **缓冲机制**: 可配置缓冲区大小,支持同步/异步写入
|
|
93
|
+
- **临终保护**: 使用 `signal-exit` 实现非侵入式进程退出监听
|
|
94
|
+
- **内置控制台**: 自动提供 `outputConsoleFn`,基于 pino 输出到控制台
|
|
95
|
+
|
|
79
96
|
## API 文档
|
|
80
97
|
|
|
81
98
|
### createOutputConsole
|
|
@@ -94,12 +111,12 @@ function createOutputConsole(
|
|
|
94
111
|
|
|
95
112
|
| 参数 | 类型 | 默认值 | 说明 |
|
|
96
113
|
| ----------------------- | ------------------------------------- | ------ | -------------------- |
|
|
97
|
-
| options.
|
|
114
|
+
| options.isSilent | (type) => boolean | - | 动态静默控制函数 |
|
|
98
115
|
| options.enableColor | boolean | true | 是否启用颜色输出 |
|
|
99
116
|
| options.colorMap | Record<OutputConsoleTypeEnum, string> | - | 自定义颜色映射 |
|
|
100
117
|
| options.isSwitchLogFile | (type) => boolean | - | 切换到日志文件的条件 |
|
|
101
118
|
| options.isSyncToLogFile | (type) => boolean | - | 同步到日志文件的条件 |
|
|
102
|
-
| options.outputFileFn |
|
|
119
|
+
| options.outputFileFn | OutputConsoleRaw | - | 日志文件输出函数 |
|
|
103
120
|
|
|
104
121
|
**返回值:** OutputConsole 混合类型实例
|
|
105
122
|
|
|
@@ -108,7 +125,8 @@ function createOutputConsole(
|
|
|
108
125
|
```typescript
|
|
109
126
|
const output = createOutputConsole({
|
|
110
127
|
enableColor: true,
|
|
111
|
-
|
|
128
|
+
isSilent: (type) =>
|
|
129
|
+
type === OutputConsoleTypeEnum.DEBUG && !process.env.DEBUG,
|
|
112
130
|
});
|
|
113
131
|
|
|
114
132
|
output.info("信息");
|
|
@@ -133,11 +151,10 @@ function createOutputLogFile(
|
|
|
133
151
|
| 参数 | 类型 | 默认值 | 说明 |
|
|
134
152
|
| ----------------------- | ----------------- | ------ | -------------------- |
|
|
135
153
|
| options.logFilePath | string | - | 日志文件路径(必传) |
|
|
136
|
-
| options.
|
|
154
|
+
| options.isSilent | (type) => boolean | - | 动态静默控制函数 |
|
|
137
155
|
| options.sync | boolean | false | 是否同步写入 |
|
|
138
156
|
| options.bufferSize | number | 4096 | 缓冲区大小(字节) |
|
|
139
157
|
| options.isSwitchConsole | (type) => boolean | - | 切换到控制台的条件 |
|
|
140
|
-
| options.outputConsoleFn | OutputConsole | - | 控制台输出函数 |
|
|
141
158
|
|
|
142
159
|
**返回值:** OutputLogFile 混合类型实例
|
|
143
160
|
|
|
@@ -182,6 +199,33 @@ logger.error("数据库连接失败");
|
|
|
182
199
|
|
|
183
200
|
## 进阶使用
|
|
184
201
|
|
|
202
|
+
### 动态静默控制
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import {
|
|
206
|
+
createOutputConsole,
|
|
207
|
+
OutputConsoleTypeEnum,
|
|
208
|
+
} from "@done-coding/output-node";
|
|
209
|
+
|
|
210
|
+
const output = createOutputConsole({
|
|
211
|
+
// 动态控制静默:只在调试模式下显示 DEBUG 信息
|
|
212
|
+
isSilent: (type) => {
|
|
213
|
+
if (type === OutputConsoleTypeEnum.DEBUG) {
|
|
214
|
+
return !process.env.DEBUG;
|
|
215
|
+
}
|
|
216
|
+
// 生产环境下静默所有 SKIP 类型
|
|
217
|
+
if (type === OutputConsoleTypeEnum.SKIP) {
|
|
218
|
+
return process.env.NODE_ENV === "production";
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
output.debug("调试信息"); // 只在 DEBUG=true 时显示
|
|
225
|
+
output.skip("跳过信息"); // 生产环境下不显示
|
|
226
|
+
output.info("普通信息"); // 总是显示
|
|
227
|
+
```
|
|
228
|
+
|
|
185
229
|
### 切换和同步逻辑
|
|
186
230
|
|
|
187
231
|
```typescript
|
|
@@ -201,7 +245,10 @@ const output = createOutputConsole({
|
|
|
201
245
|
isSwitchLogFile: (type) => type === OutputConsoleTypeEnum.ERROR,
|
|
202
246
|
// 警告级别同步到日志文件(控制台和文件都显示)
|
|
203
247
|
isSyncToLogFile: (type) => type === OutputConsoleTypeEnum.WARN,
|
|
204
|
-
outputFileFn:
|
|
248
|
+
outputFileFn: (type, ...messages) => {
|
|
249
|
+
// 将控制台类型映射到日志文件类型并输出
|
|
250
|
+
fileLogger(type, ...messages);
|
|
251
|
+
},
|
|
205
252
|
});
|
|
206
253
|
|
|
207
254
|
output.info("普通信息"); // 只在控制台显示
|
|
@@ -283,11 +330,11 @@ logger.info("应用启动");
|
|
|
283
330
|
|
|
284
331
|
### 测试覆盖率
|
|
285
332
|
|
|
286
|
-
- **语句覆盖率**: 99.
|
|
287
|
-
- **分支覆盖率**:
|
|
288
|
-
- **函数覆盖率**: 97.
|
|
289
|
-
- **行覆盖率**: 99.
|
|
290
|
-
- **测试数量**:
|
|
333
|
+
- **语句覆盖率**: 99.35%
|
|
334
|
+
- **分支覆盖率**: 97.63%
|
|
335
|
+
- **函数覆盖率**: 97.5%
|
|
336
|
+
- **行覆盖率**: 99.35%
|
|
337
|
+
- **测试数量**: 181 个测试,全部通过
|
|
291
338
|
|
|
292
339
|
### 本地开发
|
|
293
340
|
|
|
@@ -319,6 +366,14 @@ pnpm build
|
|
|
319
366
|
|
|
320
367
|
## 常见问题
|
|
321
368
|
|
|
369
|
+
**Q: 为什么 Node 包不需要传入 `outputImpl` 参数?**
|
|
370
|
+
|
|
371
|
+
A: Node 包自动提供了基于 `console.log + chalk` 和 `pino` 的输出实现,用户无需手动创建和传入 `outputImpl`。这是 Node 包相比 Core 包的主要优势。
|
|
372
|
+
|
|
373
|
+
**Q: 如何在生产环境中优化日志性能?**
|
|
374
|
+
|
|
375
|
+
A: 使用异步写入模式(`sync: false`),适当增加缓冲区大小(如 8KB 或 16KB),并合理配置 `isSilent` 函数来过滤不必要的日志输出。
|
|
376
|
+
|
|
322
377
|
**Q: 如何在 NestJS 中使用?**
|
|
323
378
|
|
|
324
379
|
A: 可以在 NestJS 的 OnModuleInit 和 OnApplicationShutdown 钩子中使用,临终落盘保护会自动处理进程退出时的日志刷新。
|
package/es/index.mjs
CHANGED
|
@@ -1,95 +1,93 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { OutputConsoleTypeEnum as
|
|
3
|
-
import { OutputConsoleTypeEnum as
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import { onExit as
|
|
8
|
-
class
|
|
9
|
-
constructor(
|
|
10
|
-
super(`无效的输出类型: ${
|
|
2
|
+
import { OutputConsoleTypeEnum as u, OutputLogFileTypeEnum as a, handleTableTypeConsole as w, createOutputConsole as D, createOutputLogFile as A } from "@done-coding/output-core";
|
|
3
|
+
import { OutputConsoleTypeEnum as le, OutputLogFileTypeEnum as fe } from "@done-coding/output-core";
|
|
4
|
+
import d from "chalk";
|
|
5
|
+
import O from "pino";
|
|
6
|
+
import h from "node:fs";
|
|
7
|
+
import { onExit as P } from "signal-exit";
|
|
8
|
+
class L extends Error {
|
|
9
|
+
constructor(r, t) {
|
|
10
|
+
super(`无效的输出类型: ${r}。有效的类型包括: ${t.join(", ")}`), this.name = "InvalidOutputTypeError";
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
class
|
|
14
|
-
constructor(
|
|
15
|
-
super(`配置错误: ${
|
|
13
|
+
class g extends Error {
|
|
14
|
+
constructor(r) {
|
|
15
|
+
super(`配置错误: ${r}`), this.name = "InvalidConfigurationError";
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
class
|
|
19
|
-
constructor(
|
|
20
|
-
super(`文件权限不足: 无法${
|
|
18
|
+
class re extends Error {
|
|
19
|
+
constructor(r, t) {
|
|
20
|
+
super(`文件权限不足: 无法${t}文件 "${r}"`), this.name = "FilePermissionError";
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
class
|
|
24
|
-
constructor(
|
|
25
|
-
super(`驱动初始化失败: ${
|
|
23
|
+
class C extends Error {
|
|
24
|
+
constructor(r, t) {
|
|
25
|
+
super(`驱动初始化失败: ${r}${t ? ` - ${t.message}` : ""}`), this.name = "DriverInitializationError", t && (this.cause = t);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
function
|
|
29
|
-
const
|
|
30
|
-
(
|
|
28
|
+
function _(e) {
|
|
29
|
+
const r = Object.values(u).filter(
|
|
30
|
+
(t) => typeof t == "number"
|
|
31
31
|
);
|
|
32
|
-
if (typeof e != "number" || !
|
|
33
|
-
const
|
|
34
|
-
(
|
|
32
|
+
if (typeof e != "number" || !r.includes(e)) {
|
|
33
|
+
const t = Object.keys(u).filter(
|
|
34
|
+
(o) => isNaN(Number(o))
|
|
35
35
|
);
|
|
36
|
-
throw new
|
|
36
|
+
throw new L(e, t);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
function
|
|
40
|
-
const
|
|
41
|
-
(
|
|
39
|
+
function U(e) {
|
|
40
|
+
const r = Object.values(a).filter(
|
|
41
|
+
(t) => typeof t == "number"
|
|
42
42
|
);
|
|
43
|
-
if (typeof e != "number" || !
|
|
44
|
-
const
|
|
45
|
-
(
|
|
43
|
+
if (typeof e != "number" || !r.includes(e)) {
|
|
44
|
+
const t = Object.keys(a).filter(
|
|
45
|
+
(o) => isNaN(Number(o))
|
|
46
46
|
);
|
|
47
|
-
throw new
|
|
47
|
+
throw new L(e, t);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
function
|
|
51
|
-
for (const
|
|
52
|
-
if (!(
|
|
53
|
-
throw new
|
|
50
|
+
function T(e, r) {
|
|
51
|
+
for (const t of r)
|
|
52
|
+
if (!(t in e) || e[t] === void 0)
|
|
53
|
+
throw new g(`缺少必需字段: ${t}`);
|
|
54
54
|
}
|
|
55
|
-
function
|
|
55
|
+
function M(e) {
|
|
56
56
|
if (typeof e != "string" || e.trim() === "")
|
|
57
|
-
throw new
|
|
57
|
+
throw new g("文件路径必须是非空字符串");
|
|
58
58
|
if (/[<>:"|?*]/.test(e))
|
|
59
|
-
throw new
|
|
59
|
+
throw new g(`文件路径包含非法字符: ${e}`);
|
|
60
60
|
}
|
|
61
|
-
function
|
|
61
|
+
function c(e, r) {
|
|
62
62
|
try {
|
|
63
63
|
return e();
|
|
64
|
-
} catch (
|
|
65
|
-
return
|
|
64
|
+
} catch (t) {
|
|
65
|
+
return r ? r(t) : void 0;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
silent: !1,
|
|
68
|
+
const R = {
|
|
69
|
+
// isSilent 是可选的,不需要默认值
|
|
71
70
|
/** 默认启用颜色输出:是 */
|
|
72
71
|
enableColor: !0
|
|
73
|
-
},
|
|
74
|
-
[
|
|
75
|
-
[
|
|
76
|
-
[
|
|
77
|
-
[
|
|
78
|
-
[
|
|
79
|
-
[
|
|
80
|
-
[
|
|
81
|
-
[
|
|
82
|
-
},
|
|
72
|
+
}, $ = {
|
|
73
|
+
[u.DEBUG]: "gray",
|
|
74
|
+
[u.SKIP]: "dim",
|
|
75
|
+
[u.INFO]: "white",
|
|
76
|
+
[u.TABLE]: "cyan",
|
|
77
|
+
[u.STAGE]: "blue",
|
|
78
|
+
[u.SUCCESS]: "greenBright",
|
|
79
|
+
[u.WARN]: "yellow",
|
|
80
|
+
[u.ERROR]: "redBright"
|
|
81
|
+
}, x = {
|
|
83
82
|
/** 默认颜色格式化失败时的回退颜色 */
|
|
84
83
|
fallbackColor: "white"
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
silent: !1,
|
|
84
|
+
}, m = {
|
|
85
|
+
// isSilent 是可选的,不需要默认值
|
|
88
86
|
/** 默认同步写入:关闭(异步写入) */
|
|
89
87
|
sync: !1,
|
|
90
88
|
/** 默认缓冲区大小:4KB */
|
|
91
89
|
bufferSize: 4096
|
|
92
|
-
},
|
|
90
|
+
}, b = {
|
|
93
91
|
/** 默认日志级别:trace */
|
|
94
92
|
level: "trace",
|
|
95
93
|
/** 默认时间格式:yyyy-mm-dd HH:MM:ss */
|
|
@@ -100,7 +98,7 @@ const I = {
|
|
|
100
98
|
messageFormat: "{msg}",
|
|
101
99
|
/** 默认文件输出颜色:关闭 */
|
|
102
100
|
colorize: !1
|
|
103
|
-
},
|
|
101
|
+
}, E = {
|
|
104
102
|
/** 最小缓冲区大小:1KB */
|
|
105
103
|
MIN_SIZE: 1024,
|
|
106
104
|
/** 默认缓冲区大小:4KB */
|
|
@@ -109,26 +107,24 @@ const I = {
|
|
|
109
107
|
RECOMMENDED_SIZE: 8192,
|
|
110
108
|
/** 最大缓冲区大小:64KB */
|
|
111
109
|
MAX_SIZE: 65536
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
silent: !1,
|
|
110
|
+
}, z = {
|
|
111
|
+
// isSilent 是可选的,不需要默认值
|
|
115
112
|
/** 默认启用颜色输出:是 */
|
|
116
113
|
enableColor: !0
|
|
117
|
-
},
|
|
118
|
-
|
|
119
|
-
silent: !1,
|
|
114
|
+
}, F = {
|
|
115
|
+
// isSilent 是可选的,不需要默认值
|
|
120
116
|
/** 默认同步写入:关闭(异步写入) */
|
|
121
117
|
sync: !1,
|
|
122
118
|
/** 默认缓冲区大小:4KB */
|
|
123
119
|
bufferSize: 4096
|
|
124
|
-
},
|
|
120
|
+
}, te = {
|
|
125
121
|
/** 默认静默模式:是(避免控制台输出) */
|
|
126
122
|
silentMode: !0,
|
|
127
123
|
/** 默认最大重试次数:3次 */
|
|
128
124
|
maxRetries: 3,
|
|
129
125
|
/** 默认重试间隔:100ms */
|
|
130
126
|
retryInterval: 100
|
|
131
|
-
},
|
|
127
|
+
}, oe = {
|
|
132
128
|
/** 默认错误处理模式:静默处理 */
|
|
133
129
|
silentMode: !0,
|
|
134
130
|
/** 默认错误重试次数:2次 */
|
|
@@ -136,277 +132,210 @@ const I = {
|
|
|
136
132
|
/** 默认错误重试延迟:50ms */
|
|
137
133
|
retryDelay: 50
|
|
138
134
|
};
|
|
139
|
-
function
|
|
135
|
+
function G(e) {
|
|
140
136
|
const {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
} = e, o = { ...B, ...i };
|
|
137
|
+
enableColor: r = R.enableColor,
|
|
138
|
+
colorMap: t
|
|
139
|
+
} = e, o = { ...$, ...t };
|
|
145
140
|
try {
|
|
146
|
-
if (
|
|
147
|
-
for (const [
|
|
148
|
-
if (
|
|
149
|
-
throw new Error(`颜色值必须是字符串: ${
|
|
141
|
+
if (T(e, []), t) {
|
|
142
|
+
for (const [n, i] of Object.entries(t))
|
|
143
|
+
if (_(Number(n)), typeof i != "string")
|
|
144
|
+
throw new Error(`颜色值必须是字符串: ${i}`);
|
|
150
145
|
}
|
|
151
|
-
} catch (
|
|
152
|
-
throw new
|
|
146
|
+
} catch (n) {
|
|
147
|
+
throw new C("控制台驱动", n);
|
|
153
148
|
}
|
|
154
|
-
return (
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
if (s === c.TABLE) {
|
|
158
|
-
a(() => Z(...l));
|
|
149
|
+
return (n, ...i) => {
|
|
150
|
+
if (c(() => _(n)), n === u.TABLE) {
|
|
151
|
+
c(() => w(...i));
|
|
159
152
|
return;
|
|
160
153
|
}
|
|
161
|
-
const
|
|
162
|
-
() =>
|
|
163
|
-
() =>
|
|
164
|
-
) :
|
|
165
|
-
|
|
154
|
+
const l = o[n] || x.fallbackColor, f = i.map((s) => typeof s == "string" && r ? c(
|
|
155
|
+
() => l in d && typeof d[l] == "function" ? d[l](s) : d.white(s),
|
|
156
|
+
() => s
|
|
157
|
+
) : s);
|
|
158
|
+
c(() => console.log(...f));
|
|
166
159
|
};
|
|
167
160
|
}
|
|
168
|
-
const
|
|
169
|
-
let
|
|
170
|
-
function
|
|
171
|
-
for (const { logger: e, destination:
|
|
161
|
+
const N = /* @__PURE__ */ new Set();
|
|
162
|
+
let I = !1;
|
|
163
|
+
function Z() {
|
|
164
|
+
for (const { logger: e, destination: r } of N)
|
|
172
165
|
try {
|
|
173
|
-
e.info("进程退出,日志刷新完成"),
|
|
166
|
+
e.info("进程退出,日志刷新完成"), B(r);
|
|
174
167
|
} catch {
|
|
175
168
|
}
|
|
176
|
-
|
|
169
|
+
H();
|
|
177
170
|
}
|
|
178
|
-
function
|
|
179
|
-
if (
|
|
171
|
+
function B(e) {
|
|
172
|
+
if (v(e))
|
|
180
173
|
try {
|
|
181
|
-
e.flushSync(),
|
|
182
|
-
} catch (
|
|
183
|
-
if (
|
|
174
|
+
e.flushSync(), j(e);
|
|
175
|
+
} catch (r) {
|
|
176
|
+
if (r instanceof Error && r.message.includes("sonic boom is not ready yet"))
|
|
184
177
|
return;
|
|
185
178
|
}
|
|
186
179
|
}
|
|
187
|
-
function
|
|
188
|
-
const
|
|
189
|
-
if (typeof
|
|
180
|
+
function j(e) {
|
|
181
|
+
const r = e.fd;
|
|
182
|
+
if (typeof r == "number" && r > 0)
|
|
190
183
|
try {
|
|
191
|
-
|
|
184
|
+
h.fsyncSync(r);
|
|
192
185
|
} catch {
|
|
193
186
|
}
|
|
194
187
|
}
|
|
195
|
-
function
|
|
188
|
+
function v(e) {
|
|
196
189
|
if (!e || !("flushSync" in e) || typeof e.flushSync != "function")
|
|
197
190
|
return !1;
|
|
198
|
-
const
|
|
199
|
-
if (
|
|
200
|
-
return
|
|
201
|
-
const
|
|
202
|
-
return typeof
|
|
191
|
+
const r = e;
|
|
192
|
+
if (r.constructor && r.constructor.name === "SonicBoom")
|
|
193
|
+
return k(r);
|
|
194
|
+
const t = r.fd;
|
|
195
|
+
return typeof t == "number" ? t > 0 || t === 1 || t === 2 : !(r.destroyed || r.closed || r.writable === !1);
|
|
203
196
|
}
|
|
204
|
-
function
|
|
197
|
+
function k(e) {
|
|
205
198
|
return !(!e.fd || e.fd === null || e.fd === void 0 || e.fd < 0 || e._writing === !0 || e.destroyed === !0 || e._reopening === !0 || e._ending === !0 || e._asyncDrainScheduled === !0 || e._buf && e._buf.length > 0 && e._writing);
|
|
206
199
|
}
|
|
207
|
-
function
|
|
200
|
+
function H() {
|
|
208
201
|
try {
|
|
209
|
-
process.stdout.fd !== void 0 && typeof process.stdout.fd == "number" &&
|
|
202
|
+
process.stdout.fd !== void 0 && typeof process.stdout.fd == "number" && h.fsyncSync(process.stdout.fd);
|
|
210
203
|
} catch {
|
|
211
204
|
}
|
|
212
205
|
try {
|
|
213
|
-
process.stderr.fd !== void 0 && typeof process.stderr.fd == "number" &&
|
|
206
|
+
process.stderr.fd !== void 0 && typeof process.stderr.fd == "number" && h.fsyncSync(process.stderr.fd);
|
|
214
207
|
} catch {
|
|
215
208
|
}
|
|
216
209
|
}
|
|
217
|
-
function
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}),
|
|
210
|
+
function X() {
|
|
211
|
+
I || (P(() => {
|
|
212
|
+
Z();
|
|
213
|
+
}), I = !0);
|
|
221
214
|
}
|
|
222
|
-
function
|
|
223
|
-
|
|
215
|
+
function V({
|
|
216
|
+
logger: e,
|
|
217
|
+
destination: r
|
|
218
|
+
}) {
|
|
219
|
+
N.add({ logger: e, destination: r }), X();
|
|
224
220
|
}
|
|
225
|
-
function
|
|
221
|
+
function W(e) {
|
|
226
222
|
const {
|
|
227
|
-
silent: t = g.silent,
|
|
228
223
|
logFilePath: r,
|
|
229
|
-
sync:
|
|
230
|
-
bufferSize: o =
|
|
224
|
+
sync: t = m.sync,
|
|
225
|
+
bufferSize: o = m.bufferSize
|
|
231
226
|
} = e;
|
|
232
227
|
try {
|
|
233
|
-
if (
|
|
228
|
+
if (T(e, []), r !== void 0 && M(r), o <= 0)
|
|
234
229
|
throw new Error(`缓冲区大小必须大于0: ${o}`);
|
|
235
|
-
if (o <
|
|
230
|
+
if (o < E.MIN_SIZE || o > E.MAX_SIZE)
|
|
236
231
|
throw new Error(
|
|
237
|
-
`缓冲区大小必须在 ${
|
|
232
|
+
`缓冲区大小必须在 ${E.MIN_SIZE} - ${E.MAX_SIZE} 字节范围内: ${o}`
|
|
238
233
|
);
|
|
239
|
-
} catch (
|
|
240
|
-
throw new
|
|
234
|
+
} catch (f) {
|
|
235
|
+
throw new C("日志文件驱动", f);
|
|
241
236
|
}
|
|
242
|
-
const
|
|
243
|
-
let l = null, f = null;
|
|
244
|
-
if (!t) {
|
|
245
|
-
const n = $({
|
|
246
|
-
logFilePath: s,
|
|
247
|
-
sync: i,
|
|
248
|
-
bufferSize: o
|
|
249
|
-
});
|
|
250
|
-
l = n.logger, f = n.destination, l && f && P(l, f);
|
|
251
|
-
}
|
|
252
|
-
return (n, ...u) => {
|
|
253
|
-
if (a(() => w(n)), t || !l)
|
|
254
|
-
return;
|
|
255
|
-
const y = u.length === 1 ? u[0] : u.join(" ");
|
|
256
|
-
a(() => {
|
|
257
|
-
const U = (E[n] || "INFO").toLowerCase();
|
|
258
|
-
l[U](y);
|
|
259
|
-
});
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
function Y(e) {
|
|
263
|
-
const {
|
|
264
|
-
silent: t = g.silent,
|
|
237
|
+
const i = K({
|
|
265
238
|
logFilePath: r,
|
|
266
|
-
sync:
|
|
267
|
-
bufferSize: o
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
const s = r || D();
|
|
280
|
-
let l = null, f = null;
|
|
281
|
-
if (!t) {
|
|
282
|
-
const n = $({
|
|
283
|
-
logFilePath: s,
|
|
284
|
-
sync: i,
|
|
285
|
-
bufferSize: o
|
|
286
|
-
});
|
|
287
|
-
l = n.logger, f = n.destination, l && f && P(l, f);
|
|
288
|
-
}
|
|
289
|
-
return (n, ...u) => {
|
|
290
|
-
if (t || !l)
|
|
291
|
-
return;
|
|
292
|
-
const y = u.length === 1 ? u[0] : u.join(" ");
|
|
293
|
-
a(() => {
|
|
294
|
-
l.info(y);
|
|
295
|
-
});
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
function A() {
|
|
299
|
-
let e = null;
|
|
300
|
-
return e = ee().logger, (r, ...i) => {
|
|
301
|
-
if (a(() => w(r)), !e)
|
|
302
|
-
return;
|
|
303
|
-
const o = i.length === 1 ? i[0] : i.join(" ");
|
|
304
|
-
a(() => {
|
|
305
|
-
const s = (E[r] || "INFO").toLowerCase();
|
|
306
|
-
e[s](o);
|
|
239
|
+
sync: t,
|
|
240
|
+
bufferSize: o
|
|
241
|
+
});
|
|
242
|
+
V(i);
|
|
243
|
+
const { logger: l } = i;
|
|
244
|
+
return (f, ...s) => {
|
|
245
|
+
c(() => U(f));
|
|
246
|
+
const y = s.length === 1 ? s[0] : s.join(" ");
|
|
247
|
+
c(() => {
|
|
248
|
+
var S;
|
|
249
|
+
const p = (a[f] || a[a.INFO]).toLowerCase();
|
|
250
|
+
(S = l[p]) == null || S.call(l, y);
|
|
307
251
|
});
|
|
308
252
|
};
|
|
309
253
|
}
|
|
310
|
-
function
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
function $(e) {
|
|
315
|
-
const { logFilePath: t, sync: r, bufferSize: i } = e, o = h.destination({
|
|
316
|
-
dest: t,
|
|
317
|
-
sync: r,
|
|
254
|
+
function K(e) {
|
|
255
|
+
const { logFilePath: r, sync: t, bufferSize: o } = e, n = O.destination({
|
|
256
|
+
dest: r,
|
|
257
|
+
sync: t,
|
|
318
258
|
// 使用用户配置的同步/异步模式
|
|
319
|
-
bufferSize:
|
|
259
|
+
bufferSize: o,
|
|
320
260
|
// 使用用户配置的缓冲区大小
|
|
321
261
|
autoEnd: !1
|
|
322
262
|
// 始终禁用自动结束,使用我们的防御性退出处理
|
|
323
|
-
}),
|
|
324
|
-
return
|
|
325
|
-
if (
|
|
326
|
-
return
|
|
327
|
-
}, { logger:
|
|
263
|
+
}), i = n.flushSync;
|
|
264
|
+
return n.flushSync = function() {
|
|
265
|
+
if (v(n))
|
|
266
|
+
return i.call(this);
|
|
267
|
+
}, { logger: O(
|
|
328
268
|
{
|
|
329
|
-
level:
|
|
269
|
+
level: b.level
|
|
330
270
|
},
|
|
331
|
-
|
|
332
|
-
), destination:
|
|
271
|
+
n
|
|
272
|
+
), destination: n };
|
|
333
273
|
}
|
|
334
|
-
function
|
|
335
|
-
return { logger: h({
|
|
336
|
-
level: v.level
|
|
337
|
-
}), destination: process.stdout };
|
|
338
|
-
}
|
|
339
|
-
function fe(e = {}) {
|
|
274
|
+
function ne(e = {}) {
|
|
340
275
|
const {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
colorMap:
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
outputFileFn: l
|
|
347
|
-
} = e, f = X({
|
|
348
|
-
silent: t,
|
|
276
|
+
enableColor: r = z.enableColor,
|
|
277
|
+
isSilent: t,
|
|
278
|
+
colorMap: o,
|
|
279
|
+
...n
|
|
280
|
+
} = e, i = G({
|
|
349
281
|
enableColor: r,
|
|
350
|
-
colorMap:
|
|
282
|
+
colorMap: o
|
|
351
283
|
});
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
silent: t,
|
|
357
|
-
colorMap: i,
|
|
284
|
+
return D({
|
|
285
|
+
outputImpl: i,
|
|
286
|
+
isSilent: t,
|
|
287
|
+
colorMap: o,
|
|
358
288
|
enableColor: r,
|
|
359
|
-
|
|
360
|
-
isSyncToLogFile: s,
|
|
361
|
-
outputFileFn: n
|
|
289
|
+
...n
|
|
362
290
|
});
|
|
363
291
|
}
|
|
364
|
-
function
|
|
292
|
+
function ie(e) {
|
|
365
293
|
const {
|
|
366
|
-
|
|
367
|
-
|
|
294
|
+
isSilent: r,
|
|
295
|
+
// 不设置默认值,保持可选
|
|
296
|
+
logFilePath: t,
|
|
368
297
|
// 现在是必传的绝对路径参数
|
|
369
|
-
sync:
|
|
298
|
+
sync: o = F.sync,
|
|
370
299
|
// 默认异步写入
|
|
371
|
-
bufferSize:
|
|
300
|
+
bufferSize: n = F.bufferSize,
|
|
372
301
|
// 默认缓冲区大小 4KB
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
sync: i,
|
|
379
|
-
bufferSize: o
|
|
302
|
+
...i
|
|
303
|
+
} = e, l = W({
|
|
304
|
+
logFilePath: t,
|
|
305
|
+
sync: o,
|
|
306
|
+
bufferSize: n
|
|
380
307
|
});
|
|
381
|
-
let
|
|
382
|
-
return
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
outputConsoleFn:
|
|
308
|
+
let f;
|
|
309
|
+
return A({
|
|
310
|
+
outputImpl: l,
|
|
311
|
+
isSilent: r,
|
|
312
|
+
// 内部使用pino 直接输出到控制台
|
|
313
|
+
outputConsoleFn: (s, ...y) => {
|
|
314
|
+
f || (f = O({
|
|
315
|
+
level: b.level
|
|
316
|
+
}));
|
|
317
|
+
const p = { type: s, messages: y };
|
|
318
|
+
f.info(p);
|
|
319
|
+
},
|
|
320
|
+
...i
|
|
387
321
|
});
|
|
388
322
|
}
|
|
389
|
-
function ae() {
|
|
390
|
-
return A();
|
|
391
|
-
}
|
|
392
323
|
export {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
ae as createPinoConsoleOutput,
|
|
411
|
-
A as createPinoConsoleOutputImpl
|
|
324
|
+
E as BUFFER_SIZE_CONFIG,
|
|
325
|
+
$ as DEFAULT_CONSOLE_COLOR_MAP,
|
|
326
|
+
R as DEFAULT_CONSOLE_OUTPUT_IMPL_OPTIONS,
|
|
327
|
+
oe as DEFAULT_ERROR_HANDLING_CONFIG,
|
|
328
|
+
m as DEFAULT_LOG_FILE_OUTPUT_IMPL_OPTIONS,
|
|
329
|
+
z as DEFAULT_NODE_CREATE_OUTPUT_CONSOLE_OPTIONS,
|
|
330
|
+
F as DEFAULT_NODE_CREATE_OUTPUT_LOG_FILE_OPTIONS,
|
|
331
|
+
b as DEFAULT_PINO_CONFIG,
|
|
332
|
+
te as DEFAULT_PROCESS_HANDLER_CONFIG,
|
|
333
|
+
C as DriverInitializationError,
|
|
334
|
+
re as FilePermissionError,
|
|
335
|
+
g as InvalidConfigurationError,
|
|
336
|
+
L as InvalidOutputTypeError,
|
|
337
|
+
le as OutputConsoleTypeEnum,
|
|
338
|
+
fe as OutputLogFileTypeEnum,
|
|
339
|
+
ne as createOutputConsole,
|
|
340
|
+
ie as createOutputLogFile
|
|
412
341
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@done-coding/output-node",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "node相关输出",
|
|
5
5
|
"private": false,
|
|
6
6
|
"module": "es/index.mjs",
|
|
@@ -43,6 +43,9 @@
|
|
|
43
43
|
"@types/node": "^18.0.0",
|
|
44
44
|
"@types/signal-exit": "^4.0.0",
|
|
45
45
|
"@vitest/coverage-v8": "^1.6.1",
|
|
46
|
+
"chalk": "^5.3.0",
|
|
47
|
+
"pino": "^8.17.2",
|
|
48
|
+
"signal-exit": "^4.1.0",
|
|
46
49
|
"typescript": "^5.8.3",
|
|
47
50
|
"vite": "^5.0.10",
|
|
48
51
|
"vite-plugin-dts": "^3.7.0",
|
|
@@ -54,10 +57,10 @@
|
|
|
54
57
|
"signal-exit": "^4.1.0"
|
|
55
58
|
},
|
|
56
59
|
"dependencies": {
|
|
57
|
-
"@done-coding/output-core": "0.1.
|
|
60
|
+
"@done-coding/output-core": "0.1.1"
|
|
58
61
|
},
|
|
59
62
|
"engines": {
|
|
60
63
|
"node": ">=18.0.0"
|
|
61
64
|
},
|
|
62
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "87831fe924a30d5f398a6687e92f5db72d6ea71b"
|
|
63
66
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -32,12 +32,9 @@ export declare function createOutputConsole(options?: CreateOutputConsoleOptions
|
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Node.js 环境下的控制台输出选项
|
|
35
|
-
* 继承核心包选项,但不需要手动传入 outputImpl
|
|
35
|
+
* 继承核心包选项,但不需要手动传入 outputImpl
|
|
36
36
|
*/
|
|
37
|
-
export declare
|
|
38
|
-
/** 日志文件输出函数 */
|
|
39
|
-
outputFileFn?: OutputConsoleRaw;
|
|
40
|
-
}
|
|
37
|
+
export declare type CreateOutputConsoleOptions = Omit<CreateOutputConsoleOptions_2, "outputImpl">;
|
|
41
38
|
|
|
42
39
|
/**
|
|
43
40
|
* 创建日志文件输出实例 (Node.js 适配版本)
|
|
@@ -50,31 +47,18 @@ export declare function createOutputLogFile(options: CreateOutputLogFileOptions)
|
|
|
50
47
|
|
|
51
48
|
/**
|
|
52
49
|
* Node.js 环境下的日志文件输出选项
|
|
53
|
-
* 继承核心包选项,但不需要手动传入 outputImpl
|
|
50
|
+
* 继承核心包选项,但不需要手动传入 outputImpl,并且增加 Node.js 特定参数
|
|
54
51
|
* logFilePath 为必传参数,必须提供绝对路径
|
|
55
52
|
*/
|
|
56
|
-
export declare interface CreateOutputLogFileOptions extends Omit<CreateOutputLogFileOptions_2, "
|
|
53
|
+
export declare interface CreateOutputLogFileOptions extends Omit<CreateOutputLogFileOptions_2, "outputImpl" | "logFilePath" | "outputConsoleFn"> {
|
|
54
|
+
/** 日志文件是否同步写入 (默认: false,异步写入) */
|
|
55
|
+
sync?: boolean;
|
|
56
|
+
/** 异步写入是的缓冲区大小 (字节,默认: 4096) */
|
|
57
|
+
bufferSize?: number;
|
|
57
58
|
/** 日志文件绝对路径 (必传) */
|
|
58
59
|
logFilePath: string;
|
|
59
|
-
/** 输出到控制台对应的方法 */
|
|
60
|
-
outputConsoleFn?: OutputLogFileRaw;
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
/**
|
|
64
|
-
* 创建基于 pino 的控制台输出实现
|
|
65
|
-
* 用于 outputLogFile 切换到控制台输出时使用
|
|
66
|
-
*
|
|
67
|
-
* @param options 配置选项
|
|
68
|
-
* @returns 控制台输出函数(保持日志级别类型)
|
|
69
|
-
*/
|
|
70
|
-
export declare function createPinoConsoleOutput(): OutputLogFileRaw;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* 创建控制台输出实现(基于 pino)
|
|
74
|
-
* @returns 日志文件输出函数(输出到控制台)
|
|
75
|
-
*/
|
|
76
|
-
export declare function createPinoConsoleOutputImpl(): OutputLogFileRaw;
|
|
77
|
-
|
|
78
62
|
/**
|
|
79
63
|
* 默认控制台输出颜色映射
|
|
80
64
|
* 根据需求 4.2 定义的颜色方案
|
|
@@ -85,8 +69,6 @@ export declare const DEFAULT_CONSOLE_COLOR_MAP: Record<OutputConsoleTypeEnum, st
|
|
|
85
69
|
* 控制台输出实现默认配置
|
|
86
70
|
*/
|
|
87
71
|
export declare const DEFAULT_CONSOLE_OUTPUT_IMPL_OPTIONS: {
|
|
88
|
-
/** 默认静默模式:关闭 */
|
|
89
|
-
readonly silent: false;
|
|
90
72
|
/** 默认启用颜色输出:是 */
|
|
91
73
|
readonly enableColor: true;
|
|
92
74
|
};
|
|
@@ -107,8 +89,6 @@ export declare const DEFAULT_ERROR_HANDLING_CONFIG: {
|
|
|
107
89
|
* 日志文件输出实现默认配置
|
|
108
90
|
*/
|
|
109
91
|
export declare const DEFAULT_LOG_FILE_OUTPUT_IMPL_OPTIONS: {
|
|
110
|
-
/** 默认静默模式:关闭 */
|
|
111
|
-
readonly silent: false;
|
|
112
92
|
/** 默认同步写入:关闭(异步写入) */
|
|
113
93
|
readonly sync: false;
|
|
114
94
|
/** 默认缓冲区大小:4KB */
|
|
@@ -119,8 +99,6 @@ export declare const DEFAULT_LOG_FILE_OUTPUT_IMPL_OPTIONS: {
|
|
|
119
99
|
* Node.js 控制台输出创建函数默认配置
|
|
120
100
|
*/
|
|
121
101
|
export declare const DEFAULT_NODE_CREATE_OUTPUT_CONSOLE_OPTIONS: {
|
|
122
|
-
/** 默认静默模式:关闭 */
|
|
123
|
-
readonly silent: false;
|
|
124
102
|
/** 默认启用颜色输出:是 */
|
|
125
103
|
readonly enableColor: true;
|
|
126
104
|
};
|
|
@@ -129,8 +107,6 @@ export declare const DEFAULT_NODE_CREATE_OUTPUT_CONSOLE_OPTIONS: {
|
|
|
129
107
|
* Node.js 日志文件输出创建函数默认配置
|
|
130
108
|
*/
|
|
131
109
|
export declare const DEFAULT_NODE_CREATE_OUTPUT_LOG_FILE_OPTIONS: {
|
|
132
|
-
/** 默认静默模式:关闭 */
|
|
133
|
-
readonly silent: false;
|
|
134
110
|
/** 默认同步写入:关闭(异步写入) */
|
|
135
111
|
readonly sync: false;
|
|
136
112
|
/** 默认缓冲区大小:4KB */
|
|
@@ -194,20 +170,6 @@ export declare class InvalidOutputTypeError extends Error {
|
|
|
194
170
|
constructor(type: unknown, validTypes: string[]);
|
|
195
171
|
}
|
|
196
172
|
|
|
197
|
-
/**
|
|
198
|
-
* 日志文件输出实现配置选项
|
|
199
|
-
*/
|
|
200
|
-
declare interface LogFileOutputImplOptions {
|
|
201
|
-
/** 是否静默模式 */
|
|
202
|
-
silent?: boolean;
|
|
203
|
-
/** 日志文件路径 (可选,相对路径) */
|
|
204
|
-
logFilePath?: string;
|
|
205
|
-
/** 是否同步写入 (默认: false,异步写入) */
|
|
206
|
-
sync?: boolean;
|
|
207
|
-
/** 缓冲区大小 (字节,默认: 4096) */
|
|
208
|
-
bufferSize?: number;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
173
|
export { OutputConsole }
|
|
212
174
|
|
|
213
175
|
export { OutputConsoleRaw }
|