@lark-apaas/nestjs-logger
v1.0.13
Published
Nestjs Logger
Readme
NestJS Logger
基于 Pino 的高性能 NestJS 日志库,支持请求追踪和结构化日志。
功能特性
- 基于 Pino 的高性能日志记录
- 自动 HTTP 请求追踪(双层日志:info 链路日志 + verbose 详细日志)
- 请求和响应体日志记录(可配置)
- 支持多日志级别
- 独立的 trace 日志文件
- 请求上下文传递
- 日志体长度截断
- 完美兼容 Exception Filter:
- 拦截
response.json()和response.send()方法 - 能够捕获 Exception Filter 改写的响应体和最终状态码
- 确保异常日志的完整性和准确性
- 拦截
安装
npm install @lark-apaas/nestjs-logger基本使用
1. 导入模块
import { Module } from '@nestjs/common';
import { LoggerModule } from '@lark-apaas/nestjs-logger';
@Module({
imports: [LoggerModule],
})
export class AppModule {}2. 使用 Logger(完全兼容 NestJS 官方 API)
本库完全遵循 NestJS 官方 Logger API,无缝替换官方 Logger。
import { Injectable, Logger } from '@nestjs/common';
@Injectable()
export class MyService {
private readonly logger = new Logger(MyService.name);
doSomething() {
// 简单日志
this.logger.log('This is an info log');
// 带 context 的日志(最后一个参数)
this.logger.log('User logged in', 'AuthModule');
// ↑ context
// 多个参数会用空格连接
this.logger.log('User', userId, 'logged in from', ip);
// 输出: User 123 logged in from 192.168.1.1
// 使用模板字符串
this.logger.log(`User ${userId} logged in from ${ip}`);
// 多参数 + context
this.logger.log('Processing order', orderId, 'OrderService');
// ↑ context
}
handleError() {
try {
// 业务逻辑
} catch (error) {
// Error 日志 + stack trace(官方推荐方式)
this.logger.error('Failed to process', error.stack);
// ↑ 第一个参数自动识别为 stack
// Error + stack + context
this.logger.error('Payment failed', error.stack, 'PaymentService');
// ↑ stack ↑ context
}
}
}参数规则(与 NestJS 官方一致):
- 最后一个字符串参数:自动识别为
context - Error/Fatal 方法的第一个参数:如果是 stack trace 格式,自动识别为
stack - 多个参数:会用空格连接成一个字符串
- 不支持格式化占位符:不支持
%s,%d,%o等占位符,请使用模板字符串
3. 使用 logStructured 记录结构化日志(扩展功能)
除了标准的 Logger API,本库还提供了 logStructured() 方法用于记录结构化日志:
import { Inject, Injectable } from '@nestjs/common';
import { AppLogger } from '@lark-apaas/nestjs-logger';
@Injectable()
export class MyService {
constructor(
@Inject(AppLogger) private readonly logger: AppLogger,
) {}
doSomething() {
// 使用 logStructured 记录结构化日志
this.logger.logStructured(
'log', // 日志级别
'User action completed', // 消息
{ // 元数据对象(会合并到日志字段中)
action: 'create_order',
order_id: '123',
amount: 100,
},
'MyService', // context(可选)
);
}
}两种方式对比:
| 特性 | 标准 Logger API | logStructured API | |------|----------------|-------------------| | 用途 | 常规日志,兼容 NestJS 官方 | 结构化日志,将 meta 合并到字段 | | Context | 最后一个参数自动识别 | 显式传递第4个参数 | | 消息格式 | 使用模板字符串拼接 | 纯文本消息 | | 元数据 | 需要手动拼接到消息中 | 作为独立字段存储,便于查询 | | 使用场景 | 日常日志、错误日志 | 需要结构化查询的业务日志 |
环境变量配置
基础配置
# 日志级别: trace, debug, info, warn, error, fatal, silent
# 注意:HTTP 请求追踪日志使用 verbose 级别(对应 Pino 的 trace)
# 生产环境默认为 info,不会打印 verbose 级别的日志
LOGGER_LEVEL=info
# 日志目录
LOG_DIR=logs
# Node 环境(默认:开发环境使用 debug,生产环境使用 info)
NODE_ENV=production请求/响应体日志配置
# 启用请求体日志(默认:false)
LOG_REQUEST_BODY=true
# 启用响应体日志(默认:false)
LOG_RESPONSE_BODY=true
# 注意:即使启用了请求/响应体日志,也需要将日志级别设置为 verbose 才能实际输出
# 因为 HTTP 请求追踪日志使用的是 verbose 级别
LOGGER_LEVEL=verbose
# 日志体最大长度,超过会截断(默认:不限制)
# 不设置此环境变量时,不会进行截断
LOG_MAX_BODY_LENGTH=10000请求/响应体日志
日志级别说明
HTTP 请求追踪日志使用 verbose 级别(对应 Pino 的 trace 级别),这意味着:
- 生产环境默认不打印:生产环境默认日志级别为
info,不会输出 verbose 级别的日志 - 需要显式启用:要查看 HTTP 请求追踪日志,需要将
LOGGER_LEVEL设置为verbose - 细粒度控制:可以通过日志级别控制是否打印请求追踪,而无需修改
LOG_REQUEST_BODY和LOG_RESPONSE_BODY配置
响应体记录规则
只针对 JSON 响应记录 body:
- 自动检测
Content-Type是否包含application/json - 只有 JSON 响应才会记录
response_body字段 - 文件下载、HTML 页面等非 JSON 响应不会记录 body,避免日志污染
- 这样可以显著减少日志体积,同时保持日志的可读性
启用方式
通过环境变量启用:
# 方式一:仅启用 HTTP 请求追踪(不包含 body)
LOGGER_LEVEL=verbose
# 方式二:启用 HTTP 请求追踪 + 请求/响应体
LOGGER_LEVEL=verbose
LOG_REQUEST_BODY=true
LOG_RESPONSE_BODY=true重要说明
双层日志机制:
- info 级别:始终记录基础链路日志(不含 body),用于生产环境请求追踪
- verbose 级别:记录详细追踪日志(包含 body),用于开发调试
默认不限制长度:如果不设置
LOG_MAX_BODY_LENGTH环境变量,日志体不会被截断。建议在生产环境设置合理的限制值。响应体过滤:
- 只记录 JSON 响应的 body(检测 Content-Type)
- 文件下载、HTML、图片等非 JSON 响应不会记录 body
- 避免记录无法序列化的数据(如 Buffer、Stream)
- 显著减少日志体积,提高日志可读性
日志输出示例
Info 级别(链路日志)
{
"level": "INFO",
"time": 1234567890,
"msg": "HTTP request started",
"method": "GET",
"path": "/api/users",
"trace_id": "req-123-456",
"user_id": "user-001",
"tenant_id": 24020896,
"app_id": "",
"context": "HTTPTraceInterceptor"
}{
"level": "INFO",
"time": 1234567890,
"msg": "HTTP request completed",
"method": "GET",
"path": "/api/users",
"trace_id": "req-123-456",
"status_code": 200,
"duration_ms": 125,
"context": "HTTPTraceInterceptor"
}Verbose 级别(详细追踪日志)
{
"level": "TRACE",
"time": 1234567890,
"msg": "HTTP request started",
"method": "POST",
"path": "/api/users",
"trace_id": "req-123-456",
"request_body": {
"username": "john_doe",
"email": "[email protected]",
"password": "secret123"
},
"query_params": {
"filter": "active"
},
"context": "HTTPTraceInterceptor"
}{
"level": "TRACE",
"time": 1234567890,
"msg": "HTTP request completed",
"method": "POST",
"path": "/api/users",
"trace_id": "req-123-456",
"status_code": 201,
"duration_ms": 125,
"response_body": {
"id": "user-123",
"username": "john_doe",
"email": "[email protected]"
},
"context": "HTTPTraceInterceptor"
}数据截断
默认情况下,不会对日志体进行截断。当设置 LOG_MAX_BODY_LENGTH 环境变量后,如果请求/响应体超过指定长度,会自动截断:
{
"response_body": {
"_truncated": true,
"_originalLength": 50000,
"_data": "{ 前 10000 个字符... }..."
}
}建议:在生产环境设置合理的限制值(如 10000),避免单条日志过大。
日志级别映射
NestJS LoggerService 级别到 Pino 级别的映射:
fatal→fatalerror→errorwarn→warnlog→infodebug→debugverbose→trace
日志文件
日志会写入以下文件(默认在 logs/ 目录):
server.log- 应用日志trace.log- HTTP 请求追踪日志
注意事项
架构设计
Exception Filter 兼容性:
- 使用
response.on('finish')事件记录日志,确保在响应完全发送后才记录 - 拦截
response.json()和response.send()方法,捕获最终发送的响应体 - 能够正确捕获全局 Exception Filter 设置的最终状态码和响应体
- 日志记录发生在 NestJS 请求生命周期的最后阶段,确保信息完整准确
- 使用
请求生命周期:
Middleware → Guards → Interceptor (before) → Pipes → Controller ↓ Interceptor (after/catchError) → Exception Filters → Response Finish (✅ 日志记录)实现原理:
- 拦截响应方法:在 Interceptor 中拦截
res.json()和res.send(),存储响应体到res.__finalResponseBody - 类型检测:通过
Content-Typeheader 判断是否为 JSON 响应,只记录 JSON 类型的 body - 延迟记录:不在 Interceptor 的
tap()或catchError()中记录日志,而是在finish事件中统一记录 - 完整信息:此时可以获取 Exception Filter 处理后的最终状态码和响应体,确保日志准确性
- 拦截响应方法:在 Interceptor 中拦截
Logger API 兼容性:
- 完全兼容 NestJS 官方:实现与
@nestjs/common的 Logger 完全一致的 API - 参数解析规则:
- 最后一个字符串参数自动识别为
context - Error/Fatal 方法的第一个参数如果是 stack trace 格式,自动识别为
stack
- 最后一个字符串参数自动识别为
- 无缝替换:可以直接替换项目中的官方 Logger,无需修改业务代码
- 扩展功能:提供
logStructured()方法用于结构化日志场景
- 完全兼容 NestJS 官方:实现与
安全性
- 生产环境默认不打印 HTTP 追踪日志:由于使用 verbose 级别,生产环境(info 级别)默认不会输出详细日志
- 双层日志设计:info 级别始终记录链路日志,verbose 级别记录详细信息,按需启用
- 按需启用:需要查看详细追踪时,将 LOGGER_LEVEL 设置为 verbose
- 敏感数据处理:日志库不提供脱敏功能,请在业务层或通过中间件处理敏感数据
性能
- verbose 级别会输出所有 HTTP 请求详细日志,可能影响性能
- 开启请求/响应体日志会增加日志体积和 I/O 开销
- 大对象的序列化会影响性能
- 建议在开发/测试环境使用,生产环境按需临时启用
存储
- 开发环境默认启用日志轮转(基于 rotating-file-stream),活跃文件始终为
server.log,归档为server.log.1(最新)→server.log.N(最旧) - 默认单文件 10MB,最多保留 5 个归档,总占用上限约 60MB
- 可通过环境变量控制轮转行为:
LOG_ROTATION_ENABLED、LOG_ROTATION_MAX_SIZE、LOG_ROTATION_MAX_FILES - verbose 级别 + 请求/响应体日志会显著增加日志量
- 建议设置
LOG_MAX_BODY_LENGTH限制单条日志大小(默认不限制)
最佳实践
开发环境
NODE_ENV=development
# 使用 verbose 级别查看 HTTP 请求追踪
LOGGER_LEVEL=verbose
LOG_REQUEST_BODY=true
LOG_RESPONSE_BODY=true
# 开发环境可以不限制长度,或设置较大值
# LOG_MAX_BODY_LENGTH=50000生产环境
NODE_ENV=production
# 生产环境使用 info 级别,不会打印 HTTP 请求追踪日志
LOGGER_LEVEL=info
# 这两个配置可以保留,只有当 LOGGER_LEVEL=verbose 时才会生效
LOG_REQUEST_BODY=false
LOG_RESPONSE_BODY=false故障排查
临时启用详细日志:
NODE_ENV=production
# 临时开启 verbose 级别查看 HTTP 请求追踪
LOGGER_LEVEL=verbose
LOG_REQUEST_BODY=true
LOG_RESPONSE_BODY=true
LOG_MAX_BODY_LENGTH=10000 # 建议设置限制,避免日志过大License
MIT
