埋点异常阈值告警与 Webhook 通知实现

举报
yd_282816122 发表于 2026/11/13 16:04:12 2026/11/13
【摘要】 背景痛点前面的日志脚本只能定时产出报表,属于“事后看数据”:页面性能突然恶化、前端错误爆发,要等人工翻看报表才能发现;流量异常(爬虫刷量、访问突降)无法自动感知;轻量静态站点不想部署 Prometheus + AlertManager 这类重型告警组件;希望告警通知直接推到 IM 工具,及时触达维护者。方案思路:在原有日志分析脚本基础上,增加阈值规则 + 环比突变检测模块,满足条件时调用 ...

背景痛点

前面的日志脚本只能定时产出报表,属于“事后看数据”:

  1. 页面性能突然恶化、前端错误爆发,要等人工翻看报表才能发现;
  2. 流量异常(爬虫刷量、访问突降)无法自动感知;
  3. 轻量静态站点不想部署 Prometheus + AlertManager 这类重型告警组件;
  4. 希望告警通知直接推到 IM 工具,及时触达维护者。

方案思路:在原有日志分析脚本基础上,增加阈值规则 + 环比突变检测模块,满足条件时调用 Webhook 接口推送结构化告警消息。

整体流程

日志拉取 → 清洗聚合 → 指标计算 → 规则判断(固定阈值 / 环比)→ 命中则调用 Webhook 推送告警

完整扩展代码

// alert-analyzer.js
const fs = require('fs');
const path = require('path');
const https = require('https');

const REPORT_PATH = './logs/report.json';
const HISTORY_PATH = './logs/history.json';
const WEBHOOK_URL = process.env.ALERT_WEBHOOK || '';

// 告警规则配置
const ALERT_RULES = [
  {
    name: "LCP性能恶化",
    expr: (curr, prev) => curr.summary.lcpP95 > 3000,
    level: "warning",
    desc: "页面LCP P95超过3000ms,用户加载体验变差"
  },
  {
    name: "前端错误突增",
    expr: (curr, prev) => {
      const currErrCount = curr.topError.reduce((s, item) => s + item[1], 0);
      const prevErrCount = prev?.topError?.reduce((s, item) => s + item[1], 0) || 0;
      return prevErrCount > 0 && currErrCount / prevErrCount > 2.5;
    },
    level: "critical",
    desc: "前端错误总量相比上一个周期翻倍以上"
  },
  {
    name: "流量断崖下跌",
    expr: (curr, prev) => {
      if (!prev?.summary?.totalPV) return false;
      const ratio = curr.summary.totalPV / prev.summary.totalPV;
      return ratio < 0.3 && curr.summary.totalPV < 5;
    },
    level: "warning",
    desc: "页面访问量大幅下跌,可能站点无法访问"
  }
];

// 读取历史指标快照
function loadHistory() {
  if (!fs.existsSync(HISTORY_PATH)) return null;
  try {
    return JSON.parse(fs.readFileSync(HISTORY_PATH, 'utf-8'));
  } catch {
    return null;
  }
}

// 保存当前指标为历史快照,用于下一轮环比
function saveCurrentSnapshot(data) {
  fs.writeFileSync(HISTORY_PATH, JSON.stringify(data, null, 2), 'utf-8');
}

// Webhook推送消息
function sendWebhook(alerts, report) {
  if (!WEBHOOK_URL) {
    console.log("未配置ALERT_WEBHOOK,跳过推送");
    return Promise.resolve();
  }
  const alertText = alerts.map(a => `[${a.level}] ${a.name}:${a.desc}`).join('\n');
  const payload = {
    msgtype: "text",
    text: {
      content: `【静态站点埋点告警】
生成时间:${report.meta.generateAt}
大盘PV:${report.summary.totalPV},UV:${report.summary.totalUV}
${alertText}`
    }
  };
  return new Promise((resolve, reject) => {
    const req = https.request(WEBHOOK_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' }
    }, res => {
      let buf = '';
      res.on('data', d => buf += d);
      res.on('end', () => resolve({ status: res.statusCode, body: buf }));
    });
    req.on('error', reject);
    req.write(JSON.stringify(payload));
    req.end();
  })
}

async function main() {
  if (!fs.existsSync(REPORT_PATH)) {
    console.log("指标报表不存在,跳过告警");
    return;
  }
  const currReport = JSON.parse(fs.readFileSync(REPORT_PATH, 'utf-8'));
  const prevReport = loadHistory();
  const hitAlerts = [];

  for (const rule of ALERT_RULES) {
    try {
      if (rule.expr(currReport, prevReport)) {
        hitAlerts.push(rule);
      }
    } catch (e) {
      console.error(`规则${rule.name}执行异常`, e);
    }
  }

  if (hitAlerts.length > 0) {
    console.log("触发告警:", hitAlerts.map(x => x.name));
    await sendWebhook(hitAlerts, currReport);
  } else {
    console.log("无告警触发");
  }
  saveCurrentSnapshot(currReport);
}

main().catch(console.error);

流水线集成方式

和之前的日志分析脚本串联,在CI定时任务里顺序执行:

node log-analyzer.js
node alert-analyzer.js

环境变量注入 Webhook 地址,避免硬编码密钥:

variables:
  ALERT_WEBHOOK: $WEBHOOK_SECRET

告警降噪策略(非常关键)

小站点流量波动大,很容易产生误报,增加几条降噪逻辑:

  1. 最小样本阈值:PV过少的时候直接关闭告警,避免没人访问触发“流量下跌”告警;
  2. 冷却窗口:同一告警规则在30分钟内只推送一次,防止持续刷屏;
  3. 黑白名单:可以配置部分页面路径不参与告警(如内部测试页);
  4. 区分告警等级:critical 强通知,warning 只记录、可选择静默。

补充冷却改造示例,在 history.json 中额外记录每条告警最后触发时间,规则内增加时间判断。

工程权衡

  • ✅ 优点:零中间件、轻量化、复用已有的埋点报表,不需要额外存储时序库;
  • ⚠️ 局限:告警粒度和CI调度周期绑定(比如6分钟/1小时),做不到秒级实时;
  • ⚠️ 局限:环比对比只和上一个周期对比,不是多天均值;适合趋势发现,不适合精密监控;
  • ⚠️ 局限:Webhook 适配不同IM(企业微信、飞书、钉钉)的消息体格式不一样,payload 需要微调。

后续演进方向

  1. 增加告警静默计划(比如夜间低峰时段关闭通知);
  2. 增加告警聚合,短时间多条同类告警合并成一条;
  3. 增加恢复通知:指标回归正常后推送“告警已恢复”消息;
  4. 引入Mermaid图表,在Markdown报表里绘制PV、LCP时序趋势图。

、

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。