import { expect } from 'tstyche' import { InstrumentationBase, InstrumentationConfig } from '@opentelemetry/instrumentation' import { Context, Span, TextMapGetter, TextMapSetter, Tracer } from '@opentelemetry/api' import { fastify as Fastify, FastifyInstance, FastifyPluginCallback, FastifyRequest } from 'fastify' import FastifyInstrumentation, { FastifyOtelInstrumentation } from '.' import { FastifyOtelInstrumentationOpts } from './types' expect( new FastifyOtelInstrumentation() ).type.toBeAssignableTo() expect( new FastifyInstrumentation() ).type.toBeAssignableTo() const complexOpts = { enabled: true, requestHook (span, request) { expect(span).type.toBeAssignableTo() expect(request).type.toBeAssignableTo() }, lifecycleHook (span, info) { expect(span).type.toBeAssignableTo() expect(info.hookName).type.toBeAssignableTo() expect(info.request).type.toBeAssignableTo() expect(info.handler).type.toBeAssignableTo() }, recordExceptions: false, instrumentHooks: ['preHandler'] } as FastifyOtelInstrumentationOpts expect(complexOpts).type.toBeAssignableTo() expect( {} as FastifyOtelInstrumentationOpts ).type.toBeAssignableTo() const app = Fastify() const plugin = new FastifyOtelInstrumentation().plugin() expect(app).type.toBeAssignableTo() expect(plugin).type.toBeAssignableTo() expect(app.register(plugin)).type.toBeAssignableTo() app.register(new FastifyOtelInstrumentation().plugin()) app.register((nested, _opts, done) => { nested.register(new FastifyOtelInstrumentation().plugin()) done() }) app.get('/', async function (request, reply) { const otel = request.opentelemetry() expect<(carrier: any, setter?: TextMapSetter) => void>().type.toBeAssignableTo< (carrier: any, setter?: TextMapSetter) => void >() expect< (carrier: any, getter?: TextMapGetter) => Context >().type.toBeAssignableTo<(carrier: any, getter?: TextMapGetter) => Context>() expect(otel.tracer).type.toBeAssignableTo() if (otel.enabled) { expect(otel.span).type.toBeAssignableTo() expect(otel.context).type.toBeAssignableTo() } else { expect(otel.span).type.toBe() expect(otel.context).type.toBe() } }) // Test that otel field in FastifyContextConfig is optional app.get('/with-config', { config: { } }, async function (_request, _reply) { return { hello: 'world' } }) app.get('/with-otel-true', { config: { otel: true } }, async function (_request, _reply) { return { hello: 'world' } }) app.get('/with-otel-false', { config: { otel: false } }, async function (_request, _reply) { return { hello: 'world' } }) app.get('/with-otel-instrument-hooks-false', { config: { otel: { instrumentHooks: false } } }, async function (_request, _reply) { return { hello: 'world' } }) app.get('/with-otel-instrument-hooks-allowlist', { config: { otel: { instrumentHooks: ['preHandler'] } } }, async function (_request, _reply) { return { hello: 'world' } }) app.get('/with-other-config', { config: { customField: 'value' } }, async function (_request, _reply) { return { hello: 'world' } })