Skip to main content
This page covers the client requirements, enabling capture, how header names become tag keys, and how to read the results.

Requirements

A request is attributed only when all of the following are true:
  • The instrumented process is the HTTP client. Attribution is counted on the side that sends the request. A server that receives tagged requests does not attribute them.
  • The request carries at least one non-empty X-CostGraph-<key> header. Requests without one are not attributed.
  • The protocol is HTTP/1.1 or HTTP/2 over TCP. HTTP/3 (QUIC over UDP) is not supported.
  • The TLS stack is supported. This means Go’s crypto/tls, or a dynamically loaded libssl.so that exports SSL_read and SSL_write. See Runtime compatibility.
  • The client runs on a Linux node the agent monitors and is visible through the host’s /proc.
  • The process resolves to a container. Requests from processes running directly on the host are dropped unless host-flow collection is enabled.
  • Every proxy hop you want to attribute preserves the header. See Proxies and sidecars.

Runtime compatibility

The rule behind the table: CostGraph needs a TLS library it can hook. Node, Bun, Deno, and static or musl builds compile their TLS into the binary. rustls, Java JSSE, and BoringSSL are TLS stacks CostGraph doesn’t hook yet. To check whether a binary links OpenSSL dynamically, run ldd /path/to/binary | grep libssl. A libssl.so line in the output means the library can be hooked.

Enable capture

Per-request capture runs in the network metrics scraper. Where you turn it on depends on how you run CostGraph:
In the operator chart’s values, set perRequestCollector on the flowtrace component:
The flowtrace DaemonSet already mounts the host’s /proc at /host/proc, so it can see client processes. See Network Metrics scraper for its other settings.

Host processes

By default, requests from processes that don’t belong to a container are dropped. To attribute traffic from processes running directly on the node, also enable host-flow collection: flowtrace.config.includeHostFlows: true in the operator chart, or --flowtrace-include-host-flows on the agent.

Send tagged requests

Add one or more X-CostGraph-<key> headers to the outgoing requests you want to attribute. The part after X-CostGraph- is the tag key, and the header value is the tag value.
Headers are normally set where requests are built, for example in a shared HTTP client, middleware, or a transport wrapper. That way every call carries the context without changes at each call site. The agent only reads these headers. It doesn’t remove them, so every service you call receives them, including third-party APIs. Use values that aren’t sensitive, and add the headers only to requests whose destinations you want attributed.

How header names become keys

Because dashes become underscores, X-CostGraph-Cost-Center and X-CostGraph-Cost_Center produce the same key.

Limits

  • 8 tag keys per request. Extra keys are not recorded.
  • 256 bytes per value. Longer values are truncated. Invalid UTF-8 is replaced with the Unicode replacement character.
Every distinct value becomes its own series. Use values from a bounded set, like a tenant ID, team, or feature name. Don’t use request IDs, timestamps, or anything else that is unique per request.
Header values are stored and shown to anyone with access to your CostGraph organization. Don’t put secrets or personal data in X-CostGraph-* headers.

Proxies and sidecars

Attribution happens at the client process that sends the request. Behind a proxy, each hop that is itself a supported client can be attributed. This works only if the header is still on the request it forwards.
  • If your gateway or proxy strips unknown headers, allow X-CostGraph-* through so later hops can attribute too.
  • A sidecar that originates TLS (for example Envoy in Istio, or the Linkerd proxy) uses a TLS stack that isn’t supported yet. The application’s own request to the sidecar can still be attributed if the application sends it through a supported client.

Read the results

Open Network in the dashboard and go to Request header attribution. The cards at the top show totals for the selected period:
  • Request bytes and Response bytes are the total size of attributed requests and responses, including headers and bodies.
  • Attributed cost is the network cost of those bytes, priced by where the traffic went.
Each card has a Previously footer with the value for the period before. When you compare numbers, compare like with like: the footer is the previous window, not the current one.

Group and filter

  • Group by picks one or more tag keys. With All tags, every key is shown. A request with two keys, like tenant and feature, appears under both, so totals across different keys can add up to more than the overall total.
  • Filter by narrows the results to a tag value, a destination Port, or a Protocol.
  • The table can be sorted by cost or bytes. Expand a row to see the connections behind it.

Locality

Each connection is priced by where its destination was: A cost of 0 means the traffic was measured and the provider doesn’t bill it. A - means the traffic couldn’t be priced because CostGraph doesn’t know where the peer is with enough precision.

Common problems

Check each item in Requirements, in this order:
  1. The header is set on the outgoing request from the client, not on the response or on the server.
  2. The client’s runtime is in the supported half of the compatibility table.
  3. Per-request capture is on for that node. For the operator, flowtrace.config.perRequestCollector defaults to false. See Enable capture.
  4. The process runs in a container, or host-flow collection is on.
  5. The key contains only letters, digits, dashes, or underscores, and the value is not empty.
A proxy along the path is probably stripping the header, or the hop uses an unsupported TLS stack such as a BoringSSL or rustls sidecar. See Proxies and sidecars.
Dashes become underscores, so X-CostGraph-Cost-Center and X-CostGraph-Cost_Center share the key cost_center. Rename one of them.
The traffic was measured, but CostGraph couldn’t place the destination well enough to price it. This is usually a private address that doesn’t match a known resource, or a peer in the same network whose zone isn’t known.