ObservaStack

rules/recording/red.yml

groups:
  - name: red
    rules:
      - record: service:http_requests:rate5m
        expr: sum by (service) (rate(http_requests_total[5m]))
      - record: service:http_requests_errors:rate5m
        expr: sum by (service) (rate(http_requests_total{code=~"5.."}[5m]))
      - record: service_route:http_request_duration_seconds:p95_5m
        expr: histogram_quantile(0.95, sum by (service, route, le) (rate(http_request_duration_seconds_bucket[5m])))
      - record: service_route:http_request_duration_seconds:p99_5m
        expr: histogram_quantile(0.99, sum by (service, route, le) (rate(http_request_duration_seconds_bucket[5m])))
      # Per-service p95 ceilings live here so alerts do not repeat the numbers.
      # `or` keeps every label set. pint's promql/impossible check treats a
      # non-empty left side as dead code, which is wrong for this union.
      # pint disable promql/impossible
      - record: service:http_latency_p95_threshold_seconds:constant
        expr: |
          label_replace(vector(0.40), "service", "storefront", "__name__", ".*")
          or label_replace(vector(0.30), "service", "orders-api", "__name__", ".*")
          or label_replace(vector(1.00), "service", "payments-worker", "__name__", ".*")