Skip to content

Commit e3fe80e

Browse files
committed
enable sigv4 in auto instrumentation
1 parent 28836c8 commit e3fe80e

File tree

1 file changed

+155
-65
lines changed

1 file changed

+155
-65
lines changed

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts

Lines changed: 155 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import {
1414
import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
1515
import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
1616
import { 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';
1720
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
1821
import { AWSXRayIdGenerator } from '@opentelemetry/id-generator-aws-xray';
1922
import { 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';
5364
import { SEMRESATTRS_TELEMETRY_AUTO_VERSION } from '@opentelemetry/semantic-conventions';
5465
import { AlwaysRecordSampler } from './always-record-sampler';
5566
import { AttributePropagatingSpanProcessorBuilder } from './attribute-propagating-span-processor-builder';
@@ -61,6 +72,8 @@ import { OTLPUdpSpanExporter } from './otlp-udp-exporter';
6172
import { AwsXRayRemoteSampler } from './sampler/aws-xray-remote-sampler';
6273
// This file is generated via `npm run compile`
6374
import { 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

6578
const 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
6982
const METRIC_EXPORT_INTERVAL_CONFIG: string = 'OTEL_METRIC_EXPORT_INTERVAL';
7083
const DEFAULT_METRIC_EXPORT_INTERVAL_MILLIS: number = 60000;
7184
export const AWS_LAMBDA_FUNCTION_NAME_CONFIG: string = 'AWS_LAMBDA_FUNCTION_NAME';
85+
export const AGENT_OBSERVABILITY_ENABLED = 'AGENT_OBSERVABILITY_ENABLED';
7286
const AWS_XRAY_DAEMON_ADDRESS_CONFIG: string = 'AWS_XRAY_DAEMON_ADDRESS';
7387
const FORMAT_OTEL_SAMPLED_TRACES_BINARY_PREFIX = 'T1S';
7488
const 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+
424440
export 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

Comments
 (0)