Skip to content

fix(otel-nestjs-instrumentation): force RPC span kind when interceptor starts fallback transaction - #12

Merged
Farenheith merged 1 commit into
mainfrom
fix/otel-interceptor-rpc-span-kind
Aug 11, 2026
Merged

fix(otel-nestjs-instrumentation): force RPC span kind when interceptor starts fallback transaction#12
Farenheith merged 1 commit into
mainfrom
fix/otel-interceptor-rpc-span-kind

Conversation

@Farenheith

Copy link
Copy Markdown
Member

Problem

When the OtelInterceptor started a fallback OpenTelemetry transaction (no existing guard-started span), it passed the raw context to otelInstrumentation.create() which checked context.getType(). For non-HTTP transports (gRPC, microservices) where the guard didn't run, this could incorrectly create HTTP-span attributes instead of RPC-span attributes.

Fix

Added an optional forceSpanKind parameter through the call chain:

  1. Interceptor → always passes SpanKind.SERVER as force when calling startOtelInstrumentationIfAbsent(). Logic: if it were HTTP/HTTPS, the guard would have already started the transaction — any span created by the interceptor is inherently non-HTTP and should be RPC.
  2. startOtelInstrumentationIfAbsent → passes through to create()
  3. otelInstrumentation.create() → when forceSpanKind is provided, bypasses normal context-type detection and creates SERVER-kind spans with RPC attributes (rpc.method) instead of HTTP attributes

Changes

  • src/internal/otel-instrumentation.ts — accept optional forceSpanKind, use RPC attrs when forced
  • src/start-otel-instrumentation-if-absent.ts — pass through new parameter
  • src/otel.interceptor.ts — always force SERVER (RPC) span kind on fallback
  • Tests updated to match new call signatures

Verification

12 passed, 12 total
113 passed, 113 total
Build: successful
Lint: passed

…r starts fallback transaction

When no guard runs (e.g. gRPC/microservice), the interceptor now
passes effectiveType='rpc' to otelInstrumentation.create(), ensuring
the fallback span is always SERVER/RPC instead of potentially being
created as HTTP.

The create() function signature was simplified: replaced forceSpanKind
parameter with effectiveType?: 'http' | 'rpc'. When undefined, it falls
back to context.getType(). This reduces cognitive complexity from 17 to
below the SonarCloud limit of 15.
@Farenheith
Farenheith force-pushed the fix/otel-interceptor-rpc-span-kind branch from 49d8df2 to b91eeb3 Compare August 11, 2026 02:38
@sonarqubecloud

Copy link
Copy Markdown

@Farenheith
Farenheith merged commit fbb8c73 into main Aug 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant