packages/@aws-cdk/aws-applicationsignals-alpha/lib/enablement/ecs.ts (113 lines of code) (raw):
import { Annotations } from 'aws-cdk-lib';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import { Construct } from 'constructs';
import * as constants from './constants';
import * as agent from './ecs-cloudwatch-agent';
import * as sdk from './ecs-sdk-instrumentation';
import * as inst from './instrumentation-versions';
/**
* Interface for instrumentation properties.
*/
export interface InstrumentationProps {
/**
* The version of the instrumentation.
*/
readonly sdkVersion: inst.InstrumentationVersion;
/**
* The runtime platform of the instrumentation.
*
* @default - the runtime platform specified through the input TaskDefinition.
*/
readonly runtimePlatform?: ecs.RuntimePlatform;
}
/**
* Interface for Application Signals properties.
*/
export interface ApplicationSignalsIntegrationProps {
/**
* The name of the service.
*
* @default - task definition family name
*/
readonly serviceName?: string;
/**
* The task definition to integrate Application Signals into.
*
* [disable-awslint:ref-via-interface]
*/
readonly taskDefinition: ecs.TaskDefinition;
/**
* The instrumentation properties.
*/
readonly instrumentation: InstrumentationProps;
/**
* The environment variables to override.
*
* @default - no environment variables to override.
*/
readonly overrideEnvironments?: sdk.EnvironmentExtension[];
/**
* The CloudWatch Agent properties.
*
* @default - a basic agent sidecar container with latest public image
*/
readonly cloudWatchAgentSidecar?: agent.CloudWatchAgentOptions;
}
/**
* Class for integrating Application Signals into an ECS task definition.
*/
export class ApplicationSignalsIntegration extends Construct {
private sdkInjector?: sdk.Injector;
private mountVolumeName: string = 'opentelemetry-auto-instrumentation';
private cloudWatchAgentSidecar?: agent.CloudWatchAgentOptions;
constructor(
scope: Construct,
id: string,
props: ApplicationSignalsIntegrationProps) {
super(scope, id);
this.cloudWatchAgentSidecar = props.cloudWatchAgentSidecar;
let runtimePlatformObj = props.instrumentation.runtimePlatform ?? (props.taskDefinition as any).runtimePlatform;
let cpuArch = ecs.CpuArchitecture.X86_64;
let isWindows = false;
if (runtimePlatformObj) {
const runtimePlatform = runtimePlatformObj as ecs.RuntimePlatform;
if (runtimePlatform.operatingSystemFamily) {
isWindows = runtimePlatform.operatingSystemFamily.isWindows();
if (runtimePlatform.cpuArchitecture) {
cpuArch = runtimePlatform.cpuArchitecture;
}
}
}
const overrideEnvironments = [];
if (props.serviceName) {
// If service.name is also provided in OTEL_RESOURCE_ATTRIBUTES, then OTEL_SERVICE_NAME takes precedence.
overrideEnvironments.push({
name: constants.CommonExporting.OTEL_SERVICE_NAME,
value: props.serviceName,
});
}
overrideEnvironments.push(...props.overrideEnvironments ?? []);
if (props.instrumentation.sdkVersion instanceof inst.JavaInstrumentationVersion) {
this.sdkInjector = new sdk.JavaInjector(
this.mountVolumeName,
props.instrumentation.sdkVersion,
overrideEnvironments,
);
} else if (props.instrumentation.sdkVersion instanceof inst.PythonInstrumentationVersion) {
this.sdkInjector = new sdk.PythonInjector(
this.mountVolumeName,
props.instrumentation.sdkVersion,
overrideEnvironments,
);
} else if (props.instrumentation.sdkVersion instanceof inst.DotnetInstrumentationVersion) {
if (isWindows) {
this.sdkInjector = new sdk.DotNetWindowsInjector(
this.mountVolumeName,
props.instrumentation.sdkVersion,
overrideEnvironments,
);
} else {
this.sdkInjector = new sdk.DotNetLinuxInjector(
this.mountVolumeName,
props.instrumentation.sdkVersion,
cpuArch,
overrideEnvironments,
);
}
} else if (props.instrumentation.sdkVersion instanceof inst.NodeInstrumentationVersion) {
this.sdkInjector = new sdk.NodeInjector(
this.mountVolumeName,
props.instrumentation.sdkVersion,
overrideEnvironments,
);
}
this.mutateTaskDefinition(props.taskDefinition);
}
private mutateTaskDefinition(taskDefinition: ecs.TaskDefinition) {
taskDefinition.addVolume({
name: this.mountVolumeName,
});
let defaultContainer = taskDefinition.defaultContainer!;
if (this.sdkInjector) {
this.sdkInjector.renderDefaultContainer(taskDefinition);
let initContainer = this.sdkInjector.injectInitContainer(taskDefinition);
defaultContainer.addContainerDependencies({
container: initContainer,
condition: ecs.ContainerDependencyCondition.SUCCESS,
});
}
if (this.cloudWatchAgentSidecar) {
const cloudWatchAgent = new agent.CloudWatchAgentIntegration(this, 'CloudWatchAgentSidecar',
{
taskDefinition: taskDefinition,
...this.cloudWatchAgentSidecar,
},
);
defaultContainer.addContainerDependencies({
container: cloudWatchAgent.agentContainer,
condition: ecs.ContainerDependencyCondition.START,
});
} else {
Annotations.of(this).addWarningV2(this.node.id, ' Application Signals functionality requires prior deployment of the CloudWatch Agent with appropriate security group settings. Missing or incorrect configurations will prevent successful collection of observability data.');
}
}
}