Koa.js 日志系统与异常监控
日志系统的重要性
完善的日志系统是排查问题和监控应用健康状态的基础。生产环境中的日志不仅用于问题定位,还支撑着性能分析、用户行为分析、安全审计等高级需求。一个好的日志系统应该具备:结构化输出、多级别支持、轮转策略、集中存储、实时分析等能力。
日志级别设计
| 级别 | 使用场景 | 示例 |
|---|---|---|
| error | 错误信息,需要处理 | 数据库连接失败 |
| warn | 警告信息,可能有问题 | 请求超时 |
| info | 重要业务信息 | 用户登录、订单创建 |
| debug | 调试信息 | 变量值、流程分支 |
日志库配置
const log4js = require('log4js');
// 日志配置
log4js.configure({
appenders: {
console: { type: 'console' },
file: {
type: 'file',
filename: 'logs/app.log',
maxLogSize: 10485760, // 10MB
backups: 5,
compress: true
},
errorFile: {
type: 'file',
filename: 'logs/error.log'
}
},
categories: {
default: { appenders: ['console', 'file'], level: 'info' },
error: { appenders: ['console', 'errorFile'], level: 'error' }
}
});
const logger = log4js.getLogger();
const errorLogger = log4js.getLogger('error');
// Koa 中间件中使用
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
logger.info({
method: ctx.method,
url: ctx.url,
status: ctx.status,
responseTime: ms,
ip: ctx.ip
});
});
统一异常处理
在 Koa 中实现全局异常捕获:
// 错误处理中间件
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
// 记录错误日志
errorLogger.error({
message: err.message,
stack: err.stack,
url: ctx.url,
method: ctx.method,
body: ctx.request.body,
headers: ctx.headers
});
// 根据错误类型返回不同状态码
const status = err.status || err.statusCode || 500;
const message = err.message || 'Internal Server Error';
ctx.status = status;
ctx.body = {
success: false,
error: message,
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
};
// 触发告警通知
if (status >= 500) {
await notifyAdmin(err, ctx);
}
}
});
// 404 处理
app.use(async (ctx) => {
ctx.status = 404;
ctx.body = { success: false, error: 'Not Found' };
});
结构化日志
使用 JSON 格式便于日志分析和搜索:
// 业务日志记录器
const businessLogger = {
log(orderId, action, data) {
logger.info(JSON.stringify({
type: 'business',
orderId,
action,
data,
timestamp: new Date().toISOString(),
service: 'order-service'
}));
}
};
// 记录订单创建
router.post('/order', async (ctx) => {
const order = await createOrder(ctx.request.body);
businessLogger.log(order.id, 'order_created', {
userId: order.userId,
amount: order.amount,
items: order.items.length
});
ctx.body = { success: true, data: order };
});
日志分析与告警
常见日志分析场景和告警规则:
- 错误率告警:5分钟内错误数超过阈值(如10个/分钟)
- 响应时间告警:P95 响应时间超过设定阈值
- 特定错误告警:如数据库连接失败、支付异常等
- 异常堆栈:记录完整堆栈信息便于定位
日志收集方案
| 方案 | 特点 | 适用场景 |
|---|---|---|
| ELK Stack | 功能强大,生态完善 | 大型应用 |
| EFK Stack | 轻量级,易部署 | 中小型应用 |
| Loki | 简单高效,成本低 | 云原生场景 |
| 商业方案 | Datadog, NewRelic | 开箱即用 |
性能考量
- 异步写入:日志写入不阻塞请求处理
- 采样策略:高频日志可采样记录
- 日志级别:生产环境适当提高日志级别
- 敏感信息:日志中过滤密码、Token等敏感信息