@@ -29,35 +29,110 @@ 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+ // otel.js
38+ // Sets up metrics, tracing, HTTP & Node runtime instrumentation, and host metrics.
39+ // Uses ConsoleSpanExporter for local debugging of spans.
40+ const { NodeSDK } = require (' @opentelemetry/sdk-node' )
41+ const { ConsoleSpanExporter } = require (' @opentelemetry/sdk-trace-node' )
42+ const { SimpleSpanProcessor } = require (' @opentelemetry/sdk-trace-base' )
43+ const { PrometheusExporter } = require (' @opentelemetry/exporter-prometheus' )
44+ const { HttpInstrumentation } = require (' @opentelemetry/instrumentation-http' )
45+ const { RuntimeNodeInstrumentation } = require (' @opentelemetry/instrumentation-runtime-node' )
46+ const { HostMetrics } = require (' @opentelemetry/host-metrics' )
47+ const { FastifyOtelInstrumentation } = require (' @fastify/otel' )
48+ const { metrics , trace } = require (' @opentelemetry/api' )
49+ const { resourceFromAttributes } = require (' @opentelemetry/resources' )
50+ const { SemanticResourceAttributes } = require (' @opentelemetry/semantic-conventions' )
51+
52+ // Console exporter for development-time span inspection
53+ // We could use '@opentelemetry/exporter-trace-otlp-http' instead
54+ const traceExporter = new ConsoleSpanExporter ()
55+ const spanProcessor = new SimpleSpanProcessor (traceExporter)
56+
57+ const prometheusExporter = new PrometheusExporter ({ port: 9091 })
58+
59+ const sdk = new NodeSDK ({
60+ resource: resourceFromAttributes ({
61+ [SemanticResourceAttributes .SERVICE_NAME ]: ' my-service-name' ,
62+ }),
63+ spanProcessor,
64+ metricReader: prometheusExporter,
65+ instrumentations: [
66+ new HttpInstrumentation (),
67+ new RuntimeNodeInstrumentation (),
68+ ],
69+ })
3870
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)
71+ await sdk .start ()
4372
44- module .exports = { fastifyOtelInstrumentation }
73+ const fastifyOtelInstrumentation = new FastifyOtelInstrumentation ({
74+ registerOnInitialization: true ,
75+ })
76+ fastifyOtelInstrumentation .setTracerProvider (trace .getTracerProvider ())
4577
46- // ... in your Fastify definition
47- const { fastifyOtelInstrumentation } = require (' ./otel.js' );
48- const Fastify = require (' fastify' );
78+ new HostMetrics ({ meterProvider: metrics .getMeterProvider () }).start ()
4979
50- const app = fastify ();
80+ module .exports = { sdk, fastifyOtelInstrumentation }
81+ ```
82+
83+ If ` registerOnInitialization=true ` , use a loader to load your otel.js before everything else.
84+
85+ [ Fastify-cli] ( https://github.com/fastify/fastify-cli ) :
86+
87+ - ` fastify start --import otel.js ` for esm
88+ - ` fastify start --require otel.js ` for cjs
89+
90+ Node.js:
91+
92+ - ` node --import ./otel.js ./app.js ` for esm
93+ - ` node --require ./otel.js ./app.js ` for cjs
94+
95+ ``` js
96+ // app.js
97+ import Fastify from ' fastify' ;
98+
99+ // Because we used a loader flag and registerOnInitialization=true
100+ // All routes will automatically be insturmented
101+ const app = await Fastify ();
102+
103+ app .get (' /' , async () => ' hello world' );
104+
105+ app .get (
106+ ' /healthcheck' ,
107+ { config: { otel: false } }, // skip tracing/metrics for this route
108+ async () => ' Up!'
109+ );
110+
111+ // example of encapsulated context with its own instrumentation
112+ app .register (async (instance ) => {
113+ // will inherit global FastifyOtelInstrumentation because we registered with
114+ // registerOnInitialization
115+ instance .get (' /' , async () => ' nested hello world' );
116+ }, { prefix: ' /nested' });
117+
118+ await app .listen ({ port: 3000 });
119+ console .log (' ⚡ Fastify listening on http://localhost:3000' );
120+ ````
121+
122+ ### Manual plugin registration
123+
124+ If ` registerOnInitialization=false` , you must register the fastify plugin before defining any routes.
125+
126+ ` ` ` js
127+ import Fastify from 'fastify';
128+ import { fastifyOtelInstrumentation } from './otel.js';
129+
130+ const app = await Fastify();
51131// It is necessary to await for its register as it requires to be able
52132// to intercept all route definitions
53133await app.register(fastifyOtelInstrumentation.plugin());
54134
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!' )
135+ app.get('/', async () => 'hello world');
61136
62137// you can also scope your instrumentation to only be enabled on a sub context
63138// of your application
@@ -69,23 +144,7 @@ app.register((instance, opts, done) => {
69144
70145 done()
71146}, { 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- ```
147+ ` ` ` `
89148
90149> **Notes**:
91150>
0 commit comments