日志记录
该框架的核心附带了一个基于 Pino (Node.js 最快的日志库之一)的内置记录器,您可以按如下方式导入和使用 Logger:
import Logger from '@ioc:Adonis/Core/Logger'
Logger.info('A info message')
Logger.warn('A warning')
在 HTTP 请求期间,您必须使用 ctx.logger
对象,它是 logger 的一个独立子实例,将唯一的 request-id 添加到所有的日志消息中。
注:
确保通过在config/app.ts
文件中设置generateRequestId = true
来启用 request-id 生成。
Route.get('/', async ({ logger }) => {
logger.info('An info message')
return 'handled'
})
配置
记录器的配置存储在 logger
导出下的 config/app.ts
文件中,选项与 Pino 文档 相同。
以下是配置记录器所需的最低选项:
{
name: Env.get('APP_NAME'),
enabled: true,
level: Env.get('LOG_LEVEL', 'info'),
redact: {
paths: ['password', '*.password'],
},
prettyPrint: Env.get('NODE_ENV') === 'development',
}
name
记录器的名称,APP_NAME
环境变量使用 package.json 文件中的 name
属性。
enabled
切换开关以启用/禁用记录器
level
当前的日志记录级别,它派生自 LOG_LEVEL
环境变量。
redact
从日志输出中删除/编辑敏感路径,阅读 Redact section。
prettyPrint
是否优化输出日志。我们建议在生产中关闭输出优化,因为它有一些性能开销。
AdonisJS 记录器如何工作?
由于 Node.js 是单线程事件循环,因此保持主线程免于处理或重新格式化日志所需的任何额外工作非常重要。
正是出于这个原因,我们选择了 Pino,它不执行任何进程内日志格式化,而是鼓励你为此使用单独的进程。简而言之,这就是日志记录的工作方式。
- 你可以使用 Logger API 进行不同级别的日志记录,例如:
Logger.info('some message')
。 - 日志总是发送到
stdout
。 - 你可以将
stdout
流重定向到文件或使用单独的进程来读取和格式化它们。
开发中的日志
由于日志总是写入 stdout
,因此在开发环境中没有什么特殊要求。此外,当 NODE_ENV=development
时,AdonisJS 会自动 pretty print 日志。
生产中的日志
在生产中,你可能希望将日志流式传输到 Datadog 或 Papertrail 等外部服务。以下是将日志发送到外部服务的一些方法。
备注:
将标准输出流通过管道传输到服务会产生额外的操作开销。但是,该权衡值得你获得的性能提升。请务必检查 Pino 基准测试。
使用 Pino 传输
处理 stdout
流的最简单方法是使用 Pino transports。你需要做的就是将输出通过管道传输到你选择的传输中。
为了演示,让我们安装 pino-datadog
包以将日志发送到 Datadog。
npm i pino-datadog
接下来,启动生产服务器并将 stdout
输出通过管道传输到 pino-datadog
。
node build/server.js | ./node_modules/.bin/pino-datadog --key DD_API_KEY
流式传输到文件
另一种方法是将 stdout
的输出转发到磁盘上的物理文件,然后配置日志服务以读取和轮换日志文件。
node build/server.js >> app.log
现在,将你的日志服务配置为从 app.log
文件中读取日志。
编辑值
你可以通过定义要删除的键的路径来编辑/删除日志输出中的敏感值。例如:从日志输出中删除用户密码。
// 文件名: config/app.ts
{
redact: {
paths: ['password'],
}
}
上述配置将从合并对象中删除密码。
Logger.info({ username: 'virk', password: 'secret' }, 'user signup')
// 输出: {"username":"virk","password":"[Redacted]","msg":"user signup"}
你可以为编辑值定义自定义占位符,或将它们从输出中完全删除。
{
redact: {
paths: ['password'],
censor: '[PRIVATE]'
}
}
// 或者删除属性
{
redact: {
paths: ['password'],
remove: true
}
}
查看 fast-redact 包以查看可用于路径数组的表达式。
日志 API
以下是 Logger 模块上可用方法/属性的列表。所有的日志记录方法都接受以下参数。
- 第一个参数可以是字符串消息或要与最终日志消息合并的属性对象。
- 如果第一个参数是一个合并对象,那么第二个参数是字符串消息。
- 其余参数是消息占位符的插值。
import Logger from '@ioc:Adonis/Core/Logger'
Logger.info('hello %s', 'world')
// 输出: {"msg": "hello world"}
Logger.info('user details: %o', { username: 'virk' })
// 输出: {"msg":"user details: {\"username\":\"virk\"}"
定义一个合并对象如下:
import Logger from '@ioc:Adonis/Core/Logger'
Logger.info({ username: 'virk' }, 'user signup')
// 输出: {"username":"virk","msg":"user signup"}
你可以在 err
键下传递错误对象。
import Logger from '@ioc:Adonis/Core/Logger'
Logger.error({ err: new Error('signup failed') }, 'user signup')
// 输出: {"err":{"type":"Error","message":"foo","stack":"..."},"msg":"user signup"}
以下是记录方法的列表。
Logger.trace
Logger.debug
Logger.info
Logger.warn
Logger.error
Logger.fatal
isLevelEnabled
查找是否在配置文件中启用了给定的日志记录级别。
Logger.isLevelEnabled('info')
Logger.isLevelEnabled('trace')
bindings
返回一个包含所有当前绑定的对象,从通过 Logger.child()
传入的那些中克隆。
Logger.bindings()
child
创建一个子记录器实例。你也可以创建具有不同日志记录级别的子记录器。
const childLogger = Logger.child({ level: 'trace' })
childLogger.info('an info message')
你还可以为子记录器定义自定义绑定。绑定被添加到日志输出中。
const childLogger = Logger.child({ userId: user.id })
childLogger.info('an info message')
level
当前的日志记录级别值,作为字符串。
console.log(Logger.level)
// 信息
levelNumber
当前的日志记录级别值,以数字形式。
console.log(Logger.levelNumber)
// 30
levels
记录 labels
和 values
的对象。
console.log(Logger.levels)
/**
{
labels: {
'10': 'trace',
'20': 'debug',
'30': 'info',
'40': 'warn',
'50': 'error',
'60': 'fatal'
},
values: {
trace: 10,
debug: 20,
info: 30,
warn: 40,
error: 50,
fatal: 60
}
}
*/
pinoVersion
Pino版本。
console.log(Logger.pinoVersion)
// '6.11.2'
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。