mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 03:32:11 +08:00
153 lines
3.5 KiB
Go
153 lines
3.5 KiB
Go
package alertmanager
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/grafana/e2e"
|
|
)
|
|
|
|
const (
|
|
defaultLokiImage = "grafana/loki:latest"
|
|
lokiBinary = "/usr/bin/loki"
|
|
lokiHTTPPort = 3100
|
|
)
|
|
|
|
// GetDefaultImage returns the Docker image to use to run the Loki..
|
|
func GetLokiImage() string {
|
|
if img := os.Getenv("LOKI_IMAGE"); img != "" {
|
|
return img
|
|
}
|
|
|
|
return defaultLokiImage
|
|
}
|
|
|
|
type LokiService struct {
|
|
*e2e.HTTPService
|
|
}
|
|
|
|
func NewLokiService(name string, flags, envVars map[string]string) *LokiService {
|
|
svc := &LokiService{
|
|
HTTPService: e2e.NewHTTPService(
|
|
name,
|
|
GetLokiImage(),
|
|
e2e.NewCommandWithoutEntrypoint(lokiBinary, e2e.BuildArgs(flags)...),
|
|
e2e.NewHTTPReadinessProbe(lokiHTTPPort, "/ready", 200, 299),
|
|
lokiHTTPPort,
|
|
),
|
|
}
|
|
|
|
svc.SetEnvVars(envVars)
|
|
|
|
return svc
|
|
}
|
|
|
|
type LokiClient struct {
|
|
c http.Client
|
|
u *url.URL
|
|
}
|
|
|
|
func NewLokiClient(u string) (*LokiClient, error) {
|
|
pu, err := url.Parse(u)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &LokiClient{
|
|
c: http.Client{},
|
|
u: pu,
|
|
}, nil
|
|
}
|
|
|
|
type LokiQueryResponse struct {
|
|
Status string `json:"status"`
|
|
Data struct {
|
|
ResultType string `json:"resultType"`
|
|
Result []struct {
|
|
Stream struct {
|
|
Condition string `json:"condition"`
|
|
Current string `json:"current"`
|
|
DashboardUID string `json:"dashboardUID"`
|
|
Fingerprint string `json:"fingerprint"`
|
|
FolderUID string `json:"folderUID"`
|
|
From string `json:"from"`
|
|
Group string `json:"group"`
|
|
LabelsAlertname string `json:"labels_alertname"`
|
|
LabelsGrafanaFolder string `json:"labels_grafana_folder"`
|
|
OrgID string `json:"orgID"`
|
|
PanelID string `json:"panelID"`
|
|
Previous string `json:"previous"`
|
|
RuleID string `json:"ruleID"`
|
|
RuleTitle string `json:"ruleTitle"`
|
|
RuleUID string `json:"ruleUID"`
|
|
SchemaVersion string `json:"schemaVersion"`
|
|
ServiceName string `json:"service_name"`
|
|
ValuesB string `json:"values_B"`
|
|
ValuesC string `json:"values_C"`
|
|
} `json:"stream"`
|
|
Values [][]string `json:"values"`
|
|
} `json:"result"`
|
|
}
|
|
}
|
|
|
|
type AlertState string
|
|
|
|
const (
|
|
AlertStateNormal AlertState = "Normal"
|
|
AlertStatePending AlertState = "Pending"
|
|
AlertStateAlerting AlertState = "Alerting"
|
|
)
|
|
|
|
type AlertStateResponse struct {
|
|
State AlertState
|
|
Timestamp time.Time
|
|
}
|
|
|
|
// GetCurrentAlertState fetches the current alert state from loki
|
|
func (c *LokiClient) GetCurrentAlertState() (*AlertStateResponse, error) {
|
|
u := c.u.ResolveReference(&url.URL{Path: "/loki/api/v1/query_range"})
|
|
|
|
vs := url.Values{}
|
|
vs.Add("query", `{from="state-history"} | json`)
|
|
vs.Add("since", "60s")
|
|
|
|
u.RawQuery = vs.Encode()
|
|
|
|
resp, err := c.c.Get(u.String())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
//nolint:errcheck
|
|
defer resp.Body.Close()
|
|
|
|
res := LokiQueryResponse{}
|
|
|
|
if err = json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if res.Status != "success" {
|
|
return nil, fmt.Errorf("failed to query state from loki")
|
|
}
|
|
|
|
if len(res.Data.Result) == 0 {
|
|
return nil, fmt.Errorf("empty result from loki")
|
|
}
|
|
|
|
r := res.Data.Result[0]
|
|
it, err := strconv.ParseInt(r.Values[0][0], 10, 0)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse timestamp: %v", err)
|
|
}
|
|
|
|
return &AlertStateResponse{
|
|
State: AlertState(r.Stream.Current),
|
|
Timestamp: time.Unix(0, it),
|
|
}, nil
|
|
}
|