背景概述
最近看到很多群里的小伙伴在讨论,当prometheus
告警时,如何获取当前值以及如何附带最近指标的监控图标,当然我们的告警架构依旧使用prometheus
、alertmanager
、钉钉hook
。那么我们想要获取到当前值也好,还是图标也好,都需要首先获取到当前的promQL
。
效果展示
❝告警通知,使用的是钉钉
hook
,模板可能不是很美观,主要是看效果。当然也是支持获取最新的告警value
的。
前期准备
goland golang sdk 1.22
大致实现思路
通过告警数据获取alertname 通过alertname获取promQL 通过client queryRange获取最近几分钟值 格式化获取到的value 图表渲染 本地测试
核心代码
我们仅测试使用,代码中并不是完整的代码哦,可以自行扩展。
func getAlertQuery(alertName string) *string {
client := NewClient()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
v1api := v1.NewAPI(client)
rules, err := v1api.Rules(ctx)
if err != nil {
return nil
}
for _, rule := range rules.Groups {
for _, query := range rule.Rules {
switch v := query.(type) {
case v1.RecordingRule:
if v.Name == alertName {
return &v.Query
}
case v1.AlertingRule:
if v.Name == alertName {
return &v.Query
}
default:
fmt.Printf("unknown rule type %s", v)
return nil
}
}
}
return nil
}
❝这里主要是获取
promQL
func getQueryRangeValue(query string) []*QueryValue {
client := NewClient()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
v1api := v1.NewAPI(client)
value, _, err := v1api.QueryRange(ctx, query, v1.Range{
Start: time.Now().Add(10 * -time.Second),
End: time.Now(),
Step: 1 * time.Second,
})
if err != nil {
fmt.Printf("查询失败: %v\n", err)
}
//var tv = map[string]string{"instance": "ip-10-19-140-140.ap-southeast-1.compute.internal"}
type tv model.Metric
var queryValues []*QueryValue
var tvvalue = tv{"instance": "ip-10-19-140-140.ap-southeast-1.compute.internal"}
switch v := value.(type) {
case model.Matrix:
for _, frame := range v {
if frame.Metric.Equal(model.Metric(tvvalue)) {
for _, v := range frame.Values {
var queryValue = QueryValue{
Value: fmt.Sprintf("%s", v.Value),
Timestamp: int64(v.Timestamp),
}
queryValues = append(queryValues, &queryValue)
}
return queryValues
}
}
case model.Vector:
fmt.Printf("%+v\n", v)
case *model.Scalar:
fmt.Printf("%+v\n", v)
case *model.String:
fmt.Printf("%+v\n", v)
default:
fmt.Println("unknown value type")
}
return nil
}
❝这里主要是通过
promQL
获取最近一段时间的value
,这里的tv
,我们是直接写死的,仅测试使用而已。
func image(values []*QueryValue, fingerprint string) {
var (
alertSals []float64
Timestamp []time.Time
)
for _, v := range values {
a := time.Unix(v.Timestamp/1000, 0)
Timestamp = append(Timestamp, a)
fv, _ := strconv.ParseFloat(v.Value, 64)
alertSals = append(alertSals, fv)
}
graph := chart.Chart{
Title: "alert message",
XAxis: chart.XAxis{
ValueFormatter: chart.TimeValueFormatterWithFormat("15:04:05"),
},
YAxis: chart.YAxis{
ValueFormatter: func(v interface{}) string {
if vf, isFloat := v.(float64); isFloat {
return fmt.Sprintf("%.3f", vf)
}
return ""
},
},
Series: []chart.Series{
chart.TimeSeries{
Name: "安若",
XValues: Timestamp,
YValues: alertSals,
},
},
}
// 创建输出文件
f, err := os.Create("output.png")
if err != nil {
fmt.Println("Error creating file:", err)
return
}
defer f.Close()
// 渲染图表到文件
err = graph.Render(chart.PNG, f)
if err != nil {
fmt.Println("Error rendering chart:", err)
}
}
❝图片渲染
我们可以直接通过浏览器访问图片
总结
以上就是简单的对prometheus
告警附带图表的实现,当然这里还有一些不完善的地方需要自己去修改一下哦,例如图片的name
,我们可以使用告警指纹
进行命名。
添加👇下面微信,拉你进群与大佬一起探讨云原生!