@fastify/otel
Advanced tools
+7
-0
@@ -5,2 +5,9 @@ # Changelog | ||
| ### [0.13.1](https://github.com/fastify/otel/compare/v0.13.0...v0.13.1) (2025-11-07) | ||
| ### Bug Fixes | ||
| * ignore plugin hooks on disabled OTEL routes ([#108](https://github.com/fastify/otel/issues/108)) ([e31b577](https://github.com/fastify/otel/commit/e31b577834cc9ff183f428bcb17ed5f3530b1338)) | ||
| ## [0.13.0](https://github.com/fastify/otel/compare/v0.12.0...v0.13.0) (2025-10-30) | ||
@@ -7,0 +14,0 @@ |
+15
-1
@@ -441,6 +441,20 @@ 'use strict' | ||
| if (instrumentation.isEnabled() === false) { | ||
| if (instrumentation.isEnabled() === false || request.routeOptions.config?.otel === false) { | ||
| instrumentation.logger.debug( | ||
| `Ignoring route instrumentation ${request.routeOptions.method} ${request.routeOptions.url} because it is disabled` | ||
| ) | ||
| return handler.call(this, ...args) | ||
| } | ||
| if (instrumentation[kIgnorePaths]?.({ | ||
| url: request.url, | ||
| method: request.method, | ||
| }) === true) { | ||
| instrumentation.logger.debug( | ||
| `Ignoring route instrumentation ${request.routeOptions.method} ${request.routeOptions.url} because it matches the ignore path` | ||
| ) | ||
| return handler.call(this, ...args) | ||
| } | ||
| /* c8 ignore next */ | ||
| const ctx = request[kRequestContext] ?? context.active() | ||
@@ -447,0 +461,0 @@ const span = instrumentation.tracer.startSpan( |
+6
-5
| { | ||
| "name": "@fastify/otel", | ||
| "version": "0.13.0", | ||
| "version": "0.13.1", | ||
| "description": "Official Fastify OpenTelemetry Instrumentation", | ||
@@ -48,6 +48,6 @@ "main": "index.js", | ||
| "devDependencies": { | ||
| "@fastify/type-provider-typebox": "^5.0.0-pre.fv5.1", | ||
| "@fastify/type-provider-typebox": "^6.1.0", | ||
| "@opentelemetry/context-async-hooks": "^2.0.0", | ||
| "@opentelemetry/contrib-test-utils": "^0.49.0", | ||
| "@opentelemetry/instrumentation-http": "^0.205.0", | ||
| "@opentelemetry/contrib-test-utils": "^0.54.0", | ||
| "@opentelemetry/instrumentation-http": "^0.207.0", | ||
| "@opentelemetry/propagator-jaeger": "^2.0.0", | ||
@@ -61,5 +61,6 @@ "@opentelemetry/sdk-trace-base": "^2.0.0", | ||
| "fastify": "^5.1.0", | ||
| "fastify-plugin": "^5.1.0", | ||
| "fastifyv4": "npm:fastify@^4.0.0", | ||
| "neostandard": "^0.12.0", | ||
| "tsd": "^0.32.0" | ||
| "tsd": "^0.33.0" | ||
| }, | ||
@@ -66,0 +67,0 @@ "dependencies": { |
+124
-4
@@ -33,2 +33,4 @@ 'use strict' | ||
| const fp = require('fastify-plugin') | ||
| const FastifyInstrumentation = require('..') | ||
@@ -71,2 +73,5 @@ | ||
| await app.register(plugin) | ||
| app.register(fp(async function (fastify) { | ||
| fastify.addHook('onRequest', (_request, _reply, done) => done()) | ||
| })) | ||
@@ -90,2 +95,112 @@ app.get('/', async (request, reply) => 'hello world') | ||
| }) | ||
| test('should not create spans if disabled (route config)', async t => { | ||
| before(() => { | ||
| contextManager.enable() | ||
| }) | ||
| after(() => { | ||
| contextManager.disable() | ||
| spanProcessor.forceFlush() | ||
| memoryExporter.reset() | ||
| instrumentation.disable() | ||
| httpInstrumentation.disable() | ||
| }) | ||
| const app = Fastify() | ||
| const plugin = instrumentation.plugin() | ||
| await app.register(plugin) | ||
| app.register(fp(async function (fastify) { | ||
| fastify.addHook('onRequest', (_request, _reply, done) => done()) | ||
| })) | ||
| app.get('/', { config: { otel: false } }, async (request, reply) => 'hello world') | ||
| instrumentation.disable() | ||
| const response = await app.inject({ | ||
| method: 'GET', | ||
| url: '/' | ||
| }) | ||
| const spans = memoryExporter | ||
| .getFinishedSpans() | ||
| .find(span => span.instrumentationLibrary.name === '@fastify/otel') | ||
| assert.ok(spans == null) | ||
| assert.equal(response.statusCode, 200) | ||
| assert.equal(response.body, 'hello world') | ||
| }) | ||
| test('should not create spans for hooks if disabled', async t => { | ||
| before(() => { | ||
| contextManager.enable() | ||
| }) | ||
| after(() => { | ||
| contextManager.disable() | ||
| spanProcessor.forceFlush() | ||
| memoryExporter.reset() | ||
| instrumentation.disable() | ||
| httpInstrumentation.disable() | ||
| }) | ||
| const app = Fastify() | ||
| const plugin = instrumentation.plugin() | ||
| await app.register(plugin) | ||
| app.register(fp(async function (fastify) { | ||
| fastify.addHook('onRequest', (_request, _reply, done) => done()) | ||
| })) | ||
| instrumentation.disable() | ||
| app.get('/', { preHandler: (request, reply, done) => { done() } }, async (request, reply) => 'hello world') | ||
| const response = await app.inject({ | ||
| method: 'GET', | ||
| url: '/' | ||
| }) | ||
| const spans = memoryExporter | ||
| .getFinishedSpans() | ||
| .find(span => span.instrumentationLibrary.name === '@fastify/otel') | ||
| assert.ok(spans == null) | ||
| assert.equal(response.statusCode, 200) | ||
| assert.equal(response.body, 'hello world') | ||
| }) | ||
| test('should not create spans for hooks if disabled (route config)', async t => { | ||
| before(() => { | ||
| contextManager.enable() | ||
| }) | ||
| after(() => { | ||
| contextManager.disable() | ||
| spanProcessor.forceFlush() | ||
| memoryExporter.reset() | ||
| instrumentation.disable() | ||
| httpInstrumentation.disable() | ||
| }) | ||
| const app = Fastify() | ||
| const plugin = instrumentation.plugin() | ||
| await app.register(plugin) | ||
| app.get('/', { config: { otel: false }, preHandler: (request, reply, done) => { done() } }, async (request, reply) => 'hello world') | ||
| const response = await app.inject({ | ||
| method: 'GET', | ||
| url: '/' | ||
| }) | ||
| const spans = memoryExporter | ||
| .getFinishedSpans() | ||
| .find(span => span.instrumentationLibrary.name === '@fastify/otel') | ||
| assert.ok(spans == null) | ||
| assert.equal(response.statusCode, 200) | ||
| assert.equal(response.body, 'hello world') | ||
| }) | ||
| }) | ||
@@ -140,4 +255,7 @@ | ||
| await app.register(plugin) | ||
| app.register(fp(async function (fastify) { | ||
| fastify.addHook('onRequest', (_request, _reply, done) => done()) | ||
| })) | ||
| app.get('/health/up', async (request, reply) => 'hello world') | ||
| app.get('/health/up', { preHandler: (request, reply, done) => { done() } }, async (request, reply) => 'hello world') | ||
@@ -170,4 +288,7 @@ await app.listen() | ||
| await app.register(plugin) | ||
| app.register(fp(async function (fastify) { | ||
| fastify.addHook('onRequest', (_request, _reply, done) => done()) | ||
| })) | ||
| app.get('/health', async (request, reply) => 'hello world') | ||
| app.get('/health', { onRequest: (request, reply, done) => { done() } }, async (request, reply) => 'hello world') | ||
@@ -900,6 +1021,5 @@ await app.listen() | ||
| const { handler } = routeOptions | ||
| const someCustomHandlerArgumentForAPlugin = {} | ||
| routeOptions.handler = function (...args) { | ||
| return handler.call(this, someCustomHandlerArgumentForAPlugin, ...args) | ||
| return handler.call(this, ...args) | ||
| } | ||
@@ -906,0 +1026,0 @@ }) |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
107452
4.42%2378
4.76%16
6.67%