@@ -29,35 +29,108 @@ It must be configured before defining routes and other plugins in order to cover
29
29
- ` onResponse `
30
30
- ` onError `
31
31
- Instruments automatically custom 404 Not Found handler
32
+ - TODO: Clarify server shutdown/cleanup around otel metrics/traces
32
33
33
- Example:
34
+ ## Example
34
35
35
36
``` 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
+ });
38
55
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
+ });
43
70
44
- module . exports = { fastifyOtelInstrumentation }
71
+ await sdk . start ();
45
72
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 ());
49
77
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();
51
129
// It is necessary to await for its register as it requires to be able
52
130
// to intercept all route definitions
53
131
await app.register(fastifyOtelInstrumentation.plugin());
54
132
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');
61
134
62
135
// you can also scope your instrumentation to only be enabled on a sub context
63
136
// of your application
@@ -69,23 +142,7 @@ app.register((instance, opts, done) => {
69
142
70
143
done()
71
144
}, { 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
+ ` ` ` `
89
146
90
147
> **Notes**:
91
148
>
0 commit comments