@done-coding/output-node 0.1.0-alpha.0
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/LICENSE +21 -0
- package/README.md +451 -0
- package/es/index.mjs +413 -0
- package/package.json +63 -0
- package/types/index.d.ts +226 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 JustSoSu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
# @done-coding/output-node
|
|
2
|
+
|
|
3
|
+
Node.js 环境下的同构输出工具包,基于 @done-coding/output-core 核心包构建,提供控制台输出和日志文件输出功能。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- 🎨 **丰富的控制台输出** - 支持多种输出类型和颜色配置
|
|
8
|
+
- 📝 **专业的日志文件输出** - 基于 pino 的高性能日志记录
|
|
9
|
+
- 🔄 **混合类型接口** - 支持函数调用和属性链式调用两种方式
|
|
10
|
+
- 🛡️ **临终落盘保护** - 使用 signal-exit 库实现非侵入式进程退出监听
|
|
11
|
+
- 🚨 **信号监听** - 与 NestJS 等现代框架完美兼容
|
|
12
|
+
- ⚡ **高性能** - 异步日志写入,预计算枚举映射
|
|
13
|
+
- 🔧 **完整的错误处理** - 输入验证、配置验证、文件权限检查
|
|
14
|
+
- 📦 **TypeScript 支持** - 完整的类型定义和类型推导
|
|
15
|
+
- 🎯 **输出模式切换** - 支持控制台和日志文件之间的智能切换
|
|
16
|
+
- 📋 **TABLE 类型特殊处理** - 智能表格数据展示和 JSON 序列化
|
|
17
|
+
- 🔧 **常量集中管理** - 所有配置参数的默认值统一管理
|
|
18
|
+
|
|
19
|
+
## 安装
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @done-coding/output-node
|
|
23
|
+
# 或
|
|
24
|
+
yarn add @done-coding/output-node
|
|
25
|
+
# 或
|
|
26
|
+
pnpm add @done-coding/output-node
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 快速开始
|
|
30
|
+
|
|
31
|
+
### 控制台输出
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import {
|
|
35
|
+
createOutputConsole,
|
|
36
|
+
OutputConsoleTypeEnum,
|
|
37
|
+
} from "@done-coding/output-node";
|
|
38
|
+
|
|
39
|
+
// 创建控制台输出实例
|
|
40
|
+
const outputConsole = createOutputConsole({
|
|
41
|
+
enableColor: true, // 启用颜色输出
|
|
42
|
+
silent: false, // 非静默模式
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// 函数调用方式
|
|
46
|
+
outputConsole(OutputConsoleTypeEnum.INFO, "这是一条信息");
|
|
47
|
+
outputConsole(OutputConsoleTypeEnum.SUCCESS, "操作成功!");
|
|
48
|
+
outputConsole(OutputConsoleTypeEnum.ERROR, "发生错误");
|
|
49
|
+
|
|
50
|
+
// 属性链式调用方式(推荐)
|
|
51
|
+
outputConsole.info("这是一条信息");
|
|
52
|
+
outputConsole.success("操作成功!");
|
|
53
|
+
outputConsole.error("发生错误");
|
|
54
|
+
outputConsole.warn("这是一个警告");
|
|
55
|
+
outputConsole.debug("调试信息");
|
|
56
|
+
outputConsole.stage("当前步骤");
|
|
57
|
+
outputConsole.skip("跳过此步骤");
|
|
58
|
+
|
|
59
|
+
// TABLE 类型特殊处理
|
|
60
|
+
outputConsole.table({
|
|
61
|
+
name: "张三",
|
|
62
|
+
age: 25,
|
|
63
|
+
city: "北京",
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 日志文件输出
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import {
|
|
71
|
+
createOutputLogFile,
|
|
72
|
+
OutputLogFileTypeEnum,
|
|
73
|
+
} from "@done-coding/output-node";
|
|
74
|
+
|
|
75
|
+
// 创建日志文件输出实例
|
|
76
|
+
const logger = createOutputLogFile({
|
|
77
|
+
logFilePath: "app.log", // 可选,默认自动生成
|
|
78
|
+
prettyPrint: false, // 是否美化输出
|
|
79
|
+
silent: false, // 非静默模式
|
|
80
|
+
sync: false, // 异步写入(推荐)
|
|
81
|
+
bufferSize: 4096, // 缓冲区大小
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// 函数调用方式
|
|
85
|
+
logger(OutputLogFileTypeEnum.INFO, "应用启动");
|
|
86
|
+
logger(OutputLogFileTypeEnum.ERROR, "数据库连接失败");
|
|
87
|
+
|
|
88
|
+
// 属性链式调用方式(推荐)
|
|
89
|
+
logger.info("应用启动");
|
|
90
|
+
logger.warn("内存使用率较高");
|
|
91
|
+
logger.error("数据库连接失败");
|
|
92
|
+
logger.debug("调试信息");
|
|
93
|
+
logger.trace("详细跟踪信息");
|
|
94
|
+
logger.fatal("致命错误,应用即将退出");
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 输出模式切换
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { outputLogFile } from "@done-coding/output-node";
|
|
101
|
+
|
|
102
|
+
// 支持输出到控制台
|
|
103
|
+
const logger1 = outputLogFile({
|
|
104
|
+
outputToConsole: true, // 输出到控制台
|
|
105
|
+
prettyPrint: true, // 美化输出
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// 支持输出到文件
|
|
109
|
+
const logger2 = outputLogFile({
|
|
110
|
+
outputToConsole: false, // 输出到文件
|
|
111
|
+
logFilePath: "app.log",
|
|
112
|
+
sync: true, // 同步写入
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 切换和同步逻辑
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import {
|
|
120
|
+
createOutputConsole,
|
|
121
|
+
createOutputLogFile,
|
|
122
|
+
OutputConsoleTypeEnum,
|
|
123
|
+
} from "@done-coding/output-node";
|
|
124
|
+
|
|
125
|
+
// 创建日志文件输出实例
|
|
126
|
+
const fileLogger = createOutputLogFile({ logFilePath: "error.log" });
|
|
127
|
+
|
|
128
|
+
// 创建带有切换和同步逻辑的控制台输出
|
|
129
|
+
const outputConsole = createOutputConsole({
|
|
130
|
+
enableColor: true,
|
|
131
|
+
// 错误级别切换到日志文件(不在控制台显示)
|
|
132
|
+
isSwitchLogFile: (type) => type === OutputConsoleTypeEnum.ERROR,
|
|
133
|
+
// 警告级别同步到日志文件(控制台和文件都显示)
|
|
134
|
+
isSyncToLogFile: (type) => type === OutputConsoleTypeEnum.WARN,
|
|
135
|
+
// 指定日志文件输出函数
|
|
136
|
+
outputFileFn: fileLogger,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
outputConsole.info("普通信息"); // 只在控制台显示
|
|
140
|
+
outputConsole.warn("警告信息"); // 控制台和文件都显示
|
|
141
|
+
outputConsole.error("错误信息"); // 只在文件中记录
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## API 文档
|
|
145
|
+
|
|
146
|
+
### createOutputConsole(options?)
|
|
147
|
+
|
|
148
|
+
创建控制台输出实例。
|
|
149
|
+
|
|
150
|
+
#### 参数
|
|
151
|
+
|
|
152
|
+
- `options` (可选) - 配置选项
|
|
153
|
+
- `silent?: boolean` - 是否静默模式,默认 `false`
|
|
154
|
+
- `enableColor?: boolean` - 是否启用颜色输出,默认 `true`
|
|
155
|
+
- `colorMap?: Record<OutputConsoleTypeEnum, string>` - 自定义颜色映射
|
|
156
|
+
- `isSwitchLogFile?: (type: OutputConsoleTypeEnum) => boolean` - 切换到日志文件的条件函数
|
|
157
|
+
- `isSyncToLogFile?: (type: OutputConsoleTypeEnum) => boolean` - 同步到日志文件的条件函数
|
|
158
|
+
- `outputFileFn?: OutputLogFile` - 日志文件输出函数
|
|
159
|
+
|
|
160
|
+
#### 返回值
|
|
161
|
+
|
|
162
|
+
返回 `OutputConsole` 混合类型实例,支持:
|
|
163
|
+
|
|
164
|
+
- 函数调用:`output(type, ...messages)`
|
|
165
|
+
- 属性调用:`output.info(...messages)`、`output.error(...messages)` 等
|
|
166
|
+
|
|
167
|
+
### createOutputLogFile(options?)
|
|
168
|
+
|
|
169
|
+
创建日志文件输出实例。
|
|
170
|
+
|
|
171
|
+
#### 参数
|
|
172
|
+
|
|
173
|
+
- `options` (可选) - 配置选项
|
|
174
|
+
- `silent?: boolean` - 是否静默模式,默认 `false`
|
|
175
|
+
- `logFilePath?: string` - 日志文件路径,默认自动生成
|
|
176
|
+
- `prettyPrint?: boolean` - 是否启用美化输出,默认 `false`
|
|
177
|
+
- `sync?: boolean` - 是否同步写入,默认 `false`
|
|
178
|
+
- `bufferSize?: number` - 缓冲区大小,默认 `4096`
|
|
179
|
+
|
|
180
|
+
#### 返回值
|
|
181
|
+
|
|
182
|
+
返回 `OutputLogFile` 混合类型实例,支持:
|
|
183
|
+
|
|
184
|
+
- 函数调用:`logger(type, ...messages)`
|
|
185
|
+
- 属性调用:`logger.info(...messages)`、`logger.error(...messages)` 等
|
|
186
|
+
|
|
187
|
+
### outputLogFile(options?)
|
|
188
|
+
|
|
189
|
+
创建支持输出模式切换的日志实例。
|
|
190
|
+
|
|
191
|
+
#### 参数
|
|
192
|
+
|
|
193
|
+
- `options` (可选) - 配置选项
|
|
194
|
+
- `outputToConsole?: boolean` - 是否输出到控制台,默认 `false`
|
|
195
|
+
- `prettyPrint?: boolean` - 是否美化输出,默认 `false`
|
|
196
|
+
- `logFilePath?: string` - 日志文件路径(当 `outputToConsole` 为 `false` 时)
|
|
197
|
+
- `sync?: boolean` - 是否同步写入,默认 `false`
|
|
198
|
+
- `bufferSize?: number` - 缓冲区大小,默认 `4096`
|
|
199
|
+
|
|
200
|
+
### 输出类型枚举
|
|
201
|
+
|
|
202
|
+
#### OutputConsoleTypeEnum
|
|
203
|
+
|
|
204
|
+
控制台输出类型枚举:
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
enum OutputConsoleTypeEnum {
|
|
208
|
+
DEBUG = 31, // 调试信息
|
|
209
|
+
SKIP = 32, // 跳过
|
|
210
|
+
INFO = 33, // 提示信息
|
|
211
|
+
TABLE = 34, // 表格
|
|
212
|
+
STAGE = 35, // 步骤
|
|
213
|
+
SUCCESS = 36, // 成功
|
|
214
|
+
WARN = 37, // 警告
|
|
215
|
+
ERROR = 38, // 错误
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### OutputLogFileTypeEnum
|
|
220
|
+
|
|
221
|
+
日志文件输出类型枚举(对齐 Pino 标准):
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
enum OutputLogFileTypeEnum {
|
|
225
|
+
TRACE = 10, // 跟踪级别
|
|
226
|
+
DEBUG = 20, // 调试级别
|
|
227
|
+
INFO = 30, // 信息级别
|
|
228
|
+
WARN = 40, // 警告级别
|
|
229
|
+
ERROR = 50, // 错误级别
|
|
230
|
+
FATAL = 60, // 致命错误级别
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## 高级功能
|
|
235
|
+
|
|
236
|
+
### 临终落盘保护
|
|
237
|
+
|
|
238
|
+
Node.js 包使用 signal-exit 库实现非侵入式临终落盘保护机制,确保进程退出时日志数据不丢失:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
import { createOutputLogFile } from "@done-coding/output-node";
|
|
242
|
+
|
|
243
|
+
// 创建日志实例会自动注册 signal-exit 监听器
|
|
244
|
+
const logger = createOutputLogFile({ logFilePath: "app.log" });
|
|
245
|
+
|
|
246
|
+
logger.info("应用启动");
|
|
247
|
+
// 当收到 SIGINT 或 SIGTERM 信号时,会自动刷新日志缓冲区
|
|
248
|
+
// 与 NestJS 等现代框架的关闭钩子完美兼容
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### 错误处理
|
|
252
|
+
|
|
253
|
+
包含完整的错误处理机制:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
import {
|
|
257
|
+
createOutputConsole,
|
|
258
|
+
DriverInitializationError,
|
|
259
|
+
} from "@done-coding/output-node";
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
const outputConsole = createOutputConsole({
|
|
263
|
+
bufferSize: -1, // 无效配置会抛出错误
|
|
264
|
+
});
|
|
265
|
+
} catch (error) {
|
|
266
|
+
if (error instanceof DriverInitializationError) {
|
|
267
|
+
console.error("驱动初始化失败:", error.message);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### 自定义颜色配置
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import {
|
|
276
|
+
createOutputConsole,
|
|
277
|
+
OutputConsoleTypeEnum,
|
|
278
|
+
} from "@done-coding/output-node";
|
|
279
|
+
|
|
280
|
+
const outputConsole = createOutputConsole({
|
|
281
|
+
enableColor: true,
|
|
282
|
+
colorMap: {
|
|
283
|
+
[OutputConsoleTypeEnum.INFO]: "blue",
|
|
284
|
+
[OutputConsoleTypeEnum.SUCCESS]: "greenBright",
|
|
285
|
+
[OutputConsoleTypeEnum.ERROR]: "redBright",
|
|
286
|
+
[OutputConsoleTypeEnum.WARN]: "yellow",
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### 缓冲区配置
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
import { createOutputLogFile } from "@done-coding/output-node";
|
|
295
|
+
|
|
296
|
+
// 自定义缓冲区大小
|
|
297
|
+
const logger = createOutputLogFile({
|
|
298
|
+
bufferSize: 8192, // 8KB 缓冲区
|
|
299
|
+
sync: false, // 异步写入
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// 同步写入模式(性能较低但数据安全性更高)
|
|
303
|
+
const syncLogger = createOutputLogFile({
|
|
304
|
+
sync: true, // 同步写入
|
|
305
|
+
bufferSize: 1024, // 较小的缓冲区
|
|
306
|
+
});
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### 工具函数
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import {
|
|
313
|
+
generateDefaultNodeLogFileName,
|
|
314
|
+
getConsoleTypeName,
|
|
315
|
+
getLogFileTypeName,
|
|
316
|
+
} from "@done-coding/output-node";
|
|
317
|
+
|
|
318
|
+
// 生成默认日志文件名
|
|
319
|
+
const fileName = generateDefaultNodeLogFileName();
|
|
320
|
+
console.log(fileName); // 20240131_235959-12345.log
|
|
321
|
+
|
|
322
|
+
// 获取类型名称
|
|
323
|
+
console.log(getConsoleTypeName(OutputConsoleTypeEnum.INFO)); // "INFO"
|
|
324
|
+
console.log(getLogFileTypeName(OutputLogFileTypeEnum.ERROR)); // "ERROR"
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## 最佳实践
|
|
328
|
+
|
|
329
|
+
### 1. 使用属性调用方式
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
// ✅ 推荐:属性调用方式
|
|
333
|
+
outputConsole.info("用户登录成功");
|
|
334
|
+
outputConsole.error("数据库连接失败");
|
|
335
|
+
|
|
336
|
+
// ❌ 不推荐:函数调用方式(虽然也支持)
|
|
337
|
+
outputConsole(OutputConsoleTypeEnum.INFO, "用户登录成功");
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### 2. 合理配置日志级别
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
// 开发环境
|
|
344
|
+
const devLogger = createOutputLogFile({
|
|
345
|
+
prettyPrint: true, // 美化输出便于调试
|
|
346
|
+
logFilePath: "dev.log",
|
|
347
|
+
outputToConsole: true, // 同时输出到控制台
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// 生产环境
|
|
351
|
+
const prodLogger = createOutputLogFile({
|
|
352
|
+
prettyPrint: false, // 标准 JSON 格式
|
|
353
|
+
logFilePath: `/var/log/app-${process.pid}.log`,
|
|
354
|
+
sync: false, // 异步写入提高性能
|
|
355
|
+
bufferSize: 8192, // 较大缓冲区
|
|
356
|
+
});
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### 3. 错误处理和降级
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
import { createOutputLogFile } from "@done-coding/output-node";
|
|
363
|
+
|
|
364
|
+
try {
|
|
365
|
+
const logger = createOutputLogFile({
|
|
366
|
+
logFilePath: "/protected/app.log",
|
|
367
|
+
bufferSize: 4096,
|
|
368
|
+
});
|
|
369
|
+
} catch (error) {
|
|
370
|
+
// 降级到控制台输出
|
|
371
|
+
console.warn("日志文件创建失败,降级到控制台输出");
|
|
372
|
+
const fallbackLogger = createOutputLogFile({
|
|
373
|
+
outputToConsole: true,
|
|
374
|
+
prettyPrint: true,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### 4. 性能优化
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
// 在高频输出场景下使用静默模式进行性能测试
|
|
383
|
+
const outputConsole = createOutputConsole({
|
|
384
|
+
silent: process.env.NODE_ENV === "test",
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// 批量输出时考虑使用异步日志
|
|
388
|
+
const logger = createOutputLogFile({
|
|
389
|
+
logFilePath: "batch.log",
|
|
390
|
+
prettyPrint: false, // 禁用美化以提高性能
|
|
391
|
+
sync: false, // 异步写入
|
|
392
|
+
bufferSize: 16384, // 更大的缓冲区
|
|
393
|
+
});
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### 5. TABLE 类型最佳实践
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
// ✅ 推荐:结构化数据
|
|
400
|
+
outputConsole.table([
|
|
401
|
+
{ name: "张三", age: 25, city: "北京" },
|
|
402
|
+
{ name: "李四", age: 30, city: "上海" },
|
|
403
|
+
]);
|
|
404
|
+
|
|
405
|
+
// ✅ 推荐:对象数据
|
|
406
|
+
outputConsole.table({
|
|
407
|
+
total: 100,
|
|
408
|
+
success: 95,
|
|
409
|
+
failed: 5,
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// ❌ 避免:非结构化数据
|
|
413
|
+
outputConsole.table("这不是表格数据");
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## 依赖
|
|
417
|
+
|
|
418
|
+
- `@done-coding/output-core` - 核心包
|
|
419
|
+
- `chalk` - 控制台颜色输出
|
|
420
|
+
- `pino` - 高性能日志库
|
|
421
|
+
- `pino-pretty` - 日志美化输出
|
|
422
|
+
- `signal-exit` - 非侵入式进程退出监听
|
|
423
|
+
|
|
424
|
+
## 测试覆盖率
|
|
425
|
+
|
|
426
|
+
- **语句覆盖率**: 99.51%
|
|
427
|
+
- **分支覆盖率**: 98.13%
|
|
428
|
+
- **函数覆盖率**: 97.29%
|
|
429
|
+
- **行覆盖率**: 99.51%
|
|
430
|
+
- **测试数量**: 182 个测试,全部通过
|
|
431
|
+
|
|
432
|
+
## 许可证
|
|
433
|
+
|
|
434
|
+
MIT
|
|
435
|
+
|
|
436
|
+
## 贡献
|
|
437
|
+
|
|
438
|
+
欢迎提交 Issue 和 Pull Request!
|
|
439
|
+
|
|
440
|
+
## 更新日志
|
|
441
|
+
|
|
442
|
+
### v0.0.0
|
|
443
|
+
|
|
444
|
+
- 初始版本发布
|
|
445
|
+
- 支持控制台输出和日志文件输出
|
|
446
|
+
- 实现基于 signal-exit 的临终落盘保护机制
|
|
447
|
+
- 完整的错误处理和类型推导支持
|
|
448
|
+
- 输出模式切换功能
|
|
449
|
+
- TABLE 类型特殊处理
|
|
450
|
+
- 常量集中管理
|
|
451
|
+
- 缓冲区大小配置和验证
|
package/es/index.mjs
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { OutputConsoleTypeEnum as c, OutputLogFileTypeEnum as E, handleTableTypeConsole as Z, generateTimestamp as x, createOutputConsole as z, createOutputLogFile as G } from "@done-coding/output-core";
|
|
3
|
+
import { OutputConsoleTypeEnum as pe, OutputLogFileTypeEnum as Ee, OutputTargetModeEnum as ye } from "@done-coding/output-core";
|
|
4
|
+
import p from "chalk";
|
|
5
|
+
import h from "pino";
|
|
6
|
+
import F from "node:fs";
|
|
7
|
+
import { onExit as j } from "signal-exit";
|
|
8
|
+
class N extends Error {
|
|
9
|
+
constructor(t, r) {
|
|
10
|
+
super(`无效的输出类型: ${t}。有效的类型包括: ${r.join(", ")}`), this.name = "InvalidOutputTypeError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
class S extends Error {
|
|
14
|
+
constructor(t) {
|
|
15
|
+
super(`配置错误: ${t}`), this.name = "InvalidConfigurationError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
class le extends Error {
|
|
19
|
+
constructor(t, r) {
|
|
20
|
+
super(`文件权限不足: 无法${r}文件 "${t}"`), this.name = "FilePermissionError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
class _ extends Error {
|
|
24
|
+
constructor(t, r) {
|
|
25
|
+
super(`驱动初始化失败: ${t}${r ? ` - ${r.message}` : ""}`), this.name = "DriverInitializationError", r && (this.cause = r);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function C(e) {
|
|
29
|
+
const t = Object.values(c).filter(
|
|
30
|
+
(r) => typeof r == "number"
|
|
31
|
+
);
|
|
32
|
+
if (typeof e != "number" || !t.includes(e)) {
|
|
33
|
+
const r = Object.keys(c).filter(
|
|
34
|
+
(i) => isNaN(Number(i))
|
|
35
|
+
);
|
|
36
|
+
throw new N(e, r);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function w(e) {
|
|
40
|
+
const t = Object.values(E).filter(
|
|
41
|
+
(r) => typeof r == "number"
|
|
42
|
+
);
|
|
43
|
+
if (typeof e != "number" || !t.includes(e)) {
|
|
44
|
+
const r = Object.keys(E).filter(
|
|
45
|
+
(i) => isNaN(Number(i))
|
|
46
|
+
);
|
|
47
|
+
throw new N(e, r);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function m(e, t) {
|
|
51
|
+
for (const r of t)
|
|
52
|
+
if (!(r in e) || e[r] === void 0)
|
|
53
|
+
throw new S(`缺少必需字段: ${r}`);
|
|
54
|
+
}
|
|
55
|
+
function b(e) {
|
|
56
|
+
if (typeof e != "string" || e.trim() === "")
|
|
57
|
+
throw new S("文件路径必须是非空字符串");
|
|
58
|
+
if (/[<>:"|?*]/.test(e))
|
|
59
|
+
throw new S(`文件路径包含非法字符: ${e}`);
|
|
60
|
+
}
|
|
61
|
+
function a(e, t) {
|
|
62
|
+
try {
|
|
63
|
+
return e();
|
|
64
|
+
} catch (r) {
|
|
65
|
+
return t ? t(r) : void 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const I = {
|
|
69
|
+
/** 默认静默模式:关闭 */
|
|
70
|
+
silent: !1,
|
|
71
|
+
/** 默认启用颜色输出:是 */
|
|
72
|
+
enableColor: !0
|
|
73
|
+
}, B = {
|
|
74
|
+
[c.DEBUG]: "gray",
|
|
75
|
+
[c.SKIP]: "dim",
|
|
76
|
+
[c.INFO]: "white",
|
|
77
|
+
[c.TABLE]: "cyan",
|
|
78
|
+
[c.STAGE]: "blue",
|
|
79
|
+
[c.SUCCESS]: "greenBright",
|
|
80
|
+
[c.WARN]: "yellow",
|
|
81
|
+
[c.ERROR]: "redBright"
|
|
82
|
+
}, k = {
|
|
83
|
+
/** 默认颜色格式化失败时的回退颜色 */
|
|
84
|
+
fallbackColor: "white"
|
|
85
|
+
}, g = {
|
|
86
|
+
/** 默认静默模式:关闭 */
|
|
87
|
+
silent: !1,
|
|
88
|
+
/** 默认同步写入:关闭(异步写入) */
|
|
89
|
+
sync: !1,
|
|
90
|
+
/** 默认缓冲区大小:4KB */
|
|
91
|
+
bufferSize: 4096
|
|
92
|
+
}, v = {
|
|
93
|
+
/** 默认日志级别:trace */
|
|
94
|
+
level: "trace",
|
|
95
|
+
/** 默认时间格式:yyyy-mm-dd HH:MM:ss */
|
|
96
|
+
timeFormat: "yyyy-mm-dd HH:MM:ss",
|
|
97
|
+
/** 默认忽略字段:pid,hostname */
|
|
98
|
+
ignoreFields: "pid,hostname",
|
|
99
|
+
/** 默认消息格式:{msg} */
|
|
100
|
+
messageFormat: "{msg}",
|
|
101
|
+
/** 默认文件输出颜色:关闭 */
|
|
102
|
+
colorize: !1
|
|
103
|
+
}, d = {
|
|
104
|
+
/** 最小缓冲区大小:1KB */
|
|
105
|
+
MIN_SIZE: 1024,
|
|
106
|
+
/** 默认缓冲区大小:4KB */
|
|
107
|
+
DEFAULT_SIZE: 4096,
|
|
108
|
+
/** 推荐缓冲区大小:8KB */
|
|
109
|
+
RECOMMENDED_SIZE: 8192,
|
|
110
|
+
/** 最大缓冲区大小:64KB */
|
|
111
|
+
MAX_SIZE: 65536
|
|
112
|
+
}, L = {
|
|
113
|
+
/** 默认静默模式:关闭 */
|
|
114
|
+
silent: !1,
|
|
115
|
+
/** 默认启用颜色输出:是 */
|
|
116
|
+
enableColor: !0
|
|
117
|
+
}, O = {
|
|
118
|
+
/** 默认静默模式:关闭 */
|
|
119
|
+
silent: !1,
|
|
120
|
+
/** 默认同步写入:关闭(异步写入) */
|
|
121
|
+
sync: !1,
|
|
122
|
+
/** 默认缓冲区大小:4KB */
|
|
123
|
+
bufferSize: 4096
|
|
124
|
+
}, se = {
|
|
125
|
+
/** 默认静默模式:是(避免控制台输出) */
|
|
126
|
+
silentMode: !0,
|
|
127
|
+
/** 默认最大重试次数:3次 */
|
|
128
|
+
maxRetries: 3,
|
|
129
|
+
/** 默认重试间隔:100ms */
|
|
130
|
+
retryInterval: 100
|
|
131
|
+
}, ue = {
|
|
132
|
+
/** 默认错误处理模式:静默处理 */
|
|
133
|
+
silentMode: !0,
|
|
134
|
+
/** 默认错误重试次数:2次 */
|
|
135
|
+
maxRetries: 2,
|
|
136
|
+
/** 默认错误重试延迟:50ms */
|
|
137
|
+
retryDelay: 50
|
|
138
|
+
};
|
|
139
|
+
function X(e) {
|
|
140
|
+
const {
|
|
141
|
+
silent: t = I.silent,
|
|
142
|
+
enableColor: r = I.enableColor,
|
|
143
|
+
colorMap: i
|
|
144
|
+
} = e, o = { ...B, ...i };
|
|
145
|
+
try {
|
|
146
|
+
if (m(e, []), i) {
|
|
147
|
+
for (const [s, l] of Object.entries(i))
|
|
148
|
+
if (C(Number(s)), typeof l != "string")
|
|
149
|
+
throw new Error(`颜色值必须是字符串: ${l}`);
|
|
150
|
+
}
|
|
151
|
+
} catch (s) {
|
|
152
|
+
throw new _("控制台驱动", s);
|
|
153
|
+
}
|
|
154
|
+
return (s, ...l) => {
|
|
155
|
+
if (a(() => C(s)), t)
|
|
156
|
+
return;
|
|
157
|
+
if (s === c.TABLE) {
|
|
158
|
+
a(() => Z(...l));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const f = o[s] || k.fallbackColor, n = l.map((u) => typeof u == "string" && r ? a(
|
|
162
|
+
() => f in p && typeof p[f] == "function" ? p[f](u) : p.white(u),
|
|
163
|
+
() => u
|
|
164
|
+
) : u);
|
|
165
|
+
a(() => console.log(...n));
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
const R = /* @__PURE__ */ new Set();
|
|
169
|
+
let T = !1;
|
|
170
|
+
function H() {
|
|
171
|
+
for (const { logger: e, destination: t } of R)
|
|
172
|
+
try {
|
|
173
|
+
e.info("进程退出,日志刷新完成"), V(t);
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
q();
|
|
177
|
+
}
|
|
178
|
+
function V(e) {
|
|
179
|
+
if (M(e))
|
|
180
|
+
try {
|
|
181
|
+
e.flushSync(), W(e);
|
|
182
|
+
} catch (t) {
|
|
183
|
+
if (t instanceof Error && t.message.includes("sonic boom is not ready yet"))
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function W(e) {
|
|
188
|
+
const t = e.fd;
|
|
189
|
+
if (typeof t == "number" && t > 0)
|
|
190
|
+
try {
|
|
191
|
+
F.fsyncSync(t);
|
|
192
|
+
} catch {
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function M(e) {
|
|
196
|
+
if (!e || !("flushSync" in e) || typeof e.flushSync != "function")
|
|
197
|
+
return !1;
|
|
198
|
+
const t = e;
|
|
199
|
+
if (t.constructor && t.constructor.name === "SonicBoom")
|
|
200
|
+
return K(t);
|
|
201
|
+
const r = t.fd;
|
|
202
|
+
return typeof r == "number" ? r > 0 || r === 1 || r === 2 : !(t.destroyed || t.closed || t.writable === !1);
|
|
203
|
+
}
|
|
204
|
+
function K(e) {
|
|
205
|
+
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
|
+
}
|
|
207
|
+
function q() {
|
|
208
|
+
try {
|
|
209
|
+
process.stdout.fd !== void 0 && typeof process.stdout.fd == "number" && F.fsyncSync(process.stdout.fd);
|
|
210
|
+
} catch {
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
process.stderr.fd !== void 0 && typeof process.stderr.fd == "number" && F.fsyncSync(process.stderr.fd);
|
|
214
|
+
} catch {
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function J() {
|
|
218
|
+
T || (j(() => {
|
|
219
|
+
H();
|
|
220
|
+
}), T = !0);
|
|
221
|
+
}
|
|
222
|
+
function P(e, t) {
|
|
223
|
+
R.add({ logger: e, destination: t }), J();
|
|
224
|
+
}
|
|
225
|
+
function Q(e) {
|
|
226
|
+
const {
|
|
227
|
+
silent: t = g.silent,
|
|
228
|
+
logFilePath: r,
|
|
229
|
+
sync: i = g.sync,
|
|
230
|
+
bufferSize: o = g.bufferSize
|
|
231
|
+
} = e;
|
|
232
|
+
try {
|
|
233
|
+
if (m(e, []), r !== void 0 && b(r), o <= 0)
|
|
234
|
+
throw new Error(`缓冲区大小必须大于0: ${o}`);
|
|
235
|
+
if (o < d.MIN_SIZE || o > d.MAX_SIZE)
|
|
236
|
+
throw new Error(
|
|
237
|
+
`缓冲区大小必须在 ${d.MIN_SIZE} - ${d.MAX_SIZE} 字节范围内: ${o}`
|
|
238
|
+
);
|
|
239
|
+
} catch (n) {
|
|
240
|
+
throw new _("日志文件驱动", n);
|
|
241
|
+
}
|
|
242
|
+
const s = r || D();
|
|
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,
|
|
265
|
+
logFilePath: r,
|
|
266
|
+
sync: i = g.sync,
|
|
267
|
+
bufferSize: o = g.bufferSize
|
|
268
|
+
} = e;
|
|
269
|
+
try {
|
|
270
|
+
if (m(e, []), r !== void 0 && b(r), o <= 0)
|
|
271
|
+
throw new Error(`缓冲区大小必须大于0: ${o}`);
|
|
272
|
+
if (o < d.MIN_SIZE || o > d.MAX_SIZE)
|
|
273
|
+
throw new Error(
|
|
274
|
+
`缓冲区大小必须在 ${d.MIN_SIZE} - ${d.MAX_SIZE} 字节范围内: ${o}`
|
|
275
|
+
);
|
|
276
|
+
} catch (n) {
|
|
277
|
+
throw new _("日志文件驱动", n);
|
|
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);
|
|
307
|
+
});
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function D() {
|
|
311
|
+
const e = x(), t = process.pid;
|
|
312
|
+
return `${e}-${t}.log`;
|
|
313
|
+
}
|
|
314
|
+
function $(e) {
|
|
315
|
+
const { logFilePath: t, sync: r, bufferSize: i } = e, o = h.destination({
|
|
316
|
+
dest: t,
|
|
317
|
+
sync: r,
|
|
318
|
+
// 使用用户配置的同步/异步模式
|
|
319
|
+
bufferSize: i,
|
|
320
|
+
// 使用用户配置的缓冲区大小
|
|
321
|
+
autoEnd: !1
|
|
322
|
+
// 始终禁用自动结束,使用我们的防御性退出处理
|
|
323
|
+
}), s = o.flushSync;
|
|
324
|
+
return o.flushSync = function() {
|
|
325
|
+
if (M(o))
|
|
326
|
+
return s.call(this);
|
|
327
|
+
}, { logger: h(
|
|
328
|
+
{
|
|
329
|
+
level: v.level
|
|
330
|
+
},
|
|
331
|
+
o
|
|
332
|
+
), destination: o };
|
|
333
|
+
}
|
|
334
|
+
function ee() {
|
|
335
|
+
return { logger: h({
|
|
336
|
+
level: v.level
|
|
337
|
+
}), destination: process.stdout };
|
|
338
|
+
}
|
|
339
|
+
function fe(e = {}) {
|
|
340
|
+
const {
|
|
341
|
+
silent: t = L.silent,
|
|
342
|
+
enableColor: r = L.enableColor,
|
|
343
|
+
colorMap: i,
|
|
344
|
+
isSwitchLogFile: o,
|
|
345
|
+
isSyncToLogFile: s,
|
|
346
|
+
outputFileFn: l
|
|
347
|
+
} = e, f = X({
|
|
348
|
+
silent: t,
|
|
349
|
+
enableColor: r,
|
|
350
|
+
colorMap: i
|
|
351
|
+
});
|
|
352
|
+
let n = l;
|
|
353
|
+
return !n && (o || s) && (n = Y({
|
|
354
|
+
silent: t
|
|
355
|
+
})), z(f, {
|
|
356
|
+
silent: t,
|
|
357
|
+
colorMap: i,
|
|
358
|
+
enableColor: r,
|
|
359
|
+
isSwitchLogFile: o,
|
|
360
|
+
isSyncToLogFile: s,
|
|
361
|
+
outputFileFn: n
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
function ce(e) {
|
|
365
|
+
const {
|
|
366
|
+
silent: t = O.silent,
|
|
367
|
+
logFilePath: r,
|
|
368
|
+
// 现在是必传的绝对路径参数
|
|
369
|
+
sync: i = O.sync,
|
|
370
|
+
// 默认异步写入
|
|
371
|
+
bufferSize: o = O.bufferSize,
|
|
372
|
+
// 默认缓冲区大小 4KB
|
|
373
|
+
isSwitchConsole: s,
|
|
374
|
+
outputConsoleFn: l
|
|
375
|
+
} = e, f = Q({
|
|
376
|
+
silent: t,
|
|
377
|
+
logFilePath: r,
|
|
378
|
+
sync: i,
|
|
379
|
+
bufferSize: o
|
|
380
|
+
});
|
|
381
|
+
let n = l;
|
|
382
|
+
return !n && s && (n = A()), G(f, {
|
|
383
|
+
silent: t,
|
|
384
|
+
logFilePath: r,
|
|
385
|
+
isSwitchConsole: s,
|
|
386
|
+
outputConsoleFn: n
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
function ae() {
|
|
390
|
+
return A();
|
|
391
|
+
}
|
|
392
|
+
export {
|
|
393
|
+
d as BUFFER_SIZE_CONFIG,
|
|
394
|
+
B as DEFAULT_CONSOLE_COLOR_MAP,
|
|
395
|
+
I as DEFAULT_CONSOLE_OUTPUT_IMPL_OPTIONS,
|
|
396
|
+
ue as DEFAULT_ERROR_HANDLING_CONFIG,
|
|
397
|
+
g as DEFAULT_LOG_FILE_OUTPUT_IMPL_OPTIONS,
|
|
398
|
+
L as DEFAULT_NODE_CREATE_OUTPUT_CONSOLE_OPTIONS,
|
|
399
|
+
O as DEFAULT_NODE_CREATE_OUTPUT_LOG_FILE_OPTIONS,
|
|
400
|
+
v as DEFAULT_PINO_CONFIG,
|
|
401
|
+
se as DEFAULT_PROCESS_HANDLER_CONFIG,
|
|
402
|
+
_ as DriverInitializationError,
|
|
403
|
+
le as FilePermissionError,
|
|
404
|
+
S as InvalidConfigurationError,
|
|
405
|
+
N as InvalidOutputTypeError,
|
|
406
|
+
pe as OutputConsoleTypeEnum,
|
|
407
|
+
Ee as OutputLogFileTypeEnum,
|
|
408
|
+
ye as OutputTargetModeEnum,
|
|
409
|
+
fe as createOutputConsole,
|
|
410
|
+
ce as createOutputLogFile,
|
|
411
|
+
ae as createPinoConsoleOutput,
|
|
412
|
+
A as createPinoConsoleOutputImpl
|
|
413
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@done-coding/output-node",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "node相关输出",
|
|
5
|
+
"private": false,
|
|
6
|
+
"module": "es/index.mjs",
|
|
7
|
+
"types": "types/index.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./es/index.mjs",
|
|
12
|
+
"types": "./types/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"es",
|
|
17
|
+
"lib",
|
|
18
|
+
"types"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"predev": "dc-inject",
|
|
22
|
+
"dev": "vite build -w -m hotBuild",
|
|
23
|
+
"prebuild": "dc-inject",
|
|
24
|
+
"build": "vite build",
|
|
25
|
+
"prepack": "pnpm build",
|
|
26
|
+
"test": "vitest",
|
|
27
|
+
"coverage": "vitest run --coverage"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://gitee.com/done-coding/done-coding-output.git",
|
|
32
|
+
"directory": "packages/node"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public",
|
|
36
|
+
"registry": "https://registry.npmjs.org/"
|
|
37
|
+
},
|
|
38
|
+
"author": "JustSoSu",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"sideEffects": false,
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@done-coding/cli-inject": "^0.5.17",
|
|
43
|
+
"@types/node": "^18.0.0",
|
|
44
|
+
"@types/signal-exit": "^4.0.0",
|
|
45
|
+
"@vitest/coverage-v8": "^1.6.1",
|
|
46
|
+
"typescript": "^5.8.3",
|
|
47
|
+
"vite": "^5.0.10",
|
|
48
|
+
"vite-plugin-dts": "^3.7.0",
|
|
49
|
+
"vitest": "^1.6.1"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"chalk": "^5.3.0",
|
|
53
|
+
"pino": "^8.17.2",
|
|
54
|
+
"signal-exit": "^4.1.0"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@done-coding/output-core": "0.1.0-alpha.0"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=18.0.0"
|
|
61
|
+
},
|
|
62
|
+
"gitHead": "4365181831a85aa7dd657faac9af146ad0a5739d"
|
|
63
|
+
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { CreateOutputConsoleOptions as CreateOutputConsoleOptions_2 } from '@done-coding/output-core';
|
|
2
|
+
import { CreateOutputLogFileOptions as CreateOutputLogFileOptions_2 } from '@done-coding/output-core';
|
|
3
|
+
import { OutputConsole } from '@done-coding/output-core';
|
|
4
|
+
import { OutputConsoleRaw } from '@done-coding/output-core';
|
|
5
|
+
import { OutputConsoleTypeEnum } from '@done-coding/output-core';
|
|
6
|
+
import { OutputLogFile } from '@done-coding/output-core';
|
|
7
|
+
import { OutputLogFileRaw } from '@done-coding/output-core';
|
|
8
|
+
import { OutputLogFileTypeEnum } from '@done-coding/output-core';
|
|
9
|
+
import { OutputTargetModeEnum } from '@done-coding/output-core';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 缓冲区大小配置常量
|
|
13
|
+
*/
|
|
14
|
+
export declare const BUFFER_SIZE_CONFIG: {
|
|
15
|
+
/** 最小缓冲区大小:1KB */
|
|
16
|
+
readonly MIN_SIZE: 1024;
|
|
17
|
+
/** 默认缓冲区大小:4KB */
|
|
18
|
+
readonly DEFAULT_SIZE: 4096;
|
|
19
|
+
/** 推荐缓冲区大小:8KB */
|
|
20
|
+
readonly RECOMMENDED_SIZE: 8192;
|
|
21
|
+
/** 最大缓冲区大小:64KB */
|
|
22
|
+
readonly MAX_SIZE: 65536;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 创建控制台输出实例 (Node.js 适配版本)
|
|
27
|
+
* 自动提供 console.log + chalk 的 outputImpl 实现
|
|
28
|
+
*
|
|
29
|
+
* @param options 配置选项
|
|
30
|
+
* @returns 控制台输出实例
|
|
31
|
+
*/
|
|
32
|
+
export declare function createOutputConsole(options?: CreateOutputConsoleOptions): OutputConsole;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Node.js 环境下的控制台输出选项
|
|
36
|
+
* 继承核心包选项,但不需要手动传入 outputImpl,并且 silent 是可选的
|
|
37
|
+
*/
|
|
38
|
+
export declare interface CreateOutputConsoleOptions extends Omit<CreateOutputConsoleOptions_2, "outputFileFn"> {
|
|
39
|
+
/** 日志文件输出函数 */
|
|
40
|
+
outputFileFn?: OutputConsoleRaw;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 创建日志文件输出实例 (Node.js 适配版本)
|
|
45
|
+
* 自动提供 pino 的 outputImpl 实现
|
|
46
|
+
*
|
|
47
|
+
* @param options 配置选项 (logFilePath 为必传绝对路径)
|
|
48
|
+
* @returns 日志文件输出实例
|
|
49
|
+
*/
|
|
50
|
+
export declare function createOutputLogFile(options: CreateOutputLogFileOptions): OutputLogFile;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Node.js 环境下的日志文件输出选项
|
|
54
|
+
* 继承核心包选项,但不需要手动传入 outputImpl,并且 silent 是可选的
|
|
55
|
+
* logFilePath 为必传参数,必须提供绝对路径
|
|
56
|
+
*/
|
|
57
|
+
export declare interface CreateOutputLogFileOptions extends Omit<CreateOutputLogFileOptions_2, "logFilePath" | "outputConsoleFn">, Pick<LogFileOutputImplOptions, "sync" | "bufferSize"> {
|
|
58
|
+
/** 日志文件绝对路径 (必传) */
|
|
59
|
+
logFilePath: string;
|
|
60
|
+
/** 输出到控制台对应的方法 */
|
|
61
|
+
outputConsoleFn?: OutputLogFileRaw;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 创建基于 pino 的控制台输出实现
|
|
66
|
+
* 用于 outputLogFile 切换到控制台输出时使用
|
|
67
|
+
*
|
|
68
|
+
* @param options 配置选项
|
|
69
|
+
* @returns 控制台输出函数(保持日志级别类型)
|
|
70
|
+
*/
|
|
71
|
+
export declare function createPinoConsoleOutput(): OutputLogFileRaw;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 创建控制台输出实现(基于 pino)
|
|
75
|
+
* @returns 日志文件输出函数(输出到控制台)
|
|
76
|
+
*/
|
|
77
|
+
export declare function createPinoConsoleOutputImpl(): OutputLogFileRaw;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 默认控制台输出颜色映射
|
|
81
|
+
* 根据需求 4.2 定义的颜色方案
|
|
82
|
+
*/
|
|
83
|
+
export declare const DEFAULT_CONSOLE_COLOR_MAP: Record<OutputConsoleTypeEnum, string>;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 控制台输出实现默认配置
|
|
87
|
+
*/
|
|
88
|
+
export declare const DEFAULT_CONSOLE_OUTPUT_IMPL_OPTIONS: {
|
|
89
|
+
/** 默认静默模式:关闭 */
|
|
90
|
+
readonly silent: false;
|
|
91
|
+
/** 默认启用颜色输出:是 */
|
|
92
|
+
readonly enableColor: true;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 错误处理默认配置
|
|
97
|
+
*/
|
|
98
|
+
export declare const DEFAULT_ERROR_HANDLING_CONFIG: {
|
|
99
|
+
/** 默认错误处理模式:静默处理 */
|
|
100
|
+
readonly silentMode: true;
|
|
101
|
+
/** 默认错误重试次数:2次 */
|
|
102
|
+
readonly maxRetries: 2;
|
|
103
|
+
/** 默认错误重试延迟:50ms */
|
|
104
|
+
readonly retryDelay: 50;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 日志文件输出实现默认配置
|
|
109
|
+
*/
|
|
110
|
+
export declare const DEFAULT_LOG_FILE_OUTPUT_IMPL_OPTIONS: {
|
|
111
|
+
/** 默认静默模式:关闭 */
|
|
112
|
+
readonly silent: false;
|
|
113
|
+
/** 默认同步写入:关闭(异步写入) */
|
|
114
|
+
readonly sync: false;
|
|
115
|
+
/** 默认缓冲区大小:4KB */
|
|
116
|
+
readonly bufferSize: 4096;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Node.js 控制台输出创建函数默认配置
|
|
121
|
+
*/
|
|
122
|
+
export declare const DEFAULT_NODE_CREATE_OUTPUT_CONSOLE_OPTIONS: {
|
|
123
|
+
/** 默认静默模式:关闭 */
|
|
124
|
+
readonly silent: false;
|
|
125
|
+
/** 默认启用颜色输出:是 */
|
|
126
|
+
readonly enableColor: true;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Node.js 日志文件输出创建函数默认配置
|
|
131
|
+
*/
|
|
132
|
+
export declare const DEFAULT_NODE_CREATE_OUTPUT_LOG_FILE_OPTIONS: {
|
|
133
|
+
/** 默认静默模式:关闭 */
|
|
134
|
+
readonly silent: false;
|
|
135
|
+
/** 默认同步写入:关闭(异步写入) */
|
|
136
|
+
readonly sync: false;
|
|
137
|
+
/** 默认缓冲区大小:4KB */
|
|
138
|
+
readonly bufferSize: 4096;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Pino 日志配置默认值
|
|
143
|
+
*/
|
|
144
|
+
export declare const DEFAULT_PINO_CONFIG: {
|
|
145
|
+
/** 默认日志级别:trace */
|
|
146
|
+
readonly level: "trace";
|
|
147
|
+
/** 默认时间格式:yyyy-mm-dd HH:MM:ss */
|
|
148
|
+
readonly timeFormat: "yyyy-mm-dd HH:MM:ss";
|
|
149
|
+
/** 默认忽略字段:pid,hostname */
|
|
150
|
+
readonly ignoreFields: "pid,hostname";
|
|
151
|
+
/** 默认消息格式:{msg} */
|
|
152
|
+
readonly messageFormat: "{msg}";
|
|
153
|
+
/** 默认文件输出颜色:关闭 */
|
|
154
|
+
readonly colorize: false;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 进程退出处理默认配置
|
|
159
|
+
*/
|
|
160
|
+
export declare const DEFAULT_PROCESS_HANDLER_CONFIG: {
|
|
161
|
+
/** 默认静默模式:是(避免控制台输出) */
|
|
162
|
+
readonly silentMode: true;
|
|
163
|
+
/** 默认最大重试次数:3次 */
|
|
164
|
+
readonly maxRetries: 3;
|
|
165
|
+
/** 默认重试间隔:100ms */
|
|
166
|
+
readonly retryInterval: 100;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* 驱动初始化错误
|
|
171
|
+
*/
|
|
172
|
+
export declare class DriverInitializationError extends Error {
|
|
173
|
+
cause?: Error;
|
|
174
|
+
constructor(driverName: string, cause?: Error);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 文件权限错误
|
|
179
|
+
*/
|
|
180
|
+
export declare class FilePermissionError extends Error {
|
|
181
|
+
constructor(filePath: string, operation: string);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 无效配置错误
|
|
186
|
+
*/
|
|
187
|
+
export declare class InvalidConfigurationError extends Error {
|
|
188
|
+
constructor(message: string);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 无效输出类型错误
|
|
193
|
+
*/
|
|
194
|
+
export declare class InvalidOutputTypeError extends Error {
|
|
195
|
+
constructor(type: unknown, validTypes: string[]);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 日志文件输出实现配置选项
|
|
200
|
+
*/
|
|
201
|
+
declare interface LogFileOutputImplOptions {
|
|
202
|
+
/** 是否静默模式 */
|
|
203
|
+
silent?: boolean;
|
|
204
|
+
/** 日志文件路径 (可选,相对路径) */
|
|
205
|
+
logFilePath?: string;
|
|
206
|
+
/** 是否同步写入 (默认: false,异步写入) */
|
|
207
|
+
sync?: boolean;
|
|
208
|
+
/** 缓冲区大小 (字节,默认: 4096) */
|
|
209
|
+
bufferSize?: number;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export { OutputConsole }
|
|
213
|
+
|
|
214
|
+
export { OutputConsoleRaw }
|
|
215
|
+
|
|
216
|
+
export { OutputConsoleTypeEnum }
|
|
217
|
+
|
|
218
|
+
export { OutputLogFile }
|
|
219
|
+
|
|
220
|
+
export { OutputLogFileRaw }
|
|
221
|
+
|
|
222
|
+
export { OutputLogFileTypeEnum }
|
|
223
|
+
|
|
224
|
+
export { OutputTargetModeEnum }
|
|
225
|
+
|
|
226
|
+
export { }
|