Skip to content

Commit

Permalink
add documentation for prometheus plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
EmrysMyrddin committed May 7, 2024
1 parent a517979 commit e4fdacf
Showing 1 changed file with 177 additions and 0 deletions.
177 changes: 177 additions & 0 deletions website/src/pages/docs/features/monitoring.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
---
description: How to monitor your GraphQL server using Prometheus.
---

import { Callout } from '@theguild/components'

# Monitoring

Once in production, it's important to monitor your GraphQL server.

A common way to monitor your server is by using Prometheus, a popular, free and open-source
monitoring system.

## Getting Started

To get started, you need to install the `@graphql-yoga/plugin-prometheus` package.

This plugin tracks the complete execution flow, and reports metrics using Prometheus tracing (based
on `prom-client`).

```sh npm2yarn
npm i prom-client @graphql-yoga/plugin-prometheus
```

You can then add the plugin to your GraphQL server:

```ts
import { execute, parse, specifiedRules, subscribe, validate } from 'graphql'
import { envelop, useEngine } from '@envelop/core'
import { usePrometheus } from '@envelop/prometheus'

const getEnveloped = envelop({
plugins: [
useEngine({ parse, validate, specifiedRules, execute, subscribe }),
// ... other plugins ...
usePrometheus({
endpoint: '/metrics', // optional, default is `/metrics`, you can disable it by setting it to `false` if registry is configured in "push" mode
// all optional, and by default, all set to false, please opt-in to the metrics you wish to get
requestCount: true, // requires `execute` to be true as well
requestSummary: true, // requires `execute` to be true as well
parse: true,
validate: true,
contextBuilding: true,
execute: true,
errors: true,
resolvers: true, // requires "execute" to be `true` as well
resolversWhitelist: ['Mutation.*', 'Query.user'], // reports metrics als for these resolvers, leave `undefined` to report all fields
deprecatedFields: true,
registry: myRegistry // If you are using a custom prom-client registry, please set it here
})
]
})
```

<Callout type="warning">
Tracing resolvers using `resolvers: true` might have a performance impact on your GraphQL runtime.
Please consider to test it locally first and then decide if it's needed.
</Callout>

Now, you can access the metrics by visiting the `/metrics` endpoint of your server.

You can then configure Prometheus to scrape the metrics from your server by using this URL.

## Configuration

### Available metrics

You can opt-in to collect tracing from the following phases:

- HTTP request process time (`http`)
- Graphql successful requests (`requestCount`)
- Graphql request summary (`requestSummary`)
- `errors` (categorized by `phase`)
- `resolvers` tracing and runtime
- deprecated fields usage (`deprecatedFields`)
- `parse` execution time
- `validate` execution time
- `contextBuilding` execution time
- `execute` execution time
- `subscribe` execution time
- count of schema changes (`schemaChangeCount`)

> You can also customize each phase reporter, and add custom metadata and labels to the metrics.
### Custom registry

You can customize the `prom-client` `Registry` object if you are using a custom one, by passing it
along with the configuration object:

```ts
import { execute, parse, specifiedRules, subscribe, validate } from 'graphql'
import { Registry } from 'prom-client'
import { envelop, useEngine } from '@envelop/core'

const myRegistry = new Registry()

const getEnveloped = envelop({
plugins: [
useEngine({ parse, validate, specifiedRules, execute, subscribe }),
// ... other plugins ...
usePrometheus({
// ... config ...
registry: myRegistry
})
]
})
```

> Note: if you are using custom `prom-client` instances, you need to make sure to pass your registry
> there as well.
### Introspection

If you wish to disable introspection logging, you can use `skipIntrospection: true` in your config
object.

### Customize metrics options and labels

Each metric can be configured and custom `labels` can be added to provide more metadata. You can
create a custom extraction function for every `Histogram` / `Summary` / `Counter`:

```ts
import { execute, parse, specifiedRules, subscribe, validate } from 'graphql'
import { Histogram, register as registry } from 'prom-client'
import { envelop, useEngine } from '@envelop/core'
import { createHistogram, usePrometheus } from '@envelop/prometheus'

const getEnveloped = envelop({
plugins: [
useEngine({ parse, validate, specifiedRules, execute, subscribe }),
// ... other plugins ...
usePrometheus({
// all optional, and by default, all set to false, please opt-in to the metrics you wish to get
parse: createHistogram({
registry: registry // make sure to add your custom registry, if you are not using the default one
histogram: new Histogram({
name: 'my_custom_name',
help: 'HELP ME',
labelNames: ['opText'] as const,
}),
fillLabelsFn: params => {
// if you wish to fill your `labels` with metadata, you can use the params in order to get access to things like DocumentNode, operationName, operationType, `error` (for error metrics) and `info` (for resolvers metrics)
return {
opText: print(params.document)
}
}
})
})
]
})
```

## Caveats

Due to Prometheus client API limitations, if this plugin is initialized multiple times, only the
metrics configuration of the first initialization will be applied.

If necessary, use a different registry instance for each plugin instance, or clear the registry
before plugin initialization.

```ts
function usePrometheusWithRegistry() {
// create a new registry instance for each plugin instance
const registry = new Registry()

// or just clear the registry if you use only on plugin instance at a time
registry.clear()

return usePrometheus({
registry,
...
})
}
```

Keep in mind that this implies potential data loss in pull mode if some data is produced between
last pull and the re-initialization of the plugin.

0 comments on commit e4fdacf

Please sign in to comment.