11import type { IncomingMessage } from 'node:http' ;
22import { logger } from '@altinn/dialogporten-node-logger' ;
33import { FastifyOtelInstrumentation } from '@fastify/otel' ;
4+ import type { Context } from '@opentelemetry/api' ;
45import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc' ;
56import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc' ;
67import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql' ;
@@ -10,11 +11,28 @@ import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';
1011import { resourceFromAttributes } from '@opentelemetry/resources' ;
1112import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics' ;
1213import { NodeSDK } from '@opentelemetry/sdk-node' ;
13- import { ParentBasedSampler , TraceIdRatioBasedSampler } from '@opentelemetry/sdk-trace-base' ;
14+ import {
15+ BatchSpanProcessor ,
16+ ParentBasedSampler ,
17+ type ReadableSpan ,
18+ type Span ,
19+ type SpanProcessor ,
20+ TraceIdRatioBasedSampler ,
21+ } from '@opentelemetry/sdk-trace-base' ;
1422import { ATTR_SERVICE_NAME , SEMRESATTRS_SERVICE_INSTANCE_ID } from '@opentelemetry/semantic-conventions' ;
1523import config from './config.ts' ;
1624
1725const { openTelemetry } = config ;
26+ const spansExcludedFromExport = new Set ( [
27+ 'graphql.parse' ,
28+ 'graphql.validate' ,
29+ 'graphql.parseSchema' ,
30+ 'graphql.validateSchema' ,
31+ ] ) ;
32+
33+ const shouldDropSpanByName = ( spanName : string ) : boolean => {
34+ return spansExcludedFromExport . has ( spanName ) ;
35+ } ;
1836
1937// Configure HTTP instrumentation with filtering
2038const httpInstrumentationConfig : HttpInstrumentationConfig = {
@@ -58,6 +76,29 @@ const resource = resourceFromAttributes({
5876 [ SEMRESATTRS_SERVICE_INSTANCE_ID ] : config . info . instanceId || 'local-dev' ,
5977} ) ;
6078
79+ class SpanNameFilteringProcessor implements SpanProcessor {
80+ constructor ( private readonly delegate : SpanProcessor ) { }
81+
82+ onStart ( span : Span , parentContext : Context ) : void {
83+ this . delegate . onStart ( span , parentContext ) ;
84+ }
85+
86+ onEnd ( span : ReadableSpan ) : void {
87+ if ( shouldDropSpanByName ( span . name ) ) {
88+ return ;
89+ }
90+ this . delegate . onEnd ( span ) ;
91+ }
92+
93+ forceFlush ( ) : Promise < void > {
94+ return this . delegate . forceFlush ( ) ;
95+ }
96+
97+ shutdown ( ) : Promise < void > {
98+ return this . delegate . shutdown ( ) ;
99+ }
100+ }
101+
61102const initializeOpenTelemetry = ( ) => {
62103 try {
63104 if ( ! config . openTelemetry . enabled ) {
@@ -78,6 +119,7 @@ const initializeOpenTelemetry = () => {
78119 const sampler = new ParentBasedSampler ( {
79120 root : new TraceIdRatioBasedSampler ( openTelemetry . sampleRate ) ,
80121 } ) ;
122+ const spanProcessor : SpanProcessor = new SpanNameFilteringProcessor ( new BatchSpanProcessor ( traceExporter ) ) ;
81123
82124 logger . info (
83125 {
@@ -93,7 +135,7 @@ const initializeOpenTelemetry = () => {
93135 // Initialize NodeSDK
94136 const sdk = new NodeSDK ( {
95137 resource,
96- traceExporter ,
138+ spanProcessors : [ spanProcessor ] ,
97139 metricReaders : [ metricReader ] ,
98140 instrumentations,
99141 sampler,
0 commit comments