@@ -14,6 +14,9 @@ import {
1414import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc' ;
1515import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http' ;
1616import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto' ;
17+ import { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc' ;
18+ import { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http' ;
19+ import { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto' ;
1720import { ZipkinExporter } from '@opentelemetry/exporter-zipkin' ;
1821import { AWSXRayIdGenerator } from '@opentelemetry/id-generator-aws-xray' ;
1922import { Instrumentation } from '@opentelemetry/instrumentation' ;
@@ -50,6 +53,14 @@ import {
5053 SpanProcessor ,
5154 TraceIdRatioBasedSampler ,
5255} from '@opentelemetry/sdk-trace-base' ;
56+
57+ import {
58+ BatchLogRecordProcessor ,
59+ ConsoleLogRecordExporter ,
60+ LogRecordExporter ,
61+ LogRecordProcessor ,
62+ SimpleLogRecordProcessor ,
63+ } from '@opentelemetry/sdk-logs' ;
5364import { SEMRESATTRS_TELEMETRY_AUTO_VERSION } from '@opentelemetry/semantic-conventions' ;
5465import { AlwaysRecordSampler } from './always-record-sampler' ;
5566import { AttributePropagatingSpanProcessorBuilder } from './attribute-propagating-span-processor-builder' ;
@@ -61,6 +72,8 @@ import { OTLPUdpSpanExporter } from './otlp-udp-exporter';
6172import { AwsXRayRemoteSampler } from './sampler/aws-xray-remote-sampler' ;
6273// This file is generated via `npm run compile`
6374import { LIB_VERSION } from './version' ;
75+ import { OTLPAwsLogExporter } from './exporter/otlp/aws/logs/otlp-aws-log-exporter' ;
76+ import { AwsBatchLogRecordProcessor } from './exporter/otlp/aws/logs/aws-batch-log-record-processor' ;
6477
6578const XRAY_OTLP_ENDPOINT_PATTERN = '^https://xray\\.([a-z0-9-]+)\\.amazonaws\\.com/v1/traces$' ;
6679
@@ -69,6 +82,7 @@ const APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG: string = 'OTEL_AWS_APPLICATI
6982const METRIC_EXPORT_INTERVAL_CONFIG : string = 'OTEL_METRIC_EXPORT_INTERVAL' ;
7083const DEFAULT_METRIC_EXPORT_INTERVAL_MILLIS : number = 60000 ;
7184export const AWS_LAMBDA_FUNCTION_NAME_CONFIG : string = 'AWS_LAMBDA_FUNCTION_NAME' ;
85+ export const AGENT_OBSERVABILITY_ENABLED = 'AGENT_OBSERVABILITY_ENABLED' ;
7286const AWS_XRAY_DAEMON_ADDRESS_CONFIG : string = 'AWS_XRAY_DAEMON_ADDRESS' ;
7387const FORMAT_OTEL_SAMPLED_TRACES_BINARY_PREFIX = 'T1S' ;
7488const FORMAT_OTEL_UNSAMPLED_TRACES_BINARY_PREFIX = 'T1U' ;
@@ -421,15 +435,18 @@ export class ApplicationSignalsExporterProvider {
421435// TODO: `TracerProviderWithEnvExporters` is not exported, thus its useful static methods that
422436// provides some default SpanExporter configurations are unavailable. Ideally, we could contribute
423437// to upstream to export `TracerProviderWithEnvExporters`
438+ export type SignalType = 'LOGS' | 'TRACES' | 'METRICS' ;
439+
424440export class AwsSpanProcessorProvider {
425- private _configuredExporters : SpanExporter [ ] = [ ] ;
441+ private _configuredSpanExporters : SpanExporter [ ] = [ ] ;
442+ private _configuredLogExporters : LogRecordExporter [ ] = [ ] ;
426443 private _spanProcessors : SpanProcessor [ ] = [ ] ;
444+ private _logRecordProcessors : LogRecordProcessor [ ] = [ ] ;
427445 private resource : Resource ;
428446
429- static configureOtlp ( ) : SpanExporter {
430- const otlp_exporter_traces_endpoint = process . env [ 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' ] ;
447+ static configureOtlp ( signal : SignalType ) : SpanExporter | LogRecordExporter {
431448 // eslint-disable-next-line @typescript-eslint/typedef
432- let protocol = this . getOtlpProtocol ( ) ;
449+ let protocol = this . getOtlpProtocol ( signal ) ;
433450
434451 // If `isLambdaEnvironment` is true, we will default to exporting OTel spans via `udp_exporter` to Fluxpump,
435452 // regardless of whether `AppSignals` is true or false.
@@ -438,40 +455,79 @@ export class AwsSpanProcessorProvider {
438455 if ( ! hasCustomOtlpTraceEndpoint ( ) && isLambdaEnvironment ( ) ) {
439456 protocol = 'udp' ;
440457 }
441- switch ( protocol ) {
442- case 'grpc' :
443- return new OTLPGrpcTraceExporter ( ) ;
444- case 'http/json' :
445- return new OTLPHttpTraceExporter ( ) ;
446- case 'http/protobuf' :
447- if ( otlp_exporter_traces_endpoint && isXrayOtlpEndpoint ( otlp_exporter_traces_endpoint ) ) {
448- diag . debug ( 'Detected XRay OTLP Traces endpoint. Switching exporter to OtlpAwsSpanExporter' ) ;
449- return new OTLPAwsSpanExporter ( otlp_exporter_traces_endpoint ) ;
450- }
451- return new OTLPProtoTraceExporter ( ) ;
452- case 'udp' :
453- diag . debug ( 'Detected AWS Lambda environment and enabling UDPSpanExporter' ) ;
454- return new OTLPUdpSpanExporter ( getXrayDaemonEndpoint ( ) , FORMAT_OTEL_SAMPLED_TRACES_BINARY_PREFIX ) ;
455- default :
456- diag . warn ( `Unsupported OTLP traces protocol: ${ protocol } . Using http/protobuf.` ) ;
457- if ( otlp_exporter_traces_endpoint && isXrayOtlpEndpoint ( otlp_exporter_traces_endpoint ) ) {
458- diag . debug ( 'Detected XRay OTLP Traces endpoint. Switching exporter to OtlpAwsSpanExporter' ) ;
459- return new OTLPAwsSpanExporter ( otlp_exporter_traces_endpoint ) ;
460- }
461- return new OTLPProtoTraceExporter ( ) ;
458+
459+ return this . getExporterBasedOnProtocol ( protocol , signal ) ;
460+ }
461+
462+ static getExporterBasedOnProtocol ( protocol : string , signal : SignalType ) : SpanExporter | LogRecordExporter {
463+ const otlpExporterTracesEndpoint = process . env [ 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' ] ;
464+ const otlpExporterLogsEndpoint = process . env [ 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT' ] ;
465+
466+ if ( signal === 'LOGS' ) {
467+ switch ( protocol ) {
468+ case 'grpc' :
469+ return new OTLPGrpcLogExporter ( ) ;
470+ case 'http/json' :
471+ return new OTLPHttpLogExporter ( ) ;
472+ case 'http/protobuf' :
473+ return new OTLPProtoLogExporter ( ) ;
474+ default :
475+ diag . warn ( `Unsupported OTLP traces protocol: ${ protocol } . Using http/protobuf.` ) ;
476+ if ( otlpExporterLogsEndpoint && isXrayOtlpEndpoint ( otlpExporterLogsEndpoint ) ) {
477+ diag . debug ( 'Detected CloudWatch Logs OTLP Logs endpoint. Switching exporter to OTLPAwsLogExporter' ) ;
478+ return new OTLPAwsLogExporter ( otlpExporterLogsEndpoint ) ;
479+ }
480+ return new OTLPProtoLogExporter ( ) ;
481+ }
482+ }
483+
484+ if ( signal === 'TRACES' ) {
485+ switch ( protocol ) {
486+ case 'grpc' :
487+ return new OTLPGrpcTraceExporter ( ) ;
488+ case 'http/json' :
489+ return new OTLPHttpTraceExporter ( ) ;
490+ case 'http/protobuf' :
491+ return new OTLPProtoTraceExporter ( ) ;
492+ case 'udp' :
493+ diag . debug ( 'Detected AWS Lambda environment and enabling UDPSpanExporter' ) ;
494+ return new OTLPUdpSpanExporter ( getXrayDaemonEndpoint ( ) , FORMAT_OTEL_SAMPLED_TRACES_BINARY_PREFIX ) ;
495+ default :
496+ diag . warn ( `Unsupported OTLP traces protocol: ${ protocol } . Using http/protobuf.` ) ;
497+ if ( otlpExporterTracesEndpoint && isXrayOtlpEndpoint ( otlpExporterTracesEndpoint ) ) {
498+ diag . debug ( 'Detected XRay OTLP Traces endpoint. Switching exporter to OtlpAwsSpanExporter' ) ;
499+ return new OTLPAwsSpanExporter ( otlpExporterTracesEndpoint ) ;
500+ }
501+ return new OTLPProtoTraceExporter ( ) ;
502+ }
462503 }
504+
505+ return new OTLPProtoTraceExporter ( ) ;
463506 }
464507
465- static getOtlpProtocol ( ) : string {
508+ static getOtlpProtocol ( signal : SignalType ) : string {
466509 // eslint-disable-next-line @typescript-eslint/typedef
467510 const parsedEnvValues = getEnvWithoutDefaults ( ) ;
468511
469- return (
470- parsedEnvValues . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ??
471- parsedEnvValues . OTEL_EXPORTER_OTLP_PROTOCOL ??
472- getEnv ( ) . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ??
473- getEnv ( ) . OTEL_EXPORTER_OTLP_PROTOCOL
474- ) ;
512+ if ( signal === 'TRACES' ) {
513+ return (
514+ parsedEnvValues . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ??
515+ parsedEnvValues . OTEL_EXPORTER_OTLP_PROTOCOL ??
516+ getEnv ( ) . OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ??
517+ getEnv ( ) . OTEL_EXPORTER_OTLP_PROTOCOL
518+ ) ;
519+ }
520+
521+ if ( signal === 'LOGS' ) {
522+ return (
523+ parsedEnvValues . OTEL_EXPORTER_OTLP_LOGS_PROTOCOL ??
524+ parsedEnvValues . OTEL_EXPORTER_OTLP_PROTOCOL ??
525+ getEnv ( ) . OTEL_EXPORTER_OTLP_LOGS_PROTOCOL ??
526+ getEnv ( ) . OTEL_EXPORTER_OTLP_PROTOCOL
527+ ) ;
528+ }
529+
530+ return parsedEnvValues . OTEL_EXPORTER_OTLP_PROTOCOL ?? getEnv ( ) . OTEL_EXPORTER_OTLP_METRICS_PROTOCOL ;
475531 }
476532
477533 private static configureJaeger ( ) {
@@ -489,58 +545,81 @@ export class AwsSpanProcessorProvider {
489545 }
490546 }
491547
492- protected static _registeredExporters : Map < string , ( ) => SpanExporter > = new Map < string , ( ) => SpanExporter > ( [
493- [ 'otlp' , ( ) => this . configureOtlp ( ) ] ,
548+ protected static _registeredTraceExporters : Map < string , ( ) => SpanExporter > = new Map < string , ( ) => SpanExporter > ( [
549+ [ 'otlp' , ( ) => this . configureOtlp ( 'TRACES' ) as SpanExporter ] ,
494550 [ 'zipkin' , ( ) => new ZipkinExporter ( ) ] ,
495551 [ 'jaeger' , ( ) => this . configureJaeger ( ) ] ,
496552 [ 'console' , ( ) => new ConsoleSpanExporter ( ) ] ,
497553 ] ) ;
498554
555+ protected static _registeredLogRecordExporters : Map < string , ( ) => LogRecordExporter > = new Map <
556+ string ,
557+ ( ) => LogRecordExporter
558+ > ( [
559+ [ 'otlp' , ( ) => this . configureOtlp ( 'LOGS' ) as LogRecordExporter ] ,
560+ [ 'logging' , ( ) => new ConsoleLogRecordExporter ( ) ] ,
561+ [ 'console' , ( ) => new ConsoleLogRecordExporter ( ) ] ,
562+ ] ) ;
563+
499564 public constructor ( resource : Resource ) {
500565 this . resource = resource ;
501566
502567 // eslint-disable-next-line @typescript-eslint/typedef
503- let traceExportersList = this . filterBlanksAndNulls ( Array . from ( new Set ( getEnv ( ) . OTEL_TRACES_EXPORTER . split ( ',' ) ) ) ) ;
568+ const traceExportersList = this . filterBlanksAndNulls ( Array . from ( new Set ( getEnv ( ) . OTEL_TRACES_EXPORTER . split ( ',' ) ) ) ) ;
569+ const logsExportersList = this . filterBlanksAndNulls ( Array . from ( new Set ( getEnv ( ) . OTEL_LOGS_EXPORTER . split ( ',' ) ) ) ) ;
504570
505- if ( traceExportersList [ 0 ] === 'none' ) {
506- diag . warn ( 'OTEL_TRACES_EXPORTER contains "none". SDK will not be initialized.' ) ;
507- } else if ( traceExportersList . length === 0 ) {
508- diag . warn ( 'OTEL_TRACES_EXPORTER is empty. Using default otlp exporter.' ) ;
571+ this . _configuredSpanExporters = this . createExportersFromList ( traceExportersList , 'TRACES' ) as SpanExporter [ ] ;
572+ this . _configuredLogExporters = this . createExportersFromList ( logsExportersList , 'LOGS' ) as LogRecordExporter [ ] ;
509573
510- traceExportersList = [ 'otlp' ] ;
511- this . createExportersFromList ( traceExportersList ) ;
574+ this . _spanProcessors = this . configureSpanProcessors ( this . _configuredSpanExporters ) ;
575+ this . _logRecordProcessors = this . configureLogRecordProcessors ( this . _configuredLogExporters ) ;
576+ }
512577
513- this . _spanProcessors = this . configureSpanProcessors ( this . _configuredExporters ) ;
514- } else {
515- if ( traceExportersList . length > 1 && traceExportersList . includes ( 'none' ) ) {
516- diag . warn ( 'OTEL_TRACES_EXPORTER contains "none" along with other exporters. Using default otlp exporter.' ) ;
517- traceExportersList = [ 'otlp' ] ;
518- }
578+ private createExportersFromList ( exportersList : string [ ] , signal : SignalType ) {
579+ let exporterNames : string [ ] = exportersList ;
580+ const envVar = `OTEL_${ signal } _EXPORTER` ;
519581
520- this . createExportersFromList ( traceExportersList ) ;
582+ if ( exporterNames . length === 0 ) {
583+ diag . warn ( `${ envVar } is empty. Using default otlp exporter.` ) ;
584+ exporterNames = [ 'otlp' ] ;
585+ }
521586
522- if ( this . _configuredExporters . length > 0 ) {
523- this . _spanProcessors = this . configureSpanProcessors ( this . _configuredExporters ) ;
524- } else {
525- diag . warn ( 'Unable to set up trace exporter(s) due to invalid exporter and/or protocol values.' ) ;
526- }
587+ if ( exporterNames . length === 1 && exporterNames [ 0 ] === 'none' ) {
588+ diag . warn ( `${ envVar } is "none". SDK will not be initialized.` ) ;
527589 }
528- }
529590
530- private createExportersFromList ( exporterList : string [ ] ) {
531- exporterList . forEach ( exporterName => {
532- // eslint-disable-next-line @typescript-eslint/typedef
533- const exporter = this . _getSpanExporter ( exporterName ) ;
534- if ( exporter ) {
535- this . _configuredExporters . push ( exporter ) ;
536- } else {
537- diag . warn ( `Unrecognized OTEL_TRACES_EXPORTER value: ${ exporterName } .` ) ;
591+ if ( exporterNames . length > 1 && exporterNames . includes ( 'none' ) ) {
592+ diag . warn ( `${ envVar } contains "none" along with other exporters. Using default otlp exporter.` ) ;
593+ exporterNames = [ 'otlp' ] ;
594+ }
595+
596+ if ( exporterNames . length > 0 ) {
597+ const exporters = [ ] ;
598+ for ( const exporterName in exporterNames ) {
599+ const exporter = this . _getExporter ( exporterName , signal ) ;
600+ if ( exporter ) {
601+ exporters . push ( exporter ) ;
602+ } else {
603+ diag . warn ( `Unrecognized ${ envVar } value: ${ exporterName } .` ) ;
604+ }
538605 }
539- } ) ;
606+ return exporters ;
607+ } else {
608+ diag . warn ( `Unable to set up ${ signal . toLowerCase } exporter(s) due to invalid exporter and/or protocol values.` ) ;
609+ return [ ] ;
610+ }
540611 }
541612
542- protected _getSpanExporter ( name : string ) : SpanExporter | undefined {
543- return AwsSpanProcessorProvider . _registeredExporters . get ( name ) ?.( ) ;
613+ protected _getExporter ( name : string , signal : SignalType ) : SpanExporter | LogRecordExporter | undefined {
614+ if ( signal == 'LOGS' ) {
615+ return AwsSpanProcessorProvider . _registeredLogRecordExporters . get ( name ) ?.( ) ;
616+ }
617+
618+ if ( signal == 'TRACES' ) {
619+ return AwsSpanProcessorProvider . _registeredTraceExporters . get ( name ) ?.( ) ;
620+ }
621+
622+ return undefined ;
544623 }
545624
546625 private configureSpanProcessors ( exporters : SpanExporter [ ] ) : ( BatchSpanProcessor | SimpleSpanProcessor ) [ ] {
@@ -556,6 +635,17 @@ export class AwsSpanProcessorProvider {
556635 } ) ;
557636 }
558637
638+ private configureLogRecordProcessors (
639+ exporters : LogRecordExporter [ ]
640+ ) : ( BatchLogRecordProcessor | SimpleLogRecordProcessor ) [ ] {
641+ return exporters . map ( exporter => {
642+ if ( exporter instanceof ConsoleLogRecordExporter ) {
643+ return new SimpleLogRecordProcessor ( exporter ) ;
644+ }
645+ return new BatchLogRecordProcessor ( exporter ) ;
646+ } ) ;
647+ }
648+
559649 private filterBlanksAndNulls ( list : string [ ] ) : string [ ] {
560650 return list . map ( item => item . trim ( ) ) . filter ( s => s !== 'null' && s !== '' ) ;
561651 }
0 commit comments