报警聚合邮件

情景

相信在日常的运维工作中,大家会经常遇到同一个故障类型,在短时间内同时发生在多个不同的主机,然后报警系统就会根据机器的数量发出N封邮件。

比如说第一封邮件显示"主机10.10.10.1在5分钟内丢包率超过50%",然后第二封邮件提示"主机10.10.10.2在5分钟内丢包率超过50%",第三封邮件又提示"主机10.10.10.3在5分钟内丢包率超过50%"...

简直烦不胜烦,而且很容易让大家淹没在邮件中,反而找不到关键的故障报警。

改进的办法?当然是一个可以在一定的时间间隔内将所有同类型故障的告警聚合成一封邮件发出的机制了。出现上述告警情形下,只会发出一封这样的邮件:"主机 10.10.10.1 10.10.10.2 10.10.10.3 共3台主机的丢包率超过50%"。

bosun的grouping函数

这里有个bosun的例子

例子利用了bosun提供的t表达式,该表达式的具体说明可见官方文档

以上面所说的情景为例,假如查询语句是:

$query = q("sum:network.status.pingloss{host=*}", "5m", "")

这里返回的是类似这样的结果(返回的json不是这样的,只是为了说明):

{host="10.10.10.1",{"1464256454":62,"1464256574":78,"1464256694":64}}
{host="10.10.10.2",{"1464256454":70,"1464256574":80,"1464256694":60}}
{host="10.10.10.3",{"1464256454":48,"1464256574":52,"1464256694":56}}
{host="10.10.10.4",{"1464256454":0,"1464256574":0,"1464256694":0}}

为了产生告警值,先取个平均值:

$avg_value = avg($query)

然后得到这样的数据:

{host="10.10.10.1", value=68}
{host="10.10.10.2", value=60}
{host="10.10.10.3", value=52}
{host="10.10.10.4", value=0}

对group里的每个项做判断,然后用t表达式汇总:

$item_group = t($avg_value > 50, "")

得到这样的数据:

{
    "1": 1,
    "2": 1,
    "3": 1,
    "4": 0
}

注意我们只需要value,所以"1"那些key我们不用去理会了。

然后告警的条件是怎样的,只需要其中有一个value是1就可以了,于是我们可以简单地使用sum函数来操作。

$q = sum($item_group)
crit = $q > 0  
critNotification = email  

template

上面设置好了alert,接着设置下template

template pingloss_grouping {  
    subject = {{.Last.Status}}: {{.Alert.Name}} 备注:{{.Alert.Vars.notes}}
    body = `<b>丢包告警</b>
    <br>
    <br>
    <table>
        <th>主机名</th>
        <th>丢包率</th>
        {{ range $f := .EvalAll .Alert.Vars.avg_value }}
        <tr>
            <td>{{ $f.Group.host }}</td>
            <td>{{ $f.Value }}</td>
        </tr>
        {{ end }}
    </table>
    <br>
    <br>
    {{ .Graph .Alert.Vars.query }}
}

非常简单,我们将avg_value用个range列成一个table即可,然后最后的.Graph需要用回q函数的表达式才能绘图。

完整的例子

tsdbHost = localhost:4242  
smtpHost = smtp.163.com:25  
emailFrom = [email protected]  
smtpUsername = test  
smtpPassword = xxxxxxxxxx  
checkFrequency = 2m  
responseLimit = 10485760

notification email {  
    email = [email protected]
    next = email
    timeout = 30m
}

template pingloss_grouping {  
    subject = {{.Last.Status}}: {{.Alert.Name}} 备注:{{.Alert.Vars.notes}}
    body = `<b>丢包告警</b>
    <br>
    <br>
    <table>
        <th>主机名</th>
        <th>丢包率</th>
        {{ range $f := .EvalAll .Alert.Vars.avg_value }}
        <tr>
            <td>{{ $f.Group.host }}</td>
            <td>{{ $f.Value }}</td>
        </tr>
        {{ end }}
    </table>
    <br>
    <br>
    {{ .Graph .Alert.Vars.query }}
}

alert pingloss_grouping {  
    runEvery = 5
    ignoreUnknown = true
    template = pingloss_grouping
    $notes = 丢包告警
    $query = q("sum:network.status.pingloss{host=*}", "5m", "")
    $avg_value = avg($query)
    $item_group = t($avg_value > 50, "")
    $q = sum($item_group)
    crit = $q > 0
    critNotification = email
}