promethues最小化demo示例

Prometheus以scrape_interval(默认为1m)规则周期,从监控目标上收集信息。其中scrape_interval可以基于全局或基于单个metric定义;然后将监控信息持久存储在其本地存储上。

Prometheus以evaluation_interval(默认为1m)另一个独立的规则周期,对告警规则做定期计算。其中evaluation_interval只有全局值;然后更新告警状态。


type Group struct {
    name string
    // promethues evaluation_interval 告警规则做定期计算
    interval time.Duration
    rules    []Rule
}

func (g *Group) Run() {
    fmt.Println(time.Now(), g.name)

    for _, r := range g.rules {
        alerts,err := r.Eval(time.Now())
        if err != nil{
            fmt.Printf("g.name:%s,rule.name:%s,error:%v",g.name,r.GetName(),err)
            continue
        }
        // sendAlarm
        if len(alerts) >0{
            values := []float64{}
            for _,alert := range alerts{
                values = append(values,alert.Value)
            }

            fmt.Printf("time:%v,g.name:%s,rule.name:%s sendAlarm values:%v \n",time.Now(),g.name,r.GetName(),values)
        }

    }
}

type AlertState int

const (
    // StateInactive is the state of an alert that is neither firing nor pending.
    StateInactive AlertState = iota
    // StatePending is the state of an alert that has been active for less than
    // the configured threshold duration.
    StatePending
    // StateFiring is the state of an alert that has been active for longer than
    // the configured threshold duration.
    StateFiring
)

type Alert struct {
    State AlertState

    Labels      Labels
    Annotations Labels

    // The value at the last evaluation of the alerting expression.
    Value float64
    // The interval during which the condition of this alert held true.
    // ResolvedAt will be 0 to indicate a still active alert.
    ActiveAt   time.Time
    FiredAt    time.Time
    ResolvedAt time.Time
}

var seps = []byte{'\xff'}

type Labels []Label

type Label struct {
    Name, Value string
}

// Hash returns a hash value for the label set.
func (ls Labels) Hash() uint64 {
    // Use xxhash.Sum64(b) for fast path as it's faster.
    b := make([]byte, 0, 1024)
    for i, v := range ls {
        if len(b)+len(v.Name)+len(v.Value)+2 >= cap(b) {
            // If labels entry is 1KB+ do not allocate whole entry.
            h := xxhash.New()
            _, _ = h.Write(b)
            for _, v := range ls[i:] {
                _, _ = h.WriteString(v.Name)
                _, _ = h.Write(seps)
                _, _ = h.WriteString(v.Value)
                _, _ = h.Write(seps)
            }
            return h.Sum64()
        }

        b = append(b, v.Name...)
        b = append(b, seps[0])
        b = append(b, v.Value...)
        b = append(b, seps[0])
    }
    return xxhash.Sum64(b)
}

// resolvedRetention is the duration for which a resolved alert instance
// is kept in memory state and consequently repeatedly sent to the AlertManager.
const resolvedRetention = 15 * time.Minute

type Rule interface {
    Eval(ts time.Time) (tmls []*Alert, err error)
    GetName() string
}

type AlertingRule struct {
    name string
    // 报警表达式
    vector string
    // 持续时间
    holdDuration time.Duration
    labels       Labels
    annotations  Labels
    // A map of alerts which are currently active (Pending or Firing), keyed by
    // the fingerprint of the labelset they correspond to.
    active map[uint64]*Alert
}

func (r *AlertingRule) GetName() string {
    return r.name
}
func (r *AlertingRule) Eval(ts time.Time) (tmls []*Alert, err error) {

    res, err := query(r.vector, ts)
    if err != nil {
        return nil, err
    }

    alerts := make(map[uint64]*Alert, len(res))
    resultFPs := map[uint64]struct{}{}
    // step 1:将当前的符合报警的结果,塞入alerts,状态为StatePending
    for _, smpl := range res {
        expand := func(text string) string {
            return fmt.Sprintf(`
                __alert_:%s,
                __vector_:%s,
                __value_:%s,
                __smpl_:%s`,
                r.name, r.vector, text,smpl)
        }
        annotations := make(Labels, 0, len(r.annotations))
        for _, a := range r.annotations {
            annotations = append(annotations, Label{Name: a.Name, Value: expand(a.Value)})
        }
        labels := make(Labels, 0, len(r.labels))
        for _, l := range r.labels {
            labels = append(labels, Label{Name: l.Name, Value: expand(l.Value)})
        }

        h := labels.Hash()
        resultFPs[h] = struct{}{}

        if _, ok := alerts[h]; ok {
            return nil, fmt.Errorf("vector contains metrics with the same labelset after applying alert labels")
        }

        alerts[h] = &Alert{
            Labels:      labels,
            Annotations: annotations,
            ActiveAt:    ts,
            State:       StatePending,
            Value:       smpl,
        }

    }

    for h, a := range alerts {
        // Check whether we already have alerting state for the identifying label set.
        // Update the last value and annotations if so, create a new alert entry otherwise.
        if alert, ok := r.active[h]; ok && alert.State != StateInactive {
            alert.Value = a.Value
            alert.Annotations = a.Annotations
            continue
        }

        r.active[h] = a
    }

    // Check if any pending alerts should be removed or fire now. Write out alert timeseries.
    for fp, a := range r.active {
        if _, ok := resultFPs[fp]; !ok {
            // If the alert was previously firing, keep it around for a given
            // retention time so it is reported as resolved to the AlertManager.
            if a.State == StatePending || (!a.ResolvedAt.IsZero() && ts.Sub(a.ResolvedAt) > resolvedRetention) {
                delete(r.active, fp)
            }
            if a.State != StateInactive {
                a.State = StateInactive
                a.ResolvedAt = ts
            }
            continue
        }

        if a.State == StatePending && ts.Sub(a.ActiveAt) >= r.holdDuration {
            a.State = StateFiring
            a.FiredAt = ts
        }
        if a.State == StateFiring{
            tmls = append(tmls, a)
        }
    }

    return tmls, nil
}

// promethues 通过scrape_interval 定时采集
var SourceData = map[string]map[string][]float64{
    "mysql_cpu": {
        "2022-05-17 16:26": []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
        "2022-05-17 16:27": []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
        "2022-05-17 16:28": []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
        "2022-05-17 16:29": []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
        "2022-05-17 16:30": []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
        "2022-05-17 16:31": []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
        "2022-05-17 16:32": []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
    },
}

func query(vector string, ts time.Time) (res []float64, err error) {
    // demo
    ends := strings.Split(vector, ">")
    key := ends[0]
    target, _ := strconv.ParseFloat(ends[1],64)
    for _, v := range SourceData[key][ts.Format("2006-01-02 15:04")] {
        if v > target {
            res = append(res, v)
        }
    }
    return res, nil
}

func main() {
    rules1 := make([]Rule, 0)
    rules1 = append(rules1, &AlertingRule{
        name:         "mysql_cpu",
        vector:       "mysql_cpu>10",
        holdDuration: time.Minute * 2,
        labels: Labels{
            Label{
                Name:  "level",
                Value: "critical",
            },
        },
        annotations: Labels{
            Label{
                Name:  "detail",
                Value: "数据库cpu",
            },
        },
        active:map[uint64]*Alert{},
    })

    groups := []Group{
        {
            name:     "group1",
            interval: time.Minute,
            rules:    rules1,
        },
    }

    for _, group := range groups {
        go func(group Group) {
            for {
                group.Run()
                time.Sleep(group.interval)
            }
        }(group)
    }

    select {}
}

最后结果:满足持续时间2min后报警,当不满足时不报警

prometheus抓取数据后,根据告警规则计算,表达式为真时,进入pending状态,当持续时间超过for配置的时间后进入active状态;数据同时会推送至alertmanager,在经过group_wait后发送通知。

告警延迟或频发

根据整个告警流程来看,在数据到达alertmanager后,如果group_wait设置越大,则收到告警的时间也就越长,也就会造成告警延迟;同理,如果group_wait设置过小,则频繁收到告警。因此,需要按照具体场景进行设置。

不该告警的时候告警了

prometheus每经过scrape_interval时间向target拉取数据,再进行计算。与此同时,target的数据可能已经恢复正常了,也就是说,在for计算过程中,原数据已经恢复了正常,但是被告警跳过了,达到了持续时间,就触发了告警,也就发送了告警通知。但从grafana中看,认为数据正常,不应发送告警。这是因为grafana以prometheus为数据源时,是range query,而不是像告警数据那样稀疏的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF最小化托盘(System Tray)的实现可以通过以下步骤来完成: 1. 首先,在XAML文件中创建一个托盘图标。可以使用Rectangle、Ellipse或Image等控件来作为图标,然后设置图标的宽度、高度和颜色等属性。 ```xml <Rectangle Width="16" Height="16" Fill="Red" /> ``` 2. 在MainWindow.xaml.cs文件中,首先添加以下命名空间: ```csharp using System.Windows.Forms; ``` 3. 在MainWindow.xaml.cs文件中,创建一个NotifyIcon对象,并在窗口加载事件中进行初始化,包括设置托盘图标和右键菜单等属性。 ```csharp private NotifyIcon notifyIcon; private void MainWindow_Loaded(object sender, RoutedEventArgs e) { notifyIcon = new NotifyIcon(); notifyIcon.Icon = new System.Drawing.Icon("Icon.ico"); notifyIcon.Visible = true; notifyIcon.Text = "My WPF Application"; ContextMenu menu = new ContextMenu(); // 创建右键菜单 MenuItem showMenuItem = new MenuItem(); showMenuItem.Text = "显示"; showMenuItem.Click += new EventHandler(ShowMenuItem_Click); menu.MenuItems.Add(showMenuItem); MenuItem exitMenuItem = new MenuItem(); exitMenuItem.Text = "退出"; exitMenuItem.Click += new EventHandler(ExitMenuItem_Click); menu.MenuItems.Add(exitMenuItem); notifyIcon.ContextMenu = menu; } ``` 4. 创建点击事件处理方法来处理托盘图标的左键双击事件,以及右键菜单中的"显示"和"退出"事件。 ```csharp private void TrayIcon_DoubleClick(object sender, EventArgs e) { this.Show(); // 双击托盘图标时显示主窗口 this.WindowState = WindowState.Normal; } private void ShowMenuItem_Click(object sender, EventArgs e) { this.Show(); // 右键菜单中点击"显示"时显示主窗口 this.WindowState = WindowState.Normal; } private void ExitMenuItem_Click(object sender, EventArgs e) { this.Close(); // 右键菜单中点击"退出"时关闭应用程序 } ``` 5. 最后,在MainWindow.xaml文件中的Window标签中添加Loaded事件调用MainWindow_Loaded方法。 ```xml <Window x:Class="Demo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WPF最小化托盘Demo" Height="450" Width="800" Loaded="MainWindow_Loaded"> <!-- 主窗口内容 --> </Window> ``` 通过以上步骤,我们可以实现一个简单的WPF最小化托盘Demo,点击托盘图标可以显示主窗口,右键菜单中可以选择显示或退出应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值