Docs
Try Apollo Studio

Collecting metrics in the Apollo Router


The Apollo Router provides built-in support for metrics collection via Prometheus and OpenTelemetry Collector.

Using Prometheus

You can use Prometheus and Grafana to collect metrics and visualize the router metrics.

router.yaml
telemetry:
metrics:
prometheus:
# By setting this endpoint you enable the prometheus exporter
# All our endpoints exposed by plugins are namespaced by the name of the plugin
# Then to access to this prometheus endpoint, the full url path will be `/plugins/apollo.telemetry/prometheus`
enabled: true

Assuming you're running locally:

  1. Run a query against the router.
  2. Navigate to http://localhost:4000/plugins/apollo.telemetry/prometheus to see something like:
# HELP http_request_duration_seconds Total number of HTTP requests made.
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.5"} 1
http_request_duration_seconds_bucket{le="0.9"} 1
---SNIP---

Note that if you haven't run a query against the router yet, you'll see a blank page because no metrics have been generated!

The following metrics are available using Prometheus:

  • HTTP router request duration (http_request_duration_seconds_bucket)
  • HTTP request duration by subgraph (http_request_duration_seconds_bucket with attribute subgraph)
  • Total number of HTTP requests by HTTP Status (http_requests_total)
  • Total number of HTTP requests in error (http_requests_error_total)

Using OpenTelemetry Collector

You can send metrics to OpenTelemetry Collector for processing and reporting metrics.

router.yaml
telemetry:
metrics:
otlp:
# Either 'default' or a URL
endpoint: default
# Optional protocol. Only grpc is supported currently.
# Setting to http will result in configuration failure.
protocol: grpc
# Optional Grpc configuration
grpc:
domain_name: "my.domain"
key:
file: ""
# env: ""
ca:
file: ""
# env: ""
cert:
file: ""
# env: ""
metadata:
foo: bar
# Optional timeout in humatime form
timeout: 2s

Adding custom attributes/labels

You can add custom attributes (OpenTelemetry) and labels (Prometheus) to your generated metrics. You can apply these across all requests, or you can selectively apply them based on the details of a particular request. These details include:

  • The presence of a particular HTTP header
  • The value at a particular JSON path within a request or response body (either from a subgraph or from the router itself)
  • A custom value provided via the router plugin context

Examples of all of these are shown in the file below:

router.yaml
telemetry:
metrics:
common:
attributes:
router: # Attribute configuration for requests to/responses from the router
static:
- name: "version"
value: "v1.0.0"
request:
header:
- named: "content-type"
rename: "payload_type"
default: "application/json"
- named: "x-custom-header-to-add"
response:
body:
# Apply the value of the provided path of the router's response body as an attribute
- path: .errors[0].extensions.status
name: error_from_body
context:
# Apply the indicated element from the plugin chain's context as an attribute
- named: my_key
subgraph: # Attribute configuration for requests to/responses from subgraphs
all:
static:
# Always apply this attribute to all metrics for all subgraphs
- name: kind
value: subgraph_request
errors: # Only work if it's a valid GraphQL error (for example if the subgraph returns an http error or if the router can't reach the subgraph)
include_messages: true # Will include the error message in a message attribute
extensions: # Include extensions data
- name: subgraph_error_extended_type # Name of the attribute
path: .type # JSON query path to fetch data from extensions
- name: message
path: .reason
# Will create this kind of metric for example http_requests_error_total{message="cannot contact the subgraph",service_name="apollo-router",subgraph="my_subgraph_name",subgraph_error_extended_type="SubrequestHttpError"}
subgraphs:
my_subgraph_name: # Apply these rules only for the subgraph named `my_subgraph_name`
request:
header:
- named: "x-custom-header"
body:
# Apply the value of the provided path of the router's request body as an attribute (here it's the query)
- path: .query
name: query
default: UNKNOWN

Example JSON path queries

Let's say you have a JSON request body with the following structure:

{
"items": [
{
"unwanted": 7,
"wanted": { "x": 3, "y": 7 },
"array": [3, 2, 1]
},
{
"isImportant": true
}
]
}

To fetch the value of the field isImportant, the corresponding path is .items[1].isImportant.

To fetch the value of the field x, the corresponding path is .items[0].wanted.x.

JSON path queries always begin with a period .

Adding custom resources

Resources are similar to attributes, but there are more globals. They're configured directly on the metrics exporter, which means they're always present on each of your metrics.

As an example, it can be useful to set a service.name resource to help you identify metrics related to a particular service:

router.yaml
telemetry:
metrics:
common:
resources:
# Set the service name to easily find metrics related to the apollo-router in your metrics dashboards
service.name: "apollo-router"

See OpenTelemetry conventions for resources.

For example, if you want to use a Datadog agent and specify a service name, you should set the service.name resource as shown above and described in the conventions document.

Edit on GitHub
Previous
Apollo Studio reporting
Next
Tracing