日志服务支持根据仪表盘中的查询图表设置告警,实现实时的服务状态监控。

告警的查询区间和执行间隔

告警的实现原理是基于告警的查询范围,根据执行间隔定时执行配置的查询语句,并将查询结果作为告警条件的参数进行计算,如果计算结果为true,则告警触发。

不要将查询范围设置成和执行间隔一致的相对时间,如查询范围为相对1分钟,执行间隔为1分钟。原因如下(以执行间隔为1分钟为例):
  • 数据写入日志服务到能够被查询到中间存在延时,即便延时很低,也存在数据漏查的风险。如告警执行时间为12:03:30, 查询范围为相对一分钟则为[12:02:30,12:03:30),对于12:03:29秒写入的日志,不能保证12:03:30这次时间点能够查询到。
    • 如果对告警的准确性要求高(不重复报警,不漏报),查询范围起止时间可以往前推移,如 70秒前—10秒前。如告警执行时间为12:03:30,则查询范围为 [12:02:20, 12:03:20),通过设置10秒的缓冲时间来避免因为索引速度导致的漏查。
    • 如果对实时性要求高(第一时间收到告警,能够容忍重复报警),查询范围开始时间可以往前推移,如 70秒—现在。如告警执行时间为12:03:30, 查询范围设置为相对70秒, [12:02:20, 12:03:30)。
  • 对于写入包含同一分钟不同时间的日志时,由于日志服务的索引构建方式,可能会存在较晚的日志的索引落入较早的日志的时间点的可能。 如告警执行时间为12:03:30, 查询范围为相对一分钟则为[12:02:30,12:03:30),如果在12:02:50秒写入多条日志,这些日志的时间有 12:02:20,12:02:50等,那么这一批日志的索引可能会落入12:02:20 这个时间点,导致使用时间范围 [12:02:30,12:03:30) 查询不到。
    • 如果对告警的准确性要求高(不重复报警,不漏报),查询范围使用整点分钟,如整点1分钟,整点5分钟,整点1小时等,并且将执行间隔设置成一致的时间,如1分钟,5分钟,1小时等。
    • 如果对实时性要求高(第一时间收到告警,能够容忍重复报警),查询时间范围至少需要包含前一分钟。如告警执行时间为12:03:30, 查询范围可以设置为相对90秒,那么实际的查询范围为 12:02:00 - 12:03:30,同时设置执行间隔为1分钟。

基于查询结果告警

如果针对某个查询,只要查询结果不为空就认为满足告警条件,可以设置告警条件为判断任意字段存在即告警。如搜索包含IP 10.240.80.234 的日志:

只要查询到包含 10.240.80.234 的日志就告警,则可以通过任意字段设置一个始终为true的告警条件。假设 client_ip 这个字段在每条日志都存在且不可能为空字符串,则只要 client_ip 这个字段不为空就触发告警:

基于分析结果告警

基于分析结果设置告警是最常见的场景,比如针对特定的字段聚合之后告警。以最常见的包含ERROR 关键字的日志条数达到阈值即触发告警为例,查询语句可以按照如下的方式设置:
ERROR | select count(1) as errorCount
告警条件则为 errorCount 大于某个阈值,如 errorCount > 0。

关联查询告警

当从仪表盘入口创建告警时,可以选择多个图表作为告警查询的输入。
  • 对不同时间范围的查询结果进行组合告警。
    如 15分钟内的PV 大于100000 且一小时内的UV 小于1000时触发告警:
    仪表盘告警
    说明 在选择多个图表时,查询区间相互独立。在触发条件中需要使用 ${编号}.{字段} 的方式引用查询结果中的字段。如:$0.pv > 100000 && $1.uv < 1000 。
  • 基于部分图表告警,其他图表的查询结果作为辅助信息。
    基于日志级别为ERROR的日志条数告警,查询语句:
    level: ERROR | select count(1) as errorCount
    告警条件:
    errorCount > 10
    与此同时,也希望能够在告警通知中看到实际的日志级别为ERROR的日志,则可以再配置第2个查询:
    level: ERROR
    在告警通知中只需要设置:
    ${results[1].RawResultsAsKv}
    即可看到实际的日志级别为ERROR的日志。

告警抑制

当告警触发时,可能会在一段时间内多次收到通知。为了防止因为数据抖动导致的误报和重复告警,可以通过如下两种方式对告警进行抑制:
  • 设置连续触发通知阈值。

    只有告警在连续多次检查中都满足告警条件才会触发告警。

    如告警执行间隔为1分钟,触发阈值为5,则表示在连续5次即5分钟内每次告警检查结果都满足告警条件才会发送通知。只要有一次没有满足触发条件,计数将会重置。

  • 设置通知间隔。
    当告警设置的执行间隔较小时,防止频繁收到通知,可以设置两次通知之间的最小间隔。如告警执行间隔为1分钟,通知间隔为30分钟,即使30分钟内有告警触发,也不会收到任何通知。
    通知间隔

关闭告警通知

收到告警通知之后,如果希望临时关闭通知。可以通过告警概览页面关闭通知,如下图所示:

选择关闭的时长,如30分钟:

则在30分钟内,不会再发送任何通知,即便告警触发。在30分钟之后,通知自动恢复。

钉钉群成员查看告警

钉钉群是最常见的告警通知渠道,在配置钉钉通知时,我们可以@钉钉群的成员处理告警。如下图所示:

说明 需要在被@人列表发送内容中同时指定对应成员的手机号。被@人列表是用于识别发送内容中的@是提醒还是普通的@字符。

使用模版变量丰富通知内容

在配置通知方式时,可以使用模版变量来丰富通知内容。邮件标题,钉钉标题,消息内容都支持使用模版变量。 每次告警执行的时候,都会生成一个告警的上下文,其中的每个变量都可以作为模版变量,完整的变量可以参考通知方式
  • 对于顶层的变量如Project,AlertName,Dashboard,可以直接使用${project} 这种方式引用,不区分大小写。
  • 对于每个查询的上下文,包含在Results 这个数组中,数组中的每个元素对应告警关联的一个图表(对于大多数场景,可能只有一个元素),包含的变量如下所示:
    {
      "EndTime": "2006-01-02 15:04:05",
      "EndTimeTs": 1542507580,
      "FireResult": {
        "__time__": "1542453580",
        "field": "value1",
        "count": "100"
      },
      "FireResultAsKv": "[field:value1,count:100]",
      "Truncated": false,
      "LogStore": "test-logstore",
      "Query": "* | SELECT field, count(1) group by field",
      "QueryUrl": "http://xxxx",
      "RawResultCount": 2,
      "RawResults": [
        {
          "__time__": "1542453580",
          "field": "value1",
          "count": "100"
        },
        {
          "__time__": "1542453580",
          "field": "value2",
          "count": "20"
        }
      ],
      "RawResultsAsKv": "[field:value1,count:100],[field:value2,count:20]",
      "StartTime": "2006-01-02 15:04:05",
      "StartTimeTs": 1542453580
    }
    字段解释可以参考告警日志字段。Results中的字段时可以通过如下方式引用:
    • 数组类型通过"${fieldName[{index}]}"方式引用, 下标从0开始。如 ${results[0]} 表示引用Results的第1个元素。
    • 对象类型通过"${object.key}"引用,如 ${results[0].StartTimeTs}的结果为 1542453580。
    说明 只有RawResults 和FireResult 内的字段为查询结果,区分大小写,其他字段均不区分大小写。

排查告警未触发原因

配置告警之后,可以通过查看告警记录查看告警统计。对于单次告警的上下文,可以直接在internal-alert-history这个Logstore中查看,如下图所示。

日志字段解释参考告警日志字段

每次执行都会生成一个唯一的告警ID和一条对应的日志,日志中包含了告警执行的状态和查询的结果(如果查询结果超过2KB,会被截断),通过日志可以排查告警没有触发的原因。