Business flows

A flow is something your customers do, such as signing up or checking out. Flowhawk uses flows to connect everything else.

Most monitoring is organised around servers and services. Flowhawk adds a business map on top, which says which requests belong to which flow and step. With it, an alert names the flow that broke and how many customers it affected, and you can filter traces, logs, errors, sessions and metrics to a single flow.

The business map

The map is a list of flows. Each flow has steps, and each step has one or more rules that match requests by service and route, span name or queue.

flows:
  - id: checkout
    name: Checkout
    criticality: critical        # critical, important or background
    slo:
      availability: 99.5         # percent of requests that succeed
      latencyP95Ms: 800
    steps:
      - id: cart
        name: Add to cart
        match:
          - service: web
            route: POST /cart/items
      - id: pay
        name: Pay
        match:
          - service: payments
            route: POST /payments
      - id: confirm
        name: Send confirmation
        match:
          - queue: order-confirmations

Routes are written as METHOD /path, with :name for path parameters (GET /orders/:id). A rule can leave out the service to match the route in any service.

Drafting the map

Once traffic arrives, Setup drafts the map from the routes it sees, with alerts for the important flows and a first dashboard. You look through the drafts and accept the ones that fit. A coding agent connected over MCP can draft it from your code instead. Later changes go through Settings > Business map, the agent, or the YAML, and every change is a reviewed diff you can undo (config as code).

How requests are matched

  • The first span of a request in a service (its entry) is matched to a step. Spans and logs below it in the same trace inherit the flow and step.
  • With a Flowhawk SDK, the match happens in your service, and the flow travels to the services it calls in the trace's baggage, so a downstream service's work counts toward the same flow.
  • With plain OpenTelemetry or a Sentry SDK, the match happens on our side by service and route. You still see flows. Downstream services are tagged by their own routes.
  • Work that no route starts, such as a cron job or a queue consumer, can name its flow and step itself, with withStep("payouts", "settle", fn) in the SDKs or the span attributes business.flow and business.step with plain OpenTelemetry.

What a flow gives you

  • Requests, error rate and p95 latency for each flow and step, compared with the flow's SLO.
  • How many requests and users failed, and since when.
  • The deploys, flag changes and config changes that line up with a change in the flow, which are the likely causes.
  • Links from the flow to its traces, logs, errors, sessions and metrics, filtered to that flow and the same time window.
  • Collection settings per flow, so you can keep every checkout trace but only a tenth of a background job's (Settings > Collection). Errors and slow requests are kept on top of the sample rate.

Criticality decides how loud a flow is. A broken critical flow pages someone, while a broken background flow only shows in the app.