日志
日志用来记录程序的运行信息。开发服务端程序,必须集成日志管理的功能,一旦系统出现故障可以及时排查问题所在。
日志一般分为:
- 访问日志:记录系统的访问记录。
- 运行日志:输出系统运行时的一些信息
- 错误日志:记录系统出错的状态
一般我们都是通过 nginx 做负载均衡,它具备了记录访问日志的功能。所以访问日志交给 Nginx 去做就好。
在后端程序开发中,我们只需要关注运行日志和错误日志。
Koa-logger
Koa.js 官方的日志插件是 koa-logger,功能比较简单,只能打印一些请求的信息,并不会记录日志,不能满足复杂场景的需求。
const logger = require('koa-logger')
app.use(logger())
// logger
app.use(async (ctx, next) => {
const start = new Date()
await next()
const ms = new Date() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
看似是一个日志中间件,本质只是一个 console.log
打印内容的格式化。只能开发模式下打印的更加美观。
所以通常会使用一些第三方的日志模块,比如 log4js
、winston
等。
Log4js
Log4js 是一个优秀的日志插件,常用的功能包括按级别输出不同的日志信息,保存日志为文件等。
使用 log4js
安装依赖:
npm install log4js
配置
新建 log4js 的配置文件, utils/log4js.js:
// log4js.js
const path = require('path')
const log4js = require('log4js')
const { isProd } = require('./index')
// 日志配置对象
log4js.configure({
// 日志记录方式
appenders: {
// 自定义category为error,记录服务器报错信息
error: {
type: 'file', //日志类型 指定单一文件存储
filename: path.join('logs/', 'error/error.log'), //日志输出位置,当目录文件或文件夹不存在时自动创建
maxLogSize: 1024 * 1000 * 100, // 文件最大存储空间,单位是字节 1024k 1m
backups: 100 //当文件内容超过文件存储空间时,备份文件的数量
},
// 自定义category为response,记录服务器的响应情况 用户访问服务的情况
response: {
type: 'dateFile', // 以日期命名的文件记录日志
filename: path.join('logs/', 'access/response'),
pattern: 'yyyy-MM-dd.log', //日志输出模式
alwaysIncludePattern: true,
// dateFile类型的appender没有这个选项
maxLogSize: 1024 * 1000 * 100,
// dateFile类型的appender没有这个选项
backups: 1
},
console: {
type: "console",
layout: {
// 开发环境下带颜色输出,生产环境下使用基本输出
type: isProd ? 'basic' : 'coloured'
}
}
},
// log4js.getLogger(type):就是读取这里的key
categories: {
error: { appenders: ['error'], level: 'error' },
response: { appenders: ['response'], level: 'info' },
default: { appenders: ['console'], level: 'all' }
}
replaceConsole: true
})
let logger = {}
// 自定义输出格式,确定哪些内容输出到日志文件中
const formatError = (ctx, err) => {
const { method, url } = ctx
let body = ctx.request.body
const user = ctx.state.user
// 将请求方法,请求路径,请求体,登录用户,错误信息
return { method, url, body, user, err }
}
const formatRes = (ctx, costTime) => {
// const { method, url, response: { status, message, body: { success } }, request: { header: { authorization } } } = ctx
const { ip, method, url, response: { status, message }, request: { header: { authorization } } } = ctx
let body = ctx.request.body
const user = ctx.state.user
// 将请求方法,请求路径,请求体,登录用户,请求消耗时间,请求头中的authorization字段即token,响应体中的状态码,消息,以及自定义的响应状态
return { ip, method, url, body, user, costTime, authorization, response: { status, message } }
}
// 生成一个error类型的日志记录器
let errorLogger = log4js.getLogger('error')
// 生成一个response类型的日志记录器
let resLogger = log4js.getLogger('response')
// 生成一个控制台类型的日志记录器
let console = log4js.getLogger()
// 封装错误日志
logger.errLogger = (ctx, error) => {
if (ctx && error) {
errorLogger.error(formatError(ctx, error))
}
}
// 封装响应日志
logger.resLogger = (ctx, resTime) => {
if (ctx) {
resLogger.info(formatRes(ctx, resTime))
}
}
// 控制台输出
logger.log = console
module.exports = logger
在应用中使用 log4js 插件:
const Koa = require('koa')
const { isProd } = require('./utils/index')
const { log, errLogger, resLogger } = require('./utils/log4js')
// 初始化web服务
const app = new Koa()
const router = new Router()
// 通过log4js记录访问日志
app.use(async (ctx, next) => {
const start = new Date()
await next()
const end = new Date() - start
// 生产环境下,使用中间件记录日志,使用console.log打印消息。
// 其他环境下,使用log4js的console打印信息。
if (isProd) {
resLogger(ctx, end)
console.log((`${ctx.method} ${ctx.url} - ${end}ms`))
} else {
log.info(`${ctx.method} ${ctx.url} - ${end}ms`)
}
})
// error-handling
app.on('error', (err, ctx) => {
if (isProd) {
errLogger(ctx, err);
log.error(`${ctx.method} ${ctx.url}`, err)
} else {
console.error(`${ctx.method} ${ctx.url}`, err)
}
})
小结
本文总结了在 Koa.js 项目中使用第三方日志插件 log4js 的方法,首先是定义log4js的配置,它决定了该如何记录日志。然后在应用入口中使用 log4js,让其生效。