44import { Span , TraceFlags , Tracer } from '@opentelemetry/api' ;
55import { OTLPMetricExporter as OTLPGrpcOTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc' ;
66import { OTLPMetricExporter as OTLPHttpOTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http' ;
7+ import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc' ;
8+ import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http' ;
9+ import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto' ;
710import { Resource } from '@opentelemetry/resources' ;
811import { PushMetricExporter } from '@opentelemetry/sdk-metrics' ;
9- import { ReadableSpan , SpanProcessor } from '@opentelemetry/sdk-trace-base' ;
12+ import { AlwaysOffSampler , ReadableSpan , SpanProcessor , TraceIdRatioBasedSampler } from '@opentelemetry/sdk-trace-base' ;
1013import {
1114 AlwaysOnSampler ,
1215 NodeTracerProvider ,
@@ -222,6 +225,16 @@ describe('AwsOpenTelemetryConfiguratorTest', () => {
222225
223226 process . env . OTEL_AWS_APPLICATION_SIGNALS_ENABLED = 'False' ;
224227 expect ( AwsOpentelemetryConfigurator . isApplicationSignalsEnabled ( ) ) . toBeFalsy ( ) ;
228+ process . env . OTEL_AWS_APPLICATION_SIGNALS_ENABLED = 'abcdefg' ;
229+ expect ( AwsOpentelemetryConfigurator . isApplicationSignalsEnabled ( ) ) . toBeFalsy ( ) ;
230+ process . env . OTEL_AWS_APPLICATION_SIGNALS_ENABLED = 'True_abcdefg' ;
231+ expect ( AwsOpentelemetryConfigurator . isApplicationSignalsEnabled ( ) ) . toBeFalsy ( ) ;
232+ process . env . OTEL_AWS_APPLICATION_SIGNALS_ENABLED = 'abcdefg_True' ;
233+ expect ( AwsOpentelemetryConfigurator . isApplicationSignalsEnabled ( ) ) . toBeFalsy ( ) ;
234+ process . env . OTEL_AWS_APPLICATION_SIGNALS_ENABLED = '0' ;
235+ expect ( AwsOpentelemetryConfigurator . isApplicationSignalsEnabled ( ) ) . toBeFalsy ( ) ;
236+ process . env . OTEL_AWS_APPLICATION_SIGNALS_ENABLED = '1' ;
237+ expect ( AwsOpentelemetryConfigurator . isApplicationSignalsEnabled ( ) ) . toBeFalsy ( ) ;
225238 delete process . env . OTEL_AWS_APPLICATION_SIGNALS_ENABLED ;
226239 expect ( AwsOpentelemetryConfigurator . isApplicationSignalsEnabled ( ) ) . toBeFalsy ( ) ;
227240 } ) ;
@@ -294,6 +307,9 @@ describe('AwsOpenTelemetryConfiguratorTest', () => {
294307 } ) ;
295308
296309 it ( 'ApplicationSignalsExporterProviderTest' , ( ) => {
310+ const DEFAULT_OTEL_EXPORTER_OTLP_PROTOCOL = process . env . OTEL_EXPORTER_OTLP_PROTOCOL ;
311+ delete process . env . OTEL_EXPORTER_OTLP_METRICS_PROTOCOL ;
312+
297313 // Check default protocol - HTTP, as specified by aws-distro-opentelemetry-node-autoinstrumentation's register.ts.
298314 let exporter : PushMetricExporter = ApplicationSignalsExporterProvider . Instance . createExporter ( ) ;
299315 expect ( exporter ) . toBeInstanceOf ( OTLPHttpOTLPMetricExporter ) ;
@@ -310,6 +326,61 @@ describe('AwsOpenTelemetryConfiguratorTest', () => {
310326 exporter = ApplicationSignalsExporterProvider . Instance . createExporter ( ) ;
311327 expect ( exporter ) . toBeInstanceOf ( OTLPHttpOTLPMetricExporter ) ;
312328 expect ( 'http://localhost:4316/v1/metrics' ) . toEqual ( ( exporter as any ) . _otlpExporter . url ) ;
329+
330+ // If for some reason, the env var is undefined (it shouldn't), overwrite protocol to gRPC.
331+ delete process . env . OTEL_EXPORTER_OTLP_PROTOCOL ;
332+ exporter = ApplicationSignalsExporterProvider . Instance . createExporter ( ) ;
333+ expect ( exporter ) . toBeInstanceOf ( OTLPGrpcOTLPMetricExporter ) ;
334+ expect ( 'localhost:4315' ) . toEqual ( ( exporter as any ) . _otlpExporter . url ) ;
335+
336+ // Expect invalid protocol to throw error.
337+ process . env . OTEL_EXPORTER_OTLP_PROTOCOL = 'invalid_protocol' ;
338+ expect ( ( ) => ApplicationSignalsExporterProvider . Instance . createExporter ( ) ) . toThrow ( ) ;
339+
340+ // Cleanup
341+ process . env . OTEL_EXPORTER_OTLP_PROTOCOL = DEFAULT_OTEL_EXPORTER_OTLP_PROTOCOL ;
342+
343+ // Repeat tests using OTEL_EXPORTER_OTLP_METRICS_PROTOCOL environment variable instead
344+
345+ // Check default protocol - HTTP, as specified by aws-distro-opentelemetry-node-autoinstrumentation's register.ts.
346+ exporter = ApplicationSignalsExporterProvider . Instance . createExporter ( ) ;
347+ expect ( exporter ) . toBeInstanceOf ( OTLPHttpOTLPMetricExporter ) ;
348+ expect ( 'http://localhost:4316/v1/metrics' ) . toEqual ( ( exporter as any ) . _otlpExporter . url ) ;
349+
350+ // Overwrite protocol to gRPC.
351+ process . env . OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'grpc' ;
352+ exporter = ApplicationSignalsExporterProvider . Instance . createExporter ( ) ;
353+ expect ( exporter ) . toBeInstanceOf ( OTLPGrpcOTLPMetricExporter ) ;
354+ expect ( 'localhost:4315' ) . toEqual ( ( exporter as any ) . _otlpExporter . url ) ;
355+
356+ // Overwrite protocol back to HTTP.
357+ process . env . OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'http/protobuf' ;
358+ exporter = ApplicationSignalsExporterProvider . Instance . createExporter ( ) ;
359+ expect ( exporter ) . toBeInstanceOf ( OTLPHttpOTLPMetricExporter ) ;
360+ expect ( 'http://localhost:4316/v1/metrics' ) . toEqual ( ( exporter as any ) . _otlpExporter . url ) ;
361+
362+ // Expect invalid protocol to throw error.
363+ process . env . OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'invalid_protocol' ;
364+ expect ( ( ) => ApplicationSignalsExporterProvider . Instance . createExporter ( ) ) . toThrow ( ) ;
365+
366+ // Test custom URLs via OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT
367+ process . env . OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT = 'my_custom_endpoint' ;
368+
369+ // Overwrite protocol to gRPC, export to url "my_custom_endpoint"
370+ process . env . OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'grpc' ;
371+ exporter = ApplicationSignalsExporterProvider . Instance . createExporter ( ) ;
372+ expect ( exporter ) . toBeInstanceOf ( OTLPGrpcOTLPMetricExporter ) ;
373+ expect ( 'my_custom_endpoint' ) . toEqual ( ( exporter as any ) . _otlpExporter . url ) ;
374+
375+ // Overwrite protocol back to HTTP, export to url "my_custom_endpoint"
376+ process . env . OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = 'http/protobuf' ;
377+ exporter = ApplicationSignalsExporterProvider . Instance . createExporter ( ) ;
378+ expect ( exporter ) . toBeInstanceOf ( OTLPHttpOTLPMetricExporter ) ;
379+ expect ( 'my_custom_endpoint' ) . toEqual ( ( exporter as any ) . _otlpExporter . url ) ;
380+
381+ // Cleanup
382+ delete process . env . OTEL_EXPORTER_OTLP_METRICS_PROTOCOL ;
383+ delete process . env . OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT ;
313384 } ) ;
314385
315386 it ( 'tests getSamplerProbabilityFromEnv() ratio out of bounds' , ( ) => {
@@ -411,4 +482,157 @@ describe('AwsOpenTelemetryConfiguratorTest', () => {
411482 expect ( undefined ) . toEqual ( process . env . OTEL_TRACES_EXPORTER ) ;
412483 expect ( undefined ) . toEqual ( process . env . OTEL_METRICS_EXPORTER ) ;
413484 }
485+
486+ it ( 'OtelTracesSamplerInputValidationTest' , ( ) => {
487+ let config ;
488+
489+ // Test that the samplers that should exist, do exist
490+ process . env . OTEL_TRACES_SAMPLER = 'always_off' ;
491+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
492+ expect ( config . sampler ) . toBeInstanceOf ( AlwaysOffSampler ) ;
493+
494+ process . env . OTEL_TRACES_SAMPLER = 'always_on' ;
495+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
496+ expect ( config . sampler ) . toBeInstanceOf ( AlwaysOnSampler ) ;
497+
498+ process . env . OTEL_TRACES_SAMPLER = 'parentbased_always_off' ;
499+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
500+ expect ( config . sampler ) . toBeInstanceOf ( ParentBasedSampler ) ;
501+
502+ process . env . OTEL_TRACES_SAMPLER = 'parentbased_always_on' ;
503+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
504+ expect ( config . sampler ) . toBeInstanceOf ( ParentBasedSampler ) ;
505+
506+ process . env . OTEL_TRACES_SAMPLER = 'parentbased_traceidratio' ;
507+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
508+ expect ( config . sampler ) . toBeInstanceOf ( ParentBasedSampler ) ;
509+
510+ // Test invalid and out-of-bound cases for traceidratio sampler
511+ process . env . OTEL_TRACES_SAMPLER = 'traceidratio' ;
512+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
513+ expect ( config . sampler ) . toBeInstanceOf ( TraceIdRatioBasedSampler ) ;
514+ process . env . OTEL_TRACES_SAMPLER_ARG = '0.5' ;
515+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
516+ expect ( ( config . sampler as any ) . _ratio ) . toEqual ( 0.5 ) ;
517+ process . env . OTEL_TRACES_SAMPLER_ARG = '2' ;
518+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
519+ expect ( ( config . sampler as any ) . _ratio ) . toEqual ( 1 ) ;
520+ process . env . OTEL_TRACES_SAMPLER_ARG = '-3' ;
521+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
522+ expect ( ( config . sampler as any ) . _ratio ) . toEqual ( 1 ) ;
523+ process . env . OTEL_TRACES_SAMPLER_ARG = 'abc' ;
524+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
525+ expect ( ( config . sampler as any ) . _ratio ) . toEqual ( 1 ) ;
526+
527+ // In-depth testing for 'xray' sampler arguments can be found in test case 'ImportXRaySamplerWhenSamplerArgsSet'
528+ process . env . OTEL_TRACES_SAMPLER = 'xray' ;
529+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
530+ expect ( config . sampler ) . toBeInstanceOf ( AwsXRayRemoteSampler ) ;
531+
532+ // Invalid sampler cases
533+ process . env . OTEL_TRACES_SAMPLER = 'invalid_sampler' ;
534+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
535+ expect ( config . sampler ) . toBeInstanceOf ( AlwaysOnSampler ) ;
536+
537+ process . env . OTEL_TRACES_SAMPLER = '123' ;
538+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
539+ expect ( config . sampler ) . toBeInstanceOf ( AlwaysOnSampler ) ;
540+
541+ // Cleanup
542+ delete process . env . OTEL_TRACES_SAMPLER ;
543+ } ) ;
544+
545+ it ( 'OtelTraceExporterInputValidationTest' , ( ) => {
546+ process . env . OTEL_AWS_APPLICATION_SIGNALS_ENABLED = 'true' ;
547+ let config ;
548+
549+ // Default scenario where no trace exporter is specified
550+ process . env . OTEL_TRACES_EXPORTER = 'none' ;
551+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
552+ expect ( ( config . spanProcessors as any ) [ 0 ] ) . toBeInstanceOf ( AttributePropagatingSpanProcessor ) ;
553+ expect ( ( config . spanProcessors as any ) [ 1 ] ) . toBeInstanceOf ( AwsSpanMetricsProcessor ) ;
554+ expect ( config . spanProcessors ?. length ) . toEqual ( 2 ) ;
555+
556+ // Scenario where otlp trace exporter is specified, adds one more exporter compared to default case
557+ process . env . OTEL_TRACES_EXPORTER = 'otlp' ;
558+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
559+ expect ( ( config . spanProcessors as any ) [ 0 ] . _exporter . delegate ) . toBeInstanceOf ( OTLPProtoTraceExporter ) ;
560+ expect ( ( config . spanProcessors as any ) [ 1 ] ) . toBeInstanceOf ( AttributePropagatingSpanProcessor ) ;
561+ expect ( ( config . spanProcessors as any ) [ 2 ] ) . toBeInstanceOf ( AwsSpanMetricsProcessor ) ;
562+ expect ( config . spanProcessors ?. length ) . toEqual ( 3 ) ;
563+
564+ // Specify invalid exporter, same result as default scenario where no trace exporter is specified
565+ process . env . OTEL_TRACES_EXPORTER = 'invalid_exporter_name' ;
566+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
567+ expect ( ( config . spanProcessors as any ) [ 0 ] ) . toBeInstanceOf ( AttributePropagatingSpanProcessor ) ;
568+ expect ( ( config . spanProcessors as any ) [ 1 ] ) . toBeInstanceOf ( AwsSpanMetricsProcessor ) ;
569+ expect ( config . spanProcessors ?. length ) . toEqual ( 2 ) ;
570+
571+ // Cleanup
572+ delete process . env . OTEL_AWS_APPLICATION_SIGNALS_ENABLED ;
573+ delete process . env . OTEL_TRACES_EXPORTER ;
574+ } ) ;
575+
576+ it ( 'ResourceDetectorInputValidationTest' , ( ) => {
577+ let config ;
578+ process . env . OTEL_SERVICE_NAME = 'test_service_name' ;
579+
580+ // Default 2 attributes detected in test environment
581+ process . env . OTEL_NODE_RESOURCE_DETECTORS = 'container' ;
582+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
583+ expect ( Object . keys ( ( config . resource as any ) . attributes ) . length ) . toEqual ( 2 ) ;
584+ expect ( ( config . resource as any ) . attributes [ 'service.name' ] ) . toEqual ( 'test_service_name' ) ;
585+ expect ( ( config . resource as any ) . attributes [ 'telemetry.auto.version' ] . endsWith ( '-aws' ) ) . toBeTruthy ( ) ;
586+
587+ // Still default 2 attributes detected given invalid resource detectors
588+ process . env . OTEL_NODE_RESOURCE_DETECTORS = 'invalid_detector_1,invalid_detector_2' ;
589+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
590+ expect ( Object . keys ( ( config . resource as any ) . attributes ) . length ) . toEqual ( 2 ) ;
591+ expect ( ( config . resource as any ) . attributes [ 'service.name' ] ) . toEqual ( 'test_service_name' ) ;
592+ expect ( ( config . resource as any ) . attributes [ 'telemetry.auto.version' ] . endsWith ( '-aws' ) ) . toBeTruthy ( ) ;
593+
594+ // Still default 2 attributes detected given mix of valid and invalid resource detectors
595+ process . env . OTEL_NODE_RESOURCE_DETECTORS = 'container,invalid_detector_1,invalid_detector_2' ;
596+ config = new AwsOpentelemetryConfigurator ( [ ] ) . configure ( ) ;
597+ expect ( Object . keys ( ( config . resource as any ) . attributes ) . length ) . toEqual ( 2 ) ;
598+ expect ( ( config . resource as any ) . attributes [ 'service.name' ] ) . toEqual ( 'test_service_name' ) ;
599+ expect ( ( config . resource as any ) . attributes [ 'telemetry.auto.version' ] . endsWith ( '-aws' ) ) . toBeTruthy ( ) ;
600+
601+ // Cleanup
602+ delete process . env . OTEL_SERVICE_NAME ;
603+ delete process . env . OTEL_NODE_RESOURCE_DETECTORS ;
604+ } ) ;
605+
606+ it ( 'AwsSpanProcessorProviderTest' , ( ) => {
607+ let spanExporter ;
608+
609+ // Test span exporter configurations via valid environment variables
610+ delete process . env . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ;
611+ spanExporter = AwsSpanProcessorProvider . configureOtlp ( ) ;
612+ expect ( spanExporter ) . toBeInstanceOf ( OTLPProtoTraceExporter ) ;
613+
614+ process . env . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc' ;
615+ spanExporter = AwsSpanProcessorProvider . configureOtlp ( ) ;
616+ expect ( spanExporter ) . toBeInstanceOf ( OTLPGrpcTraceExporter ) ;
617+
618+ process . env . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'http/json' ;
619+ spanExporter = AwsSpanProcessorProvider . configureOtlp ( ) ;
620+ expect ( spanExporter ) . toBeInstanceOf ( OTLPHttpTraceExporter ) ;
621+
622+ process . env . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'http/protobuf' ;
623+ spanExporter = AwsSpanProcessorProvider . configureOtlp ( ) ;
624+ expect ( spanExporter ) . toBeInstanceOf ( OTLPProtoTraceExporter ) ;
625+
626+ process . env . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'udp' ;
627+ spanExporter = AwsSpanProcessorProvider . configureOtlp ( ) ;
628+ expect ( spanExporter ) . toBeInstanceOf ( OTLPUdpSpanExporter ) ;
629+
630+ // Test that a default span exporter is configured via invalid environment variable
631+ process . env . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'invalid_protocol' ;
632+ spanExporter = AwsSpanProcessorProvider . configureOtlp ( ) ;
633+ expect ( spanExporter ) . toBeInstanceOf ( OTLPProtoTraceExporter ) ;
634+
635+ // Cleanup
636+ delete process . env . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ;
637+ } ) ;
414638} ) ;
0 commit comments