作者:靠 tail -f debug.log 活着的后端守夜人
在一套互动娱乐组件中,日志、监控和健康机制往往被开发者忽视。直到你在凌晨三点被运营电话吵醒,才明白什么叫“没有日志的人生,一定会重来”。
这一部分我们将从日志设计、数据监控、告警处理、服务健康管理、实战排障等多个维度拆解整套系统中最底层、最关键但又最不被重视的“守夜人系统”。
日志不仅是排障工具,更是行为审计、数据追踪、性能评估、用户画像的基础。
日志记录不是“出了问题才查”,而是“未雨绸缪,事后可追”。
常见日志分类:
类型 | 内容 | 文件路径 |
---|---|---|
启动日志 | 系统初始化、模块加载情况 | /logs/startup.log |
行为日志 | 用户进房/退出/操作记录 | /logs/action.log |
错误日志 | try/catch 异常、接口崩溃 | /logs/error.log |
配置日志 | 后台修改参数及应用结果 | /logs/config.log |
安全日志 | 登录IP、失败尝试等信息 | /logs/security.log |
{
"timestamp": "2025-05-05T10:03:00Z",
"level": "INFO",
"module": "room_service",
"uid": 10023,
"action": "enter_room",
"room_id": "ROOM-204"
}
推荐结构化输出,便于统一检索、索引与大数据分析。
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
new winston.transports.File({ filename: 'logs/action.log' })
]
});
logger.info({
module: 'room_handler',
uid: 20394,
action: 'exit_room',
room_id: 'ROOM-009'
});
支持每日轮换日志建议结合 winston-daily-rotate-file
插件。
window.onerror = function (message, source, lineno, colno, error) {
const data = {
msg: message,
stack: error ? error.stack : '',
time: new Date().toISOString()
};
navigator.sendBeacon('/api/log_front_error', JSON.stringify(data));
};
服务端接收保存:
$data = json_decode(file_get_contents('php://input'), true);
file_put_contents("logs/front_error.log", json_encode($data) . "
", FILE_APPEND);
一个合格的双端系统应该具备如下运行指标:
指标项 | 含义 |
total_rooms | 当前房间数 |
online_users | 在线用户数 |
avg_ping | 平均响应延迟 |
socket_drop | 断连次数 |
error_rate | 接口错误比 |
建议通过 Prometheus 暴露 /metrics
接口供抓取。
app.get('/metrics', (req, res) => {
res.send(`active_users_total ${userCount}
active_rooms_total ${roomCount}`);
});
PM2:最小化部署、崩溃自启、实时日志
NodeMailer + shell:简单报警机制
Prometheus + Grafana:指标图表
Sentry:错误异常聚合
Loki + ELK:日志聚合检索
Pingdom/UptimeRobot:服务可用性检测
部署建议:
pm2 start app.js --name="dualend-server"
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
通过告警脚本结合飞书/钉钉机器人实时通知:
#!/bin/bash
error_count=$(grep -c "ERROR" logs/error.log)
if [ "$error_count" -gt 50 ]; then
curl -X POST -H 'Content-Type: application/json' \
-d '{"msg_type":"text","content":{"text":"警报:error.log 超过50条错误!"}}' \
https://open.feishu.cn/xxx/robot/webhook
fi
推荐对以下事件设置告警:
服务 crash(pm2重启触发)
error.log 突增
redis/mysql 连接失败
某模块 QPS 激增或为 0(掉服务)
没有健康检查的服务,就像没体检的老年人,哪天挂了都不知道。
服务端提供标准 /healthz
接口:
app.get('/healthz', (req, res) => {
if (db.connected && redis.ping()) res.send('ok');
else res.status(500).send('fail');
});
配合 Nginx 或 LoadBalancer:
location /healthz {
proxy_pass http://localhost:3000/healthz;
proxy_next_upstream error timeout invalid_header http_500;
}
构建一整套标准流程文档:
日志收集:tail + grep
资源分析:htop / top / free
数据库连接检查:mysqlcli / redis-cli
恢复命令:pm2 restart all / docker restart all
故障通报机制:邮件 / 飞书模版
日志按“项目+日期+类型”分目录
多服务部署建议使用集中日志平台(ELK)
高频写入日志建议采用缓冲队列写入,防止 I/O 阻塞
为防泄露,error.log 与 access.log 应分权限存储
这一章节我们写满了每一个后端人心中的执念,从日志结构、前端采集、后端记录、指标采集、异常告警、健康检测,到实际故障恢复全流程。
这套系统不是为了“看着好看”,是为了在所有人睡觉时,能自动顶上去。
写日志不是怕出问题,是为了你有问题时,不再一脸懵逼地说:“我看不出来”。
愿你有日志可查,有监控可依,有告警能醒,有系统永不宕机。