Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions docs/components/Prometheus.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import { CardGrid, LinkCard } from "@astrojs/starlight/components";
<LinkCard title="Create Silence" href="#create-silence" description="Create a silence in Alertmanager to suppress alerts" />
<LinkCard title="Expire Silence" href="#expire-silence" description="Expire an active silence in Alertmanager" />
<LinkCard title="Get Alert" href="#get-alert" description="Get a Prometheus alert by name" />
<LinkCard title="Get Silence" href="#get-silence" description="Get a silence from Alertmanager by ID" />
<LinkCard title="Query" href="#query" description="Execute a PromQL instant query" />
<LinkCard title="Query Range" href="#query-range" description="Execute a PromQL range query" />
</CardGrid>

## Instructions
Expand Down Expand Up @@ -217,3 +220,133 @@ Emits one `prometheus.alert` payload with labels, annotations, state, and timing
}
```

<a id="get-silence"></a>

## Get Silence

The Get Silence component retrieves a silence from Alertmanager (`GET /api/v2/silence/{silenceID}`) by its ID.

### Configuration

- **Silence ID**: Required ID of the silence to retrieve (supports expressions, e.g. `{{ $['Create Silence'].silenceID }}`)

### Output

Emits one `prometheus.silence` payload with silence ID, status, matchers, timing, and creator info.

### Example Output

```json
{
"data": {
"comment": "Scheduled maintenance window",
"createdBy": "SuperPlane",
"endsAt": "2026-02-12T17:30:00Z",
"matchers": [
{
"isEqual": true,
"isRegex": false,
"name": "alertname",
"value": "HighLatency"
}
],
"silenceID": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
"startsAt": "2026-02-12T16:30:00Z",
"status": "active"
},
"timestamp": "2026-02-12T16:30:05.123456789Z",
"type": "prometheus.silence"
}
```

<a id="query"></a>

## Query

The Query component executes an instant PromQL query against Prometheus (`GET /api/v1/query`).

### Configuration

- **Query**: Required PromQL expression to evaluate (supports expressions). Example: `up`

### Output

Emits one `prometheus.query` payload with the result type and results.

### Example Output

```json
{
"data": {
"result": [
{
"metric": {
"__name__": "up",
"instance": "localhost:9090",
"job": "prometheus"
},
"value": [
1708000000,
"1"
]
}
],
"resultType": "vector"
},
"timestamp": "2026-02-12T16:30:05.123456789Z",
"type": "prometheus.query"
}
```

<a id="query-range"></a>

## Query Range

The Query Range component executes a range PromQL query against Prometheus (`GET /api/v1/query_range`).

### Configuration

- **Query**: Required PromQL expression to evaluate (supports expressions). Example: `up`
- **Start**: Required start timestamp in RFC3339 or Unix format (supports expressions). Example: `2026-01-01T00:00:00Z`
- **End**: Required end timestamp in RFC3339 or Unix format (supports expressions). Example: `2026-01-02T00:00:00Z`
- **Step**: Required query resolution step (e.g. `15s`, `1m`)

### Output

Emits one `prometheus.queryRange` payload with the result type and results.

### Example Output

```json
{
"data": {
"result": [
{
"metric": {
"__name__": "up",
"instance": "localhost:9090",
"job": "prometheus"
},
"values": [
[
1708000000,
"1"
],
[
1708000015,
"1"
],
[
1708000030,
"1"
]
]
}
],
"resultType": "matrix"
},
"timestamp": "2026-02-12T16:30:05.123456789Z",
"type": "prometheus.queryRange"
}
```

50 changes: 47 additions & 3 deletions pkg/integrations/prometheus/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,14 @@ type silenceResponse struct {
}

type AlertmanagerSilence struct {
ID string `json:"id"`
Status AlertmanagerSilenceStatus `json:"status"`
Comment string `json:"comment"`
ID string `json:"id"`
Status AlertmanagerSilenceStatus `json:"status"`
Matchers []Matcher `json:"matchers"`
StartsAt string `json:"startsAt"`
EndsAt string `json:"endsAt"`
CreatedBy string `json:"createdBy"`
Comment string `json:"comment"`
UpdatedAt string `json:"updatedAt"`
}

type AlertmanagerSilenceStatus struct {
Expand Down Expand Up @@ -191,6 +196,30 @@ func (c *Client) Query(query string) (map[string]any, error) {
return response.Data, nil
}

func (c *Client) QueryRange(query, start, end, step string) (map[string]any, error) {
apiPath := fmt.Sprintf("/api/v1/query_range?query=%s&start=%s&end=%s&step=%s",
url.QueryEscape(query),
url.QueryEscape(start),
url.QueryEscape(end),
url.QueryEscape(step),
)
body, err := c.execRequest(http.MethodGet, apiPath)
if err != nil {
return nil, err
}

response := prometheusResponse[map[string]any]{}
if err := decodeResponse(body, &response); err != nil {
return nil, err
}

if response.Status != "success" {
return nil, formatPrometheusError(response.ErrorType, response.Error)
}

return response.Data, nil
}

func (c *Client) alertmanagerBaseURL() string {
if c.alertmanagerURL != "" {
return c.alertmanagerURL
Expand Down Expand Up @@ -239,6 +268,21 @@ func (c *Client) ExpireSilence(silenceID string) error {
return err
}

func (c *Client) GetSilence(silenceID string) (AlertmanagerSilence, error) {
apiURL := fmt.Sprintf("%s/api/v2/silence/%s", c.alertmanagerBaseURL(), silenceID)
body, err := c.execRequestWithBodyAndURL(http.MethodGet, apiURL, nil)
if err != nil {
return AlertmanagerSilence{}, err
}

response := AlertmanagerSilence{}
if err := decodeResponse(body, &response); err != nil {
return AlertmanagerSilence{}, err
}

return response, nil
}

func (c *Client) execRequest(method string, path string) ([]byte, error) {
return c.execRequestWithBody(method, path, nil)
}
Expand Down
30 changes: 30 additions & 0 deletions pkg/integrations/prometheus/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ var exampleOutputCreateSilenceBytes []byte
//go:embed example_output_expire_silence.json
var exampleOutputExpireSilenceBytes []byte

//go:embed example_output_get_silence.json
var exampleOutputGetSilenceBytes []byte

//go:embed example_output_query.json
var exampleOutputQueryBytes []byte

//go:embed example_output_query_range.json
var exampleOutputQueryRangeBytes []byte

var exampleDataOnAlertOnce sync.Once
var exampleDataOnAlert map[string]any

Expand All @@ -31,6 +40,15 @@ var exampleOutputCreateSilence map[string]any
var exampleOutputExpireSilenceOnce sync.Once
var exampleOutputExpireSilence map[string]any

var exampleOutputGetSilenceOnce sync.Once
var exampleOutputGetSilence map[string]any

var exampleOutputQueryOnce sync.Once
var exampleOutputQuery map[string]any

var exampleOutputQueryRangeOnce sync.Once
var exampleOutputQueryRange map[string]any

func (t *OnAlert) ExampleData() map[string]any {
return utils.UnmarshalEmbeddedJSON(&exampleDataOnAlertOnce, exampleDataOnAlertBytes, &exampleDataOnAlert)
}
Expand All @@ -46,3 +64,15 @@ func (c *CreateSilence) ExampleOutput() map[string]any {
func (c *ExpireSilence) ExampleOutput() map[string]any {
return utils.UnmarshalEmbeddedJSON(&exampleOutputExpireSilenceOnce, exampleOutputExpireSilenceBytes, &exampleOutputExpireSilence)
}

func (c *GetSilence) ExampleOutput() map[string]any {
return utils.UnmarshalEmbeddedJSON(&exampleOutputGetSilenceOnce, exampleOutputGetSilenceBytes, &exampleOutputGetSilence)
}

func (c *Query) ExampleOutput() map[string]any {
return utils.UnmarshalEmbeddedJSON(&exampleOutputQueryOnce, exampleOutputQueryBytes, &exampleOutputQuery)
}

func (c *QueryRange) ExampleOutput() map[string]any {
return utils.UnmarshalEmbeddedJSON(&exampleOutputQueryRangeOnce, exampleOutputQueryRangeBytes, &exampleOutputQueryRange)
}
20 changes: 20 additions & 0 deletions pkg/integrations/prometheus/example_output_get_silence.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"data": {
"silenceID": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
"status": "active",
"matchers": [
{
"name": "alertname",
"value": "HighLatency",
"isRegex": false,
"isEqual": true
}
],
"startsAt": "2026-02-12T16:30:00Z",
"endsAt": "2026-02-12T17:30:00Z",
"createdBy": "SuperPlane",
"comment": "Scheduled maintenance window"
},
"timestamp": "2026-02-12T16:30:05.123456789Z",
"type": "prometheus.silence"
}
17 changes: 17 additions & 0 deletions pkg/integrations/prometheus/example_output_query.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"__name__": "up",
"instance": "localhost:9090",
"job": "prometheus"
},
"value": [1708000000, "1"]
}
]
},
"timestamp": "2026-02-12T16:30:05.123456789Z",
"type": "prometheus.query"
}
21 changes: 21 additions & 0 deletions pkg/integrations/prometheus/example_output_query_range.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"data": {
"resultType": "matrix",
"result": [
{
"metric": {
"__name__": "up",
"instance": "localhost:9090",
"job": "prometheus"
},
"values": [
[1708000000, "1"],
[1708000015, "1"],
[1708000030, "1"]
]
}
]
},
"timestamp": "2026-02-12T16:30:05.123456789Z",
"type": "prometheus.queryRange"
}
Loading