Pyrra
- SLOs - Service Level Objectives and reliability metrics
Overview
Pyrra turns SLO definitions into Prometheus recording rules: metrics whose names include :burnrate, carrying labels such as slo, backstage_component, or team. Causely reads those rules on its next Prometheus sync and creates an SLO entity for each one, attached to the entity that owns it:
- a single Service, or
- a Component (one logical piece of software, often several Kubernetes Services), for example a Backstage component, or
- a Business Application (a whole product or system).
This integration builds on the Prometheus scraper. Make sure Prometheus is enabled and reachable by the mediator before configuring Pyrra. See Prometheus.
Configuration
Causely resolves the owner of each SLO from the labels on its recording rule. Two Helm settings are involved:
| Setting | Helm location | When you need it |
|---|---|---|
pyrra.associations | scrapers.prometheus.pyrra | Always. Maps the labels on a recording rule to the owner type and to the entity that should own the SLO. |
label_assignments | scrapers.kubernetes | Only for Component-owned SLOs. A rule label such as backstage_component=loki does not tell Causely which Kubernetes Services make up Component loki; label_assignments supplies that link. |
When you set associations explicitly, list every pattern your rules use—Causely does not merge in defaults. Causely tries the blocks top to bottom and uses the first match whose rule labels are all present, so put specific Component patterns before generic Service or Business Application ones.
Service-owned SLOs
The recording rule names the Kubernetes Service directly:
# Rule labels
slo: loki-querier-availability
service_id: loki-querier
k8s_ns: observability
scrapers:
prometheus:
pyrra:
associations:
- entity: { service: {} }
discovery:
- kubernetes_service:
service_name: service_id # rule label holding the Service name
namespace: k8s_ns # rule label holding the namespace
The SLO attaches to Service/observability/loki-querier only.
Business Application-owned SLOs
The recording rule is scoped to a whole product or system:
# Rule labels
slo: observability-ingest-availability
backstage_system: grafana-observability
scrapers:
prometheus:
pyrra:
associations:
- entity: { business_application: {} }
discovery:
- business_application:
name: backstage_system # rule label holding the application name
The SLO attaches under Business Application/grafana-observability.
Component-owned SLOs
The recording rule names a Component that spans several Kubernetes Services:
# Rule labels
slo: loki-querier-availability
backstage_component: loki
backstage_system: grafana-observability
backstage_domain: observability
Causely should create SLO loki-querier-availability, attach it to Component loki, and treat Services loki-querier and loki-ingester as members of that Component—not tempo-querier and tempo-ingestor, which run in the same observability namespace under sibling Component tempo. Neither the recording rule nor the cluster carries that link, so this case takes both settings.
1. Tag the Services with label_assignments. Select Services by labels they already carry (the Loki and Tempo Helm charts stamp app.kubernetes.io/name on every Service they create) and assign the catalog labels your Pyrra rules use. Nothing is written back to the cluster; the labels land only on Causely Service entities, and no Component or SLO is created at this point.
scrapers:
kubernetes:
label_assignments:
- service_selector:
app.kubernetes.io/name: loki # already on loki-querier, loki-ingester, …
labels:
causely.ai/backstage-component-name: loki
causely.ai/backstage-system: grafana-observability
causely.ai/backstage-domain: observability
- service_selector:
app.kubernetes.io/name: tempo # already on tempo-querier, tempo-ingestor, …
labels:
causely.ai/backstage-component-name: tempo
causely.ai/backstage-system: grafana-observability
causely.ai/backstage-domain: observability
2. Match those labels in pyrra.associations.
scrapers:
prometheus:
pyrra:
associations:
- entity: { component: {} }
discovery:
- component:
component_name: backstage_component # rule label → Component name
system_name: backstage_system
domain_name: backstage_domain
service_labels: # rule label → Service entity label
- metric_label: backstage_component
entity_label: causely.ai/backstage-component-name
- metric_label: backstage_system
entity_label: causely.ai/backstage-system
Together, the two settings resolve the Loki rule like this:
- The rule has
backstage_component=loki, so the Component name is loki. service_labelsmaps rule labelsbackstage_componentandbackstage_systemto the entity labels set bylabel_assignments.- Causely finds Services
observability/loki-querierandobservability/loki-ingester. Tempo's Services do not match—they carrycausely.ai/backstage-component-name=tempo. - Causely creates or updates Component/loki, links both Loki Services to it, and attaches SLO loki-querier-availability.
service_labels is the bridge between the two settings: the value of a rule label must match the value of the Service entity label that label_assignments set.
Full example
The overlay below combines all three patterns, with label_assignments supporting the Component-owned one:
scrapers:
kubernetes:
# Map existing Helm chart labels → Backstage catalog labels on Causely Service entities.
label_assignments:
- service_selector:
app.kubernetes.io/name: loki
labels:
causely.ai/backstage-component-name: loki
causely.ai/backstage-system: grafana-observability
causely.ai/backstage-domain: observability
- service_selector:
app.kubernetes.io/name: tempo
labels:
causely.ai/backstage-component-name: tempo
causely.ai/backstage-system: grafana-observability
causely.ai/backstage-domain: observability
prometheus:
pyrra:
associations:
# Component-owned SLOs (backstage_component + backstage_system on recording rules)
- entity: { component: {} }
discovery:
- component:
component_name: backstage_component
system_name: backstage_system
domain_name: backstage_domain
service_labels:
- metric_label: backstage_component
entity_label: causely.ai/backstage-component-name
- metric_label: backstage_system
entity_label: causely.ai/backstage-system
# Service-owned SLOs (service_id + k8s_ns on recording rules)
- entity: { service: {} }
discovery:
- kubernetes_service:
service_name: service_id
namespace: k8s_ns
# Business Application-owned SLOs (backstage_system only on recording rules)
- entity: { business_application: {} }
discovery:
- business_application:
name: backstage_system
Burn alerts
When Pyrra fires an ErrorBudgetBurn alert with slo=loki-querier-availability, Causely activates burn state on that SLO and elevates related Diagnoses as urgent. For how Causely uses SLO targets and burn rates in causal reasoning, see SLO Targets and Burn Rates.