日志系统 #
一、日志概述 #
Fastify内置了Pino日志库,这是一个极高性能的Node.js日志库。
1.1 Pino特点 #
| 特点 | 说明 |
|---|---|
| 高性能 | 比其他日志库快5倍以上 |
| 低开销 | 对应用性能影响极小 |
| 结构化 | JSON格式日志 |
| 可扩展 | 支持子日志、自定义格式 |
1.2 基本配置 #
javascript
const fastify = require('fastify')({
logger: true
})
fastify.get('/', async (request, reply) => {
request.log.info('Hello World')
return { message: 'Hello' }
})
二、日志配置 #
2.1 基本配置 #
javascript
const fastify = require('fastify')({
logger: {
level: 'info',
file: './logs/app.log'
}
})
2.2 完整配置 #
javascript
const fastify = require('fastify')({
logger: {
level: process.env.LOG_LEVEL || 'info',
prettyPrint: process.env.NODE_ENV === 'development',
redact: ['req.headers.authorization', 'req.headers.cookie'],
serializers: {
req(req) {
return {
method: req.method,
url: req.url,
headers: req.headers
}
},
res(res) {
return {
statusCode: res.statusCode
}
}
},
genReqId: (req) => require('crypto').randomUUID()
}
})
2.3 开发环境配置 #
javascript
const fastify = require('fastify')({
logger: {
level: 'debug',
transport: {
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'SYS:standard',
ignore: 'pid,hostname'
}
}
}
})
2.4 生产环境配置 #
javascript
const fastify = require('fastify')({
logger: {
level: 'info',
formatters: {
level: (label) => {
return { level: label.toUpperCase() }
}
},
timestamp: () => `,"time":"${new Date().toISOString()}"`,
redact: {
paths: ['req.headers.authorization', 'req.headers.cookie'],
censor: '***'
}
}
})
三、日志级别 #
3.1 日志级别 #
javascript
fastify.get('/levels', async (request, reply) => {
fastify.log.trace('Trace message')
fastify.log.debug('Debug message')
fastify.log.info('Info message')
fastify.log.warn('Warning message')
fastify.log.error('Error message')
fastify.log.fatal('Fatal message')
return { logged: true }
})
3.2 级别优先级 #
| 级别 | 优先级 | 说明 |
|---|---|---|
| trace | 10 | 最详细日志 |
| debug | 20 | 调试信息 |
| info | 30 | 一般信息 |
| warn | 40 | 警告信息 |
| error | 50 | 错误信息 |
| fatal | 60 | 致命错误 |
3.3 动态调整级别 #
javascript
fastify.get('/log-level/:level', async (request, reply) => {
const { level } = request.params
fastify.log.level = level
return { level: fastify.log.level }
})
四、请求日志 #
4.1 自动请求日志 #
Fastify自动记录请求日志:
json
{
"level": 30,
"time": 1709500000000,
"pid": 12345,
"hostname": "localhost",
"reqId": "req-1",
"req": {
"method": "GET",
"url": "/users",
"headers": {}
},
"msg": "incoming request"
}
4.2 请求日志钩子 #
javascript
fastify.addHook('onRequest', async (request, reply) => {
request.log.info({
type: 'request',
method: request.method,
url: request.url,
ip: request.ip
})
})
fastify.addHook('onResponse', async (request, reply) => {
request.log.info({
type: 'response',
method: request.method,
url: request.url,
statusCode: reply.statusCode,
responseTime: reply.elapsedTime
})
})
4.3 自定义请求ID #
javascript
const { v4: uuidv4 } = require('uuid')
const fastify = require('fastify')({
logger: true,
genReqId: (req) => req.headers['x-request-id'] || uuidv4()
})
五、结构化日志 #
5.1 对象日志 #
javascript
fastify.get('/user/:id', async (request, reply) => {
request.log.info({
action: 'get_user',
userId: request.params.id,
ip: request.ip
})
const user = await getUser(request.params.id)
request.log.info({
action: 'user_found',
userId: user.id,
userName: user.name
})
return user
})
5.2 错误日志 #
javascript
fastify.get('/error', async (request, reply) => {
try {
await riskyOperation()
} catch (error) {
request.log.error({
action: 'risky_operation',
error: {
name: error.name,
message: error.message,
stack: error.stack
}
})
throw error
}
})
5.3 性能日志 #
javascript
fastify.addHook('onRequest', async (request, reply) => {
request.startTime = Date.now()
})
fastify.addHook('onResponse', async (request, reply) => {
const duration = Date.now() - request.startTime
request.log.info({
type: 'performance',
method: request.method,
url: request.url,
duration,
statusCode: reply.statusCode
})
})
六、子日志 #
6.1 创建子日志 #
javascript
const childLogger = fastify.log.child({ module: 'user-service' })
childLogger.info('User service started')
6.2 模块日志 #
javascript
const userService = fastify.log.child({ service: 'user' })
const emailService = fastify.log.child({ service: 'email' })
userService.info('User created')
emailService.info('Email sent')
6.3 请求级子日志 #
javascript
fastify.addHook('onRequest', async (request, reply) => {
request.log = request.log.child({
requestId: request.id,
userId: request.user?.id
})
})
七、日志输出 #
7.1 控制台输出 #
javascript
const fastify = require('fastify')({
logger: {
level: 'info',
transport: {
target: 'pino-pretty',
options: {
colorize: true
}
}
}
})
7.2 文件输出 #
javascript
const fastify = require('fastify')({
logger: {
level: 'info',
file: './logs/app.log'
}
})
7.3 多输出 #
javascript
const pino = require('pino')
const fs = require('fs')
const streams = [
{ level: 'info', stream: process.stdout },
{ level: 'error', stream: fs.createWriteStream('./logs/error.log') },
{ level: 'debug', stream: fs.createWriteStream('./logs/debug.log') }
]
const fastify = require('fastify')({
logger: pino({ level: 'debug' }, pino.multistream(streams))
})
八、日志格式 #
8.1 自定义格式 #
javascript
const fastify = require('fastify')({
logger: {
formatters: {
level: (label) => {
return { level: label.toUpperCase() }
},
bindings: (bindings) => {
return { pid: bindings.pid }
}
}
}
})
8.2 时间格式 #
javascript
const fastify = require('fastify')({
logger: {
timestamp: () => `,"time":"${new Date().toISOString()}"`
}
})
8.3 自定义序列化 #
javascript
const fastify = require('fastify')({
logger: {
serializers: {
req(req) {
return {
method: req.method,
url: req.url,
headers: {
'content-type': req.headers['content-type'],
'user-agent': req.headers['user-agent']
}
}
},
res(res) {
return {
statusCode: res.statusCode,
headers: res.getHeaders()
}
},
err(err) {
return {
type: err.name,
message: err.message,
stack: err.stack
}
}
}
}
})
九、敏感信息处理 #
9.1 字段隐藏 #
javascript
const fastify = require('fastify')({
logger: {
redact: {
paths: [
'req.headers.authorization',
'req.headers.cookie',
'req.body.password',
'req.body.creditCard'
],
censor: '[REDACTED]'
}
}
})
9.2 条件隐藏 #
javascript
const fastify = require('fastify')({
logger: {
redact: {
paths: ['req.headers.authorization'],
censor: (value, path) => {
if (path.join('.') === 'req.headers.authorization') {
return value.substring(0, 10) + '...'
}
return '[REDACTED]'
}
}
}
})
十、日志最佳实践 #
10.1 日志级别使用 #
javascript
fastify.log.trace('详细调试信息')
fastify.log.debug('调试信息')
fastify.log.info('一般信息')
fastify.log.warn('警告信息')
fastify.log.error('错误信息')
fastify.log.fatal('致命错误')
10.2 结构化日志 #
javascript
request.log.info({
action: 'user_action',
userId: request.user.id,
data: { key: 'value' }
})
10.3 请求追踪 #
javascript
fastify.addHook('onRequest', async (request, reply) => {
request.log = request.log.child({
requestId: request.id,
traceId: request.headers['x-trace-id']
})
})
10.4 错误日志 #
javascript
fastify.setErrorHandler((error, request, reply) => {
request.log.error({
error: {
name: error.name,
message: error.message,
stack: error.stack
},
request: {
method: request.method,
url: request.url,
headers: request.headers
}
})
reply.code(error.statusCode || 500).send({
error: error.message
})
})
十一、总结 #
本章我们学习了:
- 日志概述:Pino特点和基本配置
- 日志配置:基本配置、开发环境、生产环境
- 日志级别:trace、debug、info、warn、error、fatal
- 请求日志:自动日志、钩子、请求ID
- 结构化日志:对象日志、错误日志、性能日志
- 子日志:创建子日志、模块日志
- 日志输出:控制台、文件、多输出
- 日志格式:自定义格式、时间格式、序列化
- 敏感信息:字段隐藏、条件隐藏
- 最佳实践:级别使用、结构化、追踪、错误处理
接下来让我们学习性能优化!
最后更新:2026-03-28