1- import { DiagConsoleLogger , DiagLogLevel , TracerProvider , diag } from "@opentelemetry/api" ;
1+ import {
2+ DiagConsoleLogger ,
3+ DiagLogLevel ,
4+ TraceFlags ,
5+ TracerProvider ,
6+ diag ,
7+ } from "@opentelemetry/api" ;
28import { logs } from "@opentelemetry/api-logs" ;
39import { TraceState } from "@opentelemetry/core" ;
410import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http" ;
@@ -21,7 +27,7 @@ import {
2127 SimpleSpanProcessor ,
2228 SpanExporter ,
2329} from "@opentelemetry/sdk-trace-node" ;
24- import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions" ;
30+ import { SemanticResourceAttributes , SEMATTRS_HTTP_URL } from "@opentelemetry/semantic-conventions" ;
2531import { VERSION } from "../../version.js" ;
2632import {
2733 OTEL_ATTRIBUTE_PER_EVENT_COUNT_LIMIT ,
@@ -287,17 +293,24 @@ function setLogLevel(level: TracingDiagnosticLogLevel) {
287293}
288294
289295class ExternalSpanExporterWrapper {
296+ private readonly _isExternallySampled : boolean ;
297+
290298 constructor (
291299 private underlyingExporter : SpanExporter ,
292300 private externalTraceId : string ,
293301 private externalTraceContext :
294- | { traceId : string ; spanId : string ; tracestate ?: string }
302+ | { traceId : string ; spanId : string ; traceFlags : number ; tracestate ?: string }
295303 | undefined
296- ) { }
304+ ) {
305+ this . _isExternallySampled = isTraceFlagSampled ( externalTraceContext ?. traceFlags ) ;
306+ }
297307
298308 private transformSpan ( span : ReadableSpan ) : ReadableSpan | undefined {
299- if ( span . attributes [ SemanticInternalAttributes . SPAN_PARTIAL ] ) {
300- // Skip partial spans
309+ if ( ! this . _isExternallySampled ) {
310+ return ;
311+ }
312+
313+ if ( isSpanInternalOnly ( span ) ) {
301314 return ;
302315 }
303316
@@ -325,8 +338,10 @@ class ExternalSpanExporterWrapper {
325338 traceState : this . externalTraceContext . tracestate
326339 ? new TraceState ( this . externalTraceContext . tracestate )
327340 : undefined ,
328- traceFlags : parentSpanContext ?. traceFlags ?? 0 ,
341+ traceFlags : this . externalTraceContext . traceFlags ,
329342 } ;
343+ } else if ( isAttemptSpan ) {
344+ parentSpanContext = undefined ;
330345 }
331346
332347 return {
@@ -360,15 +375,25 @@ class ExternalSpanExporterWrapper {
360375}
361376
362377class ExternalLogRecordExporterWrapper {
378+ private readonly _isExternallySampled : boolean ;
379+
363380 constructor (
364381 private underlyingExporter : LogRecordExporter ,
365382 private externalTraceId : string ,
366383 private externalTraceContext :
367- | { traceId : string ; spanId : string ; tracestate ?: string }
384+ | { traceId : string ; spanId : string ; tracestate ?: string ; traceFlags : number }
368385 | undefined
369- ) { }
386+ ) {
387+ this . _isExternallySampled = isTraceFlagSampled ( externalTraceContext ?. traceFlags ) ;
388+ }
370389
371390 export ( logs : any [ ] , resultCallback : ( result : any ) => void ) : void {
391+ if ( ! this . _isExternallySampled ) {
392+ this . underlyingExporter . export ( [ ] , resultCallback ) ;
393+
394+ return ;
395+ }
396+
372397 const modifiedLogs = logs . map ( this . transformLogRecord . bind ( this ) ) ;
373398
374399 this . underlyingExporter . export ( modifiedLogs , resultCallback ) ;
@@ -410,3 +435,57 @@ class ExternalLogRecordExporterWrapper {
410435 } ) ;
411436 }
412437}
438+
439+ function isSpanInternalOnly ( span : ReadableSpan ) : boolean {
440+ if ( span . attributes [ SemanticInternalAttributes . SPAN_PARTIAL ] ) {
441+ // Skip partial spans
442+ return true ;
443+ }
444+
445+ const urlPath = span . attributes [ "url.path" ] ;
446+
447+ if ( typeof urlPath === "string" && urlPath === "/api/v1/usage/ingest" ) {
448+ return true ;
449+ }
450+
451+ const httpUrl = span . attributes [ SEMATTRS_HTTP_URL ] ?? span . attributes [ "url.full" ] ;
452+
453+ const url = safeParseUrl ( httpUrl ) ;
454+
455+ if ( ! url ) {
456+ return false ;
457+ }
458+
459+ const internalHosts = [
460+ "api.trigger.dev" ,
461+ "billing.trigger.dev" ,
462+ "cloud.trigger.dev" ,
463+ "engine.trigger.dev" ,
464+ "platform.trigger.dev" ,
465+ ] ;
466+
467+ return (
468+ internalHosts . some ( ( host ) => url . hostname . includes ( host ) ) ||
469+ url . pathname . includes ( "/api/v1/usage/ingest" )
470+ ) ;
471+ }
472+
473+ function safeParseUrl ( url : unknown ) : URL | undefined {
474+ if ( typeof url !== "string" ) {
475+ return undefined ;
476+ }
477+
478+ try {
479+ return new URL ( url ) ;
480+ } catch ( e ) {
481+ return undefined ;
482+ }
483+ }
484+
485+ function isTraceFlagSampled ( traceFlags ?: number ) : boolean {
486+ if ( typeof traceFlags !== "number" ) {
487+ return true ;
488+ }
489+
490+ return ( traceFlags & TraceFlags . SAMPLED ) === TraceFlags . SAMPLED ;
491+ }
0 commit comments