TLDR: https://github.com/Shinigami92/nestjs-prometheus-graphql
Start of this week (14. Nov 2022) I needed to setup Prometheus + Grafana for an API-Gateway in my company.
I was afraid that nearly nothing already exists out there 🙀 and I only had this (spoiler: broken) guide https://hodovi.cc/blog/nestjs-apollo-graphql-prometheus-metrics-and-grafana-dashboards
The whole code examples on that blog article are not just copy&paste-able but also stale/broken.
So I needed to put some hard work into how to wire everything up and to safe hopefully some work for other devs like me, I created now a sample minimal reproducible repository and this dev.to article.
If this helped you at any time, feel free to sponsor me a cup of coffee ☕️ PayPal or via https://github.com/sponsors/Shinigami92
I assume you already have a running GraphQL NestJS app, so I will skip these steps, otherwise please follow the instructions at https://docs.nestjs.com/graphql/quick-start
First we need to install some dependencies:
npm add @willsoto/nestjs-prometheus prom-client # The general Prometheus metrics provider which will expose the endpoint /metrics
npm add apollo-metrics apollo-tracing@0.15.0 # Provides Apollo GraphQL server plugins
npm add --save-dev apollo-server-plugin-base # Contains the ApolloServerPlugin interface
Now we will add a module file src/metrics/prom.module.ts
import { Module } from "@nestjs/common";
import { PrometheusModule } from "@willsoto/nestjs-prometheus";
import createMetricsPlugin from "apollo-metrics";
import { plugin as apolloTracingPlugin } from "apollo-tracing";
import { register } from "prom-client";
export const TRACING_PLUGIN_KEY = "TRACING_PLUGIN_KEY";
export const METRICS_PLUGIN_KEY = "METRICS_PLUGIN_KEY";
@Module({
imports: [
// Register the general Prometheus module
PrometheusModule.register()
],
providers: [
{
provide: TRACING_PLUGIN_KEY,
// Provide the apollo tracing plugin
// This is only needed if you also want to measure timings
useValue: apolloTracingPlugin(),
},
{
provide: METRICS_PLUGIN_KEY,
// Provide the apollo metrics plugin
useValue: createMetricsPlugin(register),
},
],
exports: [TRACING_PLUGIN_KEY, METRICS_PLUGIN_KEY],
})
export class PromModule {}
The tracing plugin is only needed if you also want to measure timings of your field resolvers. At this time, there is NO Grafana Dashboard that will display this data. Maybe I will create one in the future, but for now at least just lets collect these additional data.
The tracing plugin will be used here apollo-metrics index L124
Now we need to register the PromModule
in our AppModule
import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
import { Module } from "@nestjs/common";
import { GraphQLModule } from "@nestjs/graphql";
import { ApolloServerPlugin } from "apollo-server-plugin-base";
import { join } from "path";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { CatsModule } from "./cats/cats.module";
import {
METRICS_PLUGIN_KEY,
PromModule,
TRACING_PLUGIN_KEY,
} from "./metrics/prom.module";
@Module({
imports: [
// Import the PromModule generally (e.g. also for other metrics like non GraphQL stuff)
PromModule,
CatsModule,
GraphQLModule.forRootAsync<ApolloDriverConfig>({
driver: ApolloDriver,
// Import the PromModule for GraphQL
imports: [PromModule],
useFactory: (
// Use provided plugins injected from below
tracingPlugin: ApolloServerPlugin,
metricsPlugin: ApolloServerPlugin
) => ({
debug: true,
introspection: true,
playground: true,
// Plugins added to apollo server
plugins: [tracingPlugin, metricsPlugin],
autoSchemaFile: join(process.cwd(), "src/schema.gql"),
}),
// We need to inject the provider keys
inject: [TRACING_PLUGIN_KEY, METRICS_PLUGIN_KEY],
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Warning: It is important to provide the plugins via that way, as otherwise if not registered to the NestJS context e.g. E2E tests will fail because the prom-client can only register a metric name once and will fail if a plugin tries to recreate a metric.
Now we are ready and just need to connect our metrics endpoint to Prometheus and then add Prometheus as Datasource for Grafana. (Please watch some other tutorials for that)
Now import the Grafana Dashboard: https://grafana.com/grafana/dashboards/16188-graphql-metrics
⚠️ But attention! ⚠️ You need to reconfigure the parameter
operation_name
tooperationName
(snake_case to camelCase)
The blog article https://hodovi.cc/blog/nestjs-apollo-graphql-prometheus-metrics-and-grafana-dashboards was manually using its own metric names 🤷
Please let me know if this was helpful and leave some comments.
Edit
I started to edit the dashboard provided by Adin Hodovic and extended it with tracing/timing panels.
Grafana Dashboard (json export): https://github.com/Shinigami92/nestjs-prometheus-graphql/blob/main/ApolloGraphQLMetrics.grafana-dashboard.json
I tried to publish it at grafana.com dashboards, but somehow the upload does not work 🤷
Top comments (2)
Great article! I’m trying to do same for a nestjs app using fastify under the hood, no graphql, how do I modify this to fit that purpose
Top work, this worked for me first time!