日志对 Web 框架的重要性不言而喻,在监控应用状态、排查问题、关键动作记录等有非常重要的作用,egg.js 对日志提供了内置的支持
日志分类
egg.js 按照场景对日志做了分类
- core log:框架内核、插件打印的日志,存储在
egg-web.log
下 - app log:应用相关日志,供应用开发者使用,存储在
${appinfo.name}-web.log
下 - agent log:agent 进程的日志,egg.js 框架和使用到 agent 进程的插件 在执行任务时把日志打印到
egg-agent.log
下 - error log:使用 egg.js 打印的错误日志会存储在
common-error.log
下,帮助开发者定位问题
可以修改 config 来自定义日志文件名称
config.logger = {
coreLogName: 'egg-web.log',
appLogName: `${appInfo.name}-web.log`,
agentLogName: 'egg-agent.log',
errorLogName: 'common-error.log',
};
日志路径
- 在本地开发环境中所有日志存储在
/logs/${appinfo.name}
下 - 在线上环境日志存放在
${appinfo.root}/logs/${appinfo.name}
下
可以修改不同环境的配置文件,自定义日志存储路径
// config/config.${env}.js
config.logger = {
dir: '/path/to/your/custom/log/dir',
};
打印日志
app log
如果想做一些应用级别的日志记录,如记录启动阶段的一些数据信息,可以通过 App Logger 来完成
// app.js
module.exports = app => {
app.logger.debug('debug info');
app.logger.info('启动耗时 %d ms', Date.now() - start);
app.logger.warn('warning!');
app.logger.error(someErrorObj);
};
框架和插件开发者还会使用到 app.coreLogger
// app.js
module.exports = app => {
app.coreLogger.info('启动耗时 %d ms', Date.now() - start);
};
Agent Logger
在开发框架和插件时有时会需要在 Agent 进程运行代码,这时使用 agent.coreLogger
// agent.js
module.exports = agent => {
agent.logger.debug('debug info');
agent.logger.info('启动耗时 %d ms', Date.now() - start);
agent.logger.warn('warning!');
agent.logger.error(someErrorObj);
};
Context Logger
egg.js 的业务开发者最常使用的是请求的 log,用来记录 Web 行为相关日志
ctx.logger.debug('debug info');
ctx.logger.info('some request data: %j', ctx.request.body);
ctx.logger.warn('WARNNING!!!!');
// 错误日志记录,直接会将错误日志完整堆栈信息记录下来,并且输出到 errorLog 中
ctx.logger.error(new Error('whoops'));
每行日志会自动记录上当前请求的一些基本信息, 如
- userId
- ip
- 耗时
- traceId
- method
- url
框架开发者和插件开发者还会使用到 ctx.coreLogger
ctx.coreLogger.info('info');
日志级别
日志分为 NONE
,DEBUG
,INFO
,WARN
和 ERROR
5 个级别,和 egg.js logger 中方法名对应,为了方便开发,在开发环境会同步输出到终端,可以通过配置修改打印到终端、输出到日志文件的级别
打印所有级别日志到终端
// config/config.${env}.js
exports.logger = {
consoleLevel: 'DEBUG',
};
关闭所有打印到文件的日志
// config/config.${env}.js
exports.logger = {
level: 'NONE',
};
生产环境打印 DEBUG 日志
为了避免一些插件的调试日志在生产环境打印导致性能问题,生产环境默认禁止打印 DEBUG 级别的日志
// config/config.prod.js
exports.logger = {
level: 'DEBUG',
allowDebugAtProd: true,
};
日志切割
日积月累日志文件会变得非常庞大,egg.js 提供了自动切割日志的功能
按天切割
egg.js 默认按天切割日志,在每日 00:00
按照 .log.YYYY-MM-DD
文件名进行切割
按小时切割
如果日志量非常大,可以修改配置,按照小时切割,例如把 common-error.log
按照小时进行切割:
// config/config.${env}.js
const path = require('path');
module.exports = appInfo => {
return {
logrotator: {
filesRotateByHour: [
path.join(appInfo.root, 'logs', appInfo.name, 'common-error.log'),
],
},
};
};
按文件大小切割
egg.js 也可以按照文件大小对日志进行切割,例如把 egg-web.log
按照大小进行切割:
// config/config.${env}.js
const path = require('path');
module.exports = appInfo => {
return {
logrotator: {
filesRotateBySize: [
path.join(appInfo.root, 'logs', appInfo.name, 'egg-web.log'),
],
maxFileSize: 2 * 1024 * 1024 * 1024, // 当文件超过 2G 时进行切割
},
};
};
性能
通常 Web 访问是高频访问,每次打印日志都写磁盘会造成频繁磁盘 IO,为了提高性能 egg.js 不会实时把日志内容写入磁盘,而是把日志内容先缓存一段时间(默认 1s)到内存中,然后再异步写入磁盘
egg.js 日志完整功能可以查看官方文档 Egg.js 日志