前端监控简介

日志与告警

了解前端日志的分级与采集思路,学会设计简单的告警规则,让问题及时被发现。

🎯 引言

前面几篇解决了「数据怎么收」,本篇解决「数据怎么让人看到」:用日志分级让记录可查,用告警规则让异常主动通知到人,而不是出了问题才去翻日志。

学完本篇,你将能够:

  • 正确使用 debug、info、warn、error 四个日志级别。
  • 封装一个带级别控制和采样能力的简易 logger。
  • 设计阈值告警和同比环比告警规则,并避开告警疲劳。

🧱 日志是什么,和埋点有什么区别

日志是程序运行时主动留下的文字记录,回答「程序此刻在做什么、状态如何」,主要给开发和运维看;第三篇讲的埋点回答「用户做了什么」,主要给产品和运营看。打个比方:埋点像商场里统计客流和购买行为的摄像头,关心「人」;日志像设备的运行记录仪,关心「机器转得正不正常」。两者配合,才能完整还原线上发生了什么。


🧱 日志分级:四个级别的使用场景

线上项目一天可能产生大量日志,不分轻重堆在一起,出问题只能一条条翻。按严重程度分级后,排查时先看 error 就能快速锁定方向。

级别从低到高是 debug → info → warn → error

  • debug:开发阶段的调试细节,如变量的当前值。量大、价值低,线上环境通常关闭。
  • info:关键流程正常推进的记录,如「用户登录成功」,事后可顺着它还原一次操作的过程。
  • warn:没出错但不对劲,如「接口超时后自动重试」「参数缺失使用了默认值」,值得回头关注。
  • error:功能确实失败,如接口报错、提交失败,通常要接告警通知到人。

🛠 封装一个简易 logger

到处散写 console.log 有两个隐患:上线后想批量关闭低级别日志要逐文件改,而且打印内容只存在用户浏览器里,出了问题你拿不到。封装统一的 logger 可以把级别控制、采样和上报集中管理。下面的实现不依赖任何第三方包,浏览器直接可用:

logger.js
const LEVELS = { debug: 0, info: 1, warn: 2, error: 3 }; // 数字越大越严重
const minLevel = 'info'; // 允许输出的最低级别,线上设为 'info' 即可关掉 debug

function log(level, message, extra) {
    if (LEVELS[level] < LEVELS[minLevel]) {
        return; // 级别不够,直接丢弃
    }

    const record = { level, message, extra, time: new Date().toISOString() };
    console[level](`[${level}]`, message, extra ?? '');

    if (LEVELS[level] >= LEVELS.warn) {
        report(record); // warn 和 error 额外上报到服务端
    }
}

function report(record) {
    // 用 sendBeacon 上报,页面关闭时也能发出去
    navigator.sendBeacon('/api/logs', JSON.stringify(record));
}

export const logger = {
    debug: (msg, extra) => log('debug', msg, extra),
    info: (msg, extra) => log('info', msg, extra),
    warn: (msg, extra) => log('warn', msg, extra),
    error: (msg, extra) => log('error', msg, extra),
};

使用时和 console 一样自然,如 logger.error('登录接口报错', { status: 500 }),但每条日志都带上了级别和时间。想关掉某个级别,只改 minLevel 这一个配置,业务代码不用动。生产项目里常用 Sentry 自带的日志和上报能力,接入方式见上一篇《Sentry 接入实践》。


💡 采样:控制日志量

高频低价值的日志(如每次操作都产生的 info)全量上报既浪费带宽,也会淹没重要信息,可以按比例抽样保留一部分:

logger.js
// 采样上报:只有 10% 的日志真正发送
function reportWithSample(record, rate = 0.1) {
    if (Math.random() < rate) {
        report(record);
    }
}

使用原则一句话:warn 和 error 全量上报,一条不丢;高频的 info、debug 才采样。


🧱 告警规则设计

告警就是按规则持续检查指标、发现异常就发通知的机制。常用的规则有两种思路。

阈值告警:超过固定的线就报警。

适合有明确安全线的指标,比如「一分钟内 error 日志超过 50 条」就触发:

alert.js
// 最近一分钟的 error 数量超过 50 条就告警
function checkErrorCount(errorCountInLastMinute) {
    if (errorCountInLastMinute > 50) {
        sendAlert(`一分钟内错误数达到 ${errorCountInLastMinute} 条,请尽快排查`);
    }
}

短板是线不好定:白天和凌晨流量差异大,用同一条线,不是白天误报就是凌晨漏报。

同比环比告警:不盯固定线,和自己的历史值比。

  • 环比:和上一个周期比,如「这一小时 vs 上一小时」。
  • 同比:和上周期的同一时段比,如「今天上午 10 点 vs 昨天上午 10 点」。

比如「本小时错误数比昨天同一小时上涨了 3 倍」就告警。这样白天和凌晨各有各的参照系,正常的流量波动不容易误报,突然异常却藏不住:

alert.js
// 同比告警:和昨天同一时段对比,涨幅超过 3 倍就告警
function checkBySamePeriod(todayCount, yesterdayCount) {
    const hasBaseline = yesterdayCount > 0;
    const ratio = hasBaseline ? todayCount / yesterdayCount : 0;
    if (hasBaseline && ratio > 3) {
        sendAlert(`错误数同比上涨 ${Math.round(ratio)} 倍,请尽快排查`);
    }
}
告警的「线」没有通用数值,上面的 50 条、3 倍只是示例。上线后要观察一段时间的误报和漏报情况,再按自己业务的流量规律调整。

🧰 告警发到哪里去

常见渠道有邮件、企业微信群机器人、飞书群机器人等;已接入 Sentry 的项目也可以直接在它的控制台配置 Alert Rule,不用自己写这部分代码。以群机器人为例,平台会给你一个 webhook 地址,往它发一条 POST 请求,消息就会出现在群里:

notify.js
function sendAlert(text) {
    fetch('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的key', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ msgtype: 'text', text: { content: text } }),
    });
}
企业微信、飞书、Sentry 等平台的页面会不定期更新,按钮名称和入口位置可能与你看到的略有不同。以上流程仅供参考,核心思路不变,操作时以平台最新页面为准。

🪤 小心告警疲劳

如果告警群一天弹几百条消息、大多又不需要处理,大家很快会把它设成免打扰,真正重要的告警反而被淹没,这就是告警疲劳。几条应对经验:

  • 每条告警都必须可行动:收到的人有明确的事情可做,否则降级成普通报表。
  • 同类告警要合并:同一接口一分钟报错 100 次,发一条汇总即可。
  • 加冷却时间:同一问题告警后的一段时间内(如 10 分钟)不再重复通知。
  • 分级通知:warn 发群里留意,error 才打电话或发短信。

🧾 小节总结

  • 日志记录「程序发生了什么」,埋点记录「用户做了什么」,两者分工不同、互相配合。
  • 日志分 debug、info、warn、error 四级,线上通常关闭 debug,warn 和 error 要上报;封装统一 logger 集中管理级别控制、采样和上报。
  • 采样用来控制日志量:高频低价值的日志按比例抽样,warn 和 error 必须全量保留。
  • 阈值告警管「绝对灾难」,同比环比告警管「异常波动」,实际项目常搭配使用。
  • 告警要可行动、要合并、要有冷却,否则会陷入告警疲劳,真正的问题反而被忽略。

❓ 知识问答

Q1:warn 和 error 怎么区分?

A:看功能是否失败。功能失败、用户操作没走通,用 error;功能还能跑但过程中有异常迹象(重试、降级、用了默认值),用 warn。

Q2:采样会不会漏掉关键问题?

A:关键是只对高频低价值的日志采样,error 和 warn 永远全量。另外采样丢失的是数量精度而不是有无:1000 条同类 info 采到 100 条,照样能看出流程在正常运转。

Q3:告警阈值定多少合适?

A:没有标准答案,建议先观察。上线初期阈值定宽松些、只记录不通知,积累一两周数据后按「正常波动范围的上沿」定线,再根据误报漏报持续调整。


🧪 小练习

练习一:给下面的 logger 补上采样逻辑,要求 info 级别按 20% 的比例上报,error 级别全量上报:

function report(level, record) {
    // 请在这里编写代码:info 按 20% 采样,error 全量上报
    navigator.sendBeacon('/api/logs', JSON.stringify(record));
}

练习二:补全这个环比告警函数,要求「本周期的错误数比上一周期上涨超过 2 倍」时触发告警,注意处理上一周期为 0 的情况:

function checkByLastPeriod(currentCount, lastCount) {
    // 请在这里编写代码:环比上涨超过 2 倍时调用 sendAlert
}

🎉 恭喜你已经掌握日志与告警技能啦!到这里,前端监控课程就全部完成了,回到 前端监控课程 复习一遍,挑一个自己的项目动手实践吧!