Skip to content

Instantly share code, notes, and snippets.

@slok
Last active November 11, 2021 06:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slok/314d591df5539905689a5ed32548537e to your computer and use it in GitHub Desktop.
Save slok/314d591df5539905689a5ed32548537e to your computer and use it in GitHub Desktop.
Alertmanager alarm tester. Fire a custom alert to your alertmanager: https://github.com/prometheus/alertmanager
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"net/url"
"regexp"
"strings"
"time"
)
const (
// alertmanager alerts api path.
amAPIPath = "api/v1/alerts"
)
var (
// label regular expression.
labelRgx = regexp.MustCompile("[^=]+=[^=]+")
)
// labelMap is the type to pass multiple labels as flags.
type labelMap map[string]string
// String implements flag.Value interface.
func (l *labelMap) String() string {
return fmt.Sprintf("%v", *l)
}
// Set implements flag.Value interface.
func (l *labelMap) Set(value string) error {
// Check label.
if !labelRgx.Match([]byte(value)) {
return fmt.Errorf("label %s is not in key value format of 'xxx=yyyy'", value)
}
// set the label.
spl := strings.Split(value, "=")
(*l)[spl[0]] = spl[1] // We tust our regexp
return nil
}
// Parses a url to check if it's correct and sets the alertmanagers alerts API path.
func parseURL(checkURL string) (*url.URL, error) {
// Check if is a valid url.
amURL, err := url.ParseRequestURI(checkURL)
if err != nil {
return nil, fmt.Errorf("wrong alertmanager url: %s", checkURL)
}
amURL.Path = amAPIPath
return amURL, nil
}
// amFirer fires alerts to alertmanager.
type amFirer struct {
amURL *url.URL // amURL is the alertmanager url.
}
// fire fires an alert.
func (a *amFirer) fire(alertName string, labels map[string]string) error {
// Add the alertname.
labels["alertname"] = alertName
// Create the alarm body.
value := []struct {
Status string `json:"status"`
Labels map[string]string `json:"labels"`
}{
{
Status: "firing",
Labels: labels,
},
}
body, err := json.Marshal(&value)
if err != nil {
return fmt.Errorf("error generating alert body: %s", err)
}
// Send the alarm.
if _, err := http.Post(a.amURL.String(), "application/json", bytes.NewBuffer(body)); err != nil {
return fmt.Errorf("failed seding the alert: %v", err)
}
return nil
}
// main will trigger a new alarm on the desired alertmanager, this could be used with test purpouses
// or a quick & easy way of manualy triggering an alarm. (https://github.com/prometheus/alertmanager)
// build:
// go build -o amfirer amfirer.go
// Usage examples:
// amfirer -l severity="warning"
// amfirer -l email="true" -address="http://alerts.mycompany.io"
// amfirer -l label_team="team-marketplace" -l severity="pager" -alertname="ClusterIsOnFireOMG"
func main() {
// flags stuff.
var (
amAddr string
labels = labelMap{}
alertName string
)
defAlertName := fmt.Sprintf("test_%d", time.Now().UTC().Unix())
flag.StringVar(&amAddr, "address", "http://127.0.0.1:9093", "alertmanager address")
flag.Var(&labels, "l", "label for the alert in key value format: 'xxx=yyy'")
flag.StringVar(&alertName, "alertname", defAlertName, "the name of the alert")
flag.Parse()
// Set correct url.
amURL, error := parseURL(amAddr)
if error != nil {
log.Fatalf("[ERROR] error parsing alertmanager url: %v", error)
}
f := &amFirer{amURL: amURL}
// Fire the alert.
if err := f.fire(alertName, map[string]string(labels)); err != nil {
log.Fatalf("[ERROR] error firing the alert: %v", err)
}
log.Printf("[OK] Alert %s sent to %s", alertName, f.amURL.String())
}
@till
Copy link

till commented Nov 10, 2021

Found this via google, so cheers for the code.

And then I also remembered that alertmanager has amtool. So assuming it is configured to talk to an alertmanager instance, you can go ahead and create an alert like so (and then wait for it to expire):

$ amtool alert add TEST-ALERT my=label

@slok
Copy link
Author

slok commented Nov 11, 2021

Thanks for the info @till! I did this a long time ago 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment