Skip to main content

Consuming the Prometheus API

Reading time: 0 minute(s) (0 words)

Because the Prometheus API for SLO time series is Prometheus-compatible, it works with the standard Prometheus ecosystem: Grafana, any Prometheus query client SDK, and your own code. All of them authenticate the same way — HTTP Basic auth with a Nobl9 access key, or HTTP Bearer auth with a Nobl9 access token. See the Prometheus API reference for the full authentication details.

Point your client at the base URL without the trailing /api/v1; most clients append that segment themselves:

https://<your-nobl9-instance>/api/prometheus/v1

Grafana data source

  1. In Grafana, go to Connections → Data sources → Add data source and choose Prometheus.
  2. Set Prometheus server URL to https://<your-nobl9-instance>/api/prometheus/v1.
  3. Under Authentication, choose Basic authentication. Enter your access key Client ID as the User and the Client Secret as the Password.
  4. Click Save & test, then build panels with the PromQL examples.
Grafana Add data source form for Prometheus with the Nobl9 server URL and Basic authentication fields filled in
Configuring the Prometheus API as a Grafana data source

For more options, see the Grafana Prometheus data source documentation.

Prometheus client SDKs

Any Prometheus-compatible query client works against the API. The libraries below cover the common languages — point each one at the base URL above and configure HTTP Basic auth.

LanguageLibraryMaintainerLink
Gonobl9-go (built-in Prometheus client)Nobl9github.com/nobl9/nobl9-go
Goclient_golang (api + api/prometheus/v1)Official Prometheusgithub.com/prometheus/client_golang
Pythonprometheus-api-clientCommunitygithub.com/4n4nd/prometheus-api-client-python
JavaScript / TypeScriptprometheus-queryCommunitygithub.com/samber/prometheus-query-js
Rubyprometheus-api-clientCommunitygithub.com/prometheus/prometheus_api_client_ruby
Rustprometheus-http-queryCommunitygithub.com/puetzp/prometheus-http-query

If your language isn't listed, any HTTP client works too — the API speaks the standard Prometheus HTTP API.

Code samples

Each sample below prints the remaining error budget of every objective of a given SLO by running the query budget{project="...",slo="..."}.

  • The Go sample uses the Prometheus client built into nobl9-go, which reads your credentials and API URL from your local sloctl configuration, so if sloctl is configured it runs as-is.
  • The Python and JavaScript samples read credentials and the base URL from environment variables.
go mod init query_budget
go get github.com/nobl9/nobl9-go github.com/prometheus/common
go run . my-project my-slo
query_budget.go
// Command query_budget prints the remaining error budget of every objective of
// a given Nobl9 SLO by querying the Prometheus API for SLO time series.
//
// It uses the Prometheus client built into nobl9-go, which reads credentials and
// the API URL from your local Nobl9 (sloctl) configuration. If sloctl is already
// configured, the program runs as-is:
//
// go mod init query_budget
// go get github.com/nobl9/nobl9-go github.com/prometheus/common
// go run . <slo-project> <slo-name>
package main

import (
"context"
"fmt"
"log"
"os"
"sort"
"time"

"github.com/prometheus/common/model"

"github.com/nobl9/nobl9-go/sdk"
prometheusV1 "github.com/nobl9/nobl9-go/sdk/endpoints/prometheus/v1"
)

func main() {
if len(os.Args) != 3 {
log.Fatalf("usage: %s <slo-project> <slo-name>", os.Args[0])
}
project, slo := os.Args[1], os.Args[2]

log.Println("Reading Nobl9 SDK configuration...")
client, err := sdk.DefaultClient()
if err != nil {
log.Fatalf("failed to create Nobl9 client: %v", err)
}

query := fmt.Sprintf(`budget{project=%q,slo=%q}`, project, slo)
log.Printf("Executing query: %s", query)

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// nobl9-go exposes the Prometheus API directly: it handles authentication
// and routes the request to your organization's Prometheus endpoint.
result, warnings, err := client.Prometheus().V1().Query(ctx, prometheusV1.QueryRequest{
Query: query,
Time: time.Now(),
})
if err != nil {
log.Fatalf("query failed: %v", err)
}
for _, w := range warnings {
log.Printf("warning: %s", w)
}

vector, ok := result.(model.Vector)
if !ok {
log.Fatalf("unexpected result type %T", result)
}
if len(vector) == 0 {
log.Fatalf("no data for SLO %q in project %q", slo, project)
}

sort.Slice(vector, func(i, j int) bool {
return vector[i].Metric["objective"] < vector[j].Metric["objective"]
})

fmt.Println("Budget for objectives:")
for _, sample := range vector {
fmt.Printf("- %s: %f%%\n", sample.Metric["objective"], float64(sample.Value)*100)
}
}

Running any of them produces output similar to:

Budget for objectives:
- objective-1: 95.405634%
- objective-2: -182.190787%