@@ -29,35 +29,108 @@ It must be configured before defining routes and other plugins in order to cover
2929 - ` onResponse `
3030 - ` onError `
3131- Instruments automatically custom 404 Not Found handler
32+ - TODO: Clarify server shutdown/cleanup around otel metrics/traces
3233
33- Example:
34+ ## Example
3435
3536``` js
36- // ... in your OTEL setup
37- const FastifyOtelInstrumentation = require (' @fastify/otel' );
37+ // otej.js
38+ // This example sets up metrics and traces,
39+ // the http and node runtime insturmentations, as well as host metrics.
40+ const { NodeSDK } = require (' @opentelemetry/sdk-node' )
41+ const { OTLPTraceExporter } = require (' @opentelemetry/exporter-trace-otlp-http' )
42+ const { PrometheusExporter } = require (' @opentelemetry/exporter-prometheus' )
43+ const { HttpInstrumentation } = require (' @opentelemetry/instrumentation-http' )
44+ const { RuntimeNodeInstrumentation } = require (' @opentelemetry/instrumentation-runtime-node' )
45+ const { HostMetrics } = require (' @opentelemetry/host-metrics' )
46+ const { FastifyOtelInstrumentation } = require (' @fastify/otel' )
47+ const { metrics , trace } = require (' @opentelemetry/api' )
48+ const { resourceFromAttributes } = require (' @opentelemetry/resources' )
49+ const { SemanticResourceAttributes } = require (' @opentelemetry/semantic-conventions' )
50+
51+ // OTLP/HTTP trace exporter
52+ const traceExporter = new OTLPTraceExporter ({
53+ url: ' http://localhost:4318/v1/traces' ,
54+ });
3855
39- // If serverName is not provided, it will fallback to OTEL_SERVICE_NAME
40- // as per https://opentelemetry.io/docs/languages/sdk-configuration/general/.
41- const fastifyOtelInstrumentation = new FastifyOtelInstrumentation ({ servername: ' <yourCustomApplicationName>' });
42- fastifyOtelInstrumentation .setTracerProvider (provider)
56+ // Prometheus pull-based metrics exporter
57+ const prometheusExporter = new PrometheusExporter ({ port: 9091 });
58+
59+ export const sdk = new NodeSDK ({
60+ resource: resourceFromAttributes ({
61+ [SemanticResourceAttributes .SERVICE_NAME ]: ' my-service-name' ,
62+ }),
63+ traceExporter,
64+ metricReader: prometheusExporter,
65+ instrumentations: [
66+ new HttpInstrumentation (),
67+ new RuntimeNodeInstrumentation (),
68+ ],
69+ });
4370
44- module . exports = { fastifyOtelInstrumentation }
71+ await sdk . start ();
4572
46- // ... in your Fastify definition
47- const { fastifyOtelInstrumentation } = require (' ./otel.js' );
48- const Fastify = require (' fastify' );
73+ export const fastifyOtelInstrumentation = new FastifyOtelInstrumentation ({
74+ registerOnInitialization: true , // auto-register on fastify() creation
75+ });
76+ fastifyOtelInstrumentation .setTracerProvider (trace .getTracerProvider ());
4977
50- const app = fastify ();
78+ new HostMetrics ({ meterProvider: metrics .getMeterProvider () }).start ();
79+ ```
80+
81+ If ` registerOnInitialization=true ` , use a loader to load your otel.js before everything else.
82+
83+ [ Fastify-cli] ( https://github.com/fastify/fastify-cli ) :
84+
85+ - ` fastify start --import otel.js ` for esm
86+ - ` fastify start --require otel.js ` for cjs
87+
88+ Node.js:
89+
90+ - ` node --import ./otel.js ./app.js ` for esm
91+ - ` node --require ./otel.js ./app.js ` for cjs
92+
93+ ``` js
94+ // app.js
95+ import Fastify from ' fastify' ;
96+
97+ // Because we used a loader flag and registerOnInitialization=true
98+ // All routes will automatically be insturmented
99+ const app = await Fastify ();
100+
101+ app .get (' /' , async () => ' hello world' );
102+
103+ app .get (
104+ ' /healthcheck' ,
105+ { config: { otel: false } }, // skip tracing/metrics for this route
106+ async () => ' Up!'
107+ );
108+
109+ // example of encapsulated context with its own instrumentation
110+ app .register (async (instance ) => {
111+ // will inherit global FastifyOtelInstrumentation because we registered with
112+ // registerOnInitialization
113+ instance .get (' /' , async () => ' nested hello world' );
114+ }, { prefix: ' /nested' });
115+
116+ await app .listen ({ port: 3000 });
117+ console .log (' ⚡ Fastify listening on http://localhost:3000' );
118+ ````
119+
120+ ### Manual plugin registration
121+
122+ If ` registerOnInitialization=false` , you must register the fastify plugin before defining any routes.
123+
124+ ` ` ` js
125+ import Fastify from 'fastify';
126+ import { fastifyOtelInstrumentation } from './otel.js';
127+
128+ const app = await Fastify();
51129// It is necessary to await for its register as it requires to be able
52130// to intercept all route definitions
53131await app.register(fastifyOtelInstrumentation.plugin());
54132
55- // automatically all your routes will be instrumented
56- app .get (' /' , () => ' hello world' )
57- // as well as your instance level hooks.
58- app .addHook (' onError' , () => /* do something */ )
59- // Manually skip telemetry for a specific route
60- app .get (' /healthcheck' , { config: { otel: false } }, () => ' Up!' )
133+ app.get('/', async () => 'hello world');
61134
62135// you can also scope your instrumentation to only be enabled on a sub context
63136// of your application
@@ -69,23 +142,7 @@ app.register((instance, opts, done) => {
69142
70143 done()
71144}, { prefix: '/nested' })
72- ```
73-
74- ### Automatic plugin registration
75-
76- The plugin can be automatically registered with ` registerOnInitialization ` option set to ` true ` .
77- In this case, it is necessary to await fastify instance.
78-
79- ``` js
80- // ... in your OTEL setup
81- const fastifyOtelInstrumentation = new FastifyOtelInstrumentation ({
82- registerOnInitialization: true ,
83- });
84-
85- // ... in your Fastify definition
86- const Fastify = require (' fastify' );
87- const app = await fastify ();
88- ```
145+ ` ` ` `
89146
90147> **Notes**:
91148>
0 commit comments