Update 2025-06-18: Provisioning with CloudFormation
Recently, AWS added native CloudFormation support for provisioning Application Signals Transaction Search. You can find the official documentation here:
Here is an example of how to implement it in the AWS CDK:
import { CfnTransactionSearchConfig } from "aws-cdk-lib/aws-xray";
import { CfnResourcePolicy } from "aws-cdk-lib/aws-logs";
const { account, partition, region } = Stack.of(this);
const transactionSearchAccess = new CfnResourcePolicy(
this,
"XRayLogResourcePolicy",
{
policyName: "TransactionSearchAccess",
policyDocument: JSON.stringify({
Version: "2012-10-17",
Statement: [
{
Sid: "TransactionSearchXRayAccess",
Effect: "Allow",
Principal: {
Service: "xray.amazonaws.com",
},
Action: "logs:PutLogEvents",
Resource: [
`arn:${partition}:logs:${region}:${account}:log-group:aws/spans:*`,
`arn:${partition}:logs:${region}:${account}:log-group:/aws/application-signals/data:*`,
],
Condition: {
ArnLike: {
"aws:SourceArn": `arn:${partition}:xray:${region}:${account}:*`,
},
StringEquals: {
"aws:SourceAccount": account,
},
},
},
],
}),
},
);
const transactionSearchConfig = new CfnTransactionSearchConfig(
this,
"XRayTransactionSearchConfig",
{
indexingPercentage: 100,
},
);
transactionSearchConfig.node.addDependency(transactionSearchAccess);
⚠️ To avoid the following error, you must first update the X-Ray segment destination to XRay before creating the Transaction Search Config again with CloudFormation:
aws xray update-trace-segment-destination --destination XRay
Without this step, you may encounter this error:
1:24:42 PM | CREATE_FAILED | AWS::XRay::TransactionSearchConfig | ApplicationsSignal...archConfigF88EF961
Resource handler returned message: "null" (RequestToken: 94079df2-4a8f-2771-a3e4-03eb0ccbc436, HandlerErrorCode: AlreadyExists)
(The rest of this post describes the original method using custom resources, which is still useful for understanding the underlying API calls.)
Use case
You want to use AWS Cloudwatch Application Signals Transaction Search and your IaC is based on AWS CDK.
Setup
This is how the Transaction Search page looks like, if it's not yet configured:
And like this in the x-ray settings:
The AWS documentation outlines the steps to enable Transaction Search functionality here: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Transaction-Search-getting-started.html#w24aac24c21c13b9
While the documentation provides AWS CLI commands, we can implement the same configuration using AWS CDK Custom Resources for infrastructure as code.
The whole configuration looks like this:
const { account, region } = Stack.of(this);
// https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Transaction-Search-getting-started.html#w24aac24c21c13b9
const applicationSignalsTransactionSearchLogsResourcePolicy =
new AwsCustomResource(
this,
"ApplicationSignalsTransactionSearchLogsResourcePolicy",
{
onCreate: {
service: "@aws-sdk/client-cloudwatch-logs",
action: "PutResourcePolicy",
parameters: {
policyName:
"ApplicationSignalsTransactionSearchLogsResourcePolicy",
policyDocument: JSON.stringify({
Version: "2012-10-17",
Statement: [
{
Sid: "TransactionSearchXRayAccess",
Effect: "Allow",
Principal: {
Service: "xray.amazonaws.com",
},
Action: ["logs:PutLogEvents", "logs:CreateLogStream"],
Resource: [
`arn:aws:logs:${region}:${account}:log-group:aws/spans:*`,
`arn:aws:logs:${region}:${account}:log-group:/aws/application-signals/data:*`,
],
Condition: {
ArnLike: {
"aws:SourceArn": `arn:aws:xray:${region}:${account}:*`,
},
StringEquals: {
"aws:SourceAccount": account,
},
},
},
],
}),
},
physicalResourceId: PhysicalResourceId.of(
"ApplicationSignalsTransactionSearchLogsResourcePolicy",
),
},
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE,
}),
},
);
const applicationSignalsTransactionSearchXraySegmentDestination =
new AwsCustomResource(
this,
"ApplicationSignalsTransactionSearchXraySegmentDestination",
{
onCreate: {
service: "@aws-sdk/client-xray",
action: "UpdateTraceSegmentDestination",
parameters: {
Destination: "CloudWatchLogs",
},
physicalResourceId: PhysicalResourceId.of(
"ApplicationSignalsTransactionSearchXraySegmentDestination",
),
},
installLatestAwsSdk: true,
policy: AwsCustomResourcePolicy.fromStatements([
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["logs:PutRetentionPolicy"],
resources: [
`arn:aws:logs:${region}:${account}:log-group:aws/spans:log-stream:`,
],
}),
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["xray:UpdateTraceSegmentDestination"],
resources: ["*"],
}),
]),
},
);
applicationSignalsTransactionSearchXraySegmentDestination.node.addDependency(
applicationSignalsTransactionSearchLogsResourcePolicy,
);
const applicationSignalsTransactionSearchXrayIndexRule =
new AwsCustomResource(
this,
"ApplicationSignalsTransactionSearchXrayIndexRule",
{
onCreate: {
service: "@aws-sdk/client-xray",
action: "UpdateIndexingRule",
parameters: {
Name: "Default",
Rule: {
Probabilistic: {
DesiredSamplingPercentage: 100,
},
},
},
physicalResourceId: PhysicalResourceId.of(
"ApplicationSignalsTransactionSearchXrayIndexRule",
),
},
installLatestAwsSdk: true,
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE,
}),
},
);
NagSuppressions.addResourceSuppressions(
[
applicationSignalsTransactionSearchXraySegmentDestination,
applicationSignalsTransactionSearchLogsResourcePolicy,
applicationSignalsTransactionSearchXrayIndexRule,
],
[
{
id: "AwsSolutions-IAM5",
reason: "CDK managed policy",
},
],
true,
);
}
It contains the following steps:
- Update the Cloudwatch Logs Resource Policy
- Update the x-ray settings
Update the Cloudwatch Logs Resource Policy
The documentation here is a little bit misleading. The shown condition arn:partition:logs:region:account-id:* should be arn:partition:xray:region:account-id:*. Also the action logs:PutLogEvents should be logs:PutLogEvents and logs:CreateLogStream.
const applicationSignalsTransactionSearchLogsResourcePolicy =
new AwsCustomResource(
this,
"ApplicationSignalsTransactionSearchLogsResourcePolicy",
{
onCreate: {
service: "@aws-sdk/client-cloudwatch-logs",
action: "PutResourcePolicy",
parameters: {
policyName:
"ApplicationSignalsTransactionSearchLogsResourcePolicy",
policyDocument: JSON.stringify({
Version: "2012-10-17",
Statement: [
{
Sid: "TransactionSearchXRayAccess",
Effect: "Allow",
Principal: {
Service: "xray.amazonaws.com",
},
Action: ["logs:PutLogEvents", "logs:CreateLogStream"],
Resource: [
`arn:aws:logs:${region}:${account}:log-group:aws/spans:*`,
`arn:aws:logs:${region}:${account}:log-group:/aws/application-signals/data:*`,
],
Condition: {
ArnLike: {
"aws:SourceArn": `arn:aws:xray:${region}:${account}:*`,
},
StringEquals: {
"aws:SourceAccount": account,
},
},
},
],
}),
},
physicalResourceId: PhysicalResourceId.of(
"ApplicationSignalsTransactionSearchLogsResourcePolicy",
),
},
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE,
}),
},
);
Update the x-ray settings
The 2 API calls for x-ray are nearly straight forward. Only the comamnds UpdateTraceSegmentDestination and UpdateIndexingRule requires the newest SDK version, because it's introduced in version: https://github.com/aws/aws-sdk-js-v3/releases/tag/v3.698.0
const applicationSignalsTransactionSearchXraySegmentDestination =
new AwsCustomResource(
this,
"ApplicationSignalsTransactionSearchXraySegmentDestination",
{
onCreate: {
service: "@aws-sdk/client-xray",
action: "UpdateTraceSegmentDestination",
parameters: {
Destination: "CloudWatchLogs",
},
physicalResourceId: PhysicalResourceId.of(
"ApplicationSignalsTransactionSearchXraySegmentDestination",
),
},
installLatestAwsSdk: true,
policy: AwsCustomResourcePolicy.fromStatements([
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["logs:PutRetentionPolicy"],
resources: [
`arn:aws:logs:${region}:${account}:log-group:aws/spans:log-stream:`,
],
}),
new PolicyStatement({
effect: Effect.ALLOW,
actions: ["xray:UpdateTraceSegmentDestination"],
resources: ["*"],
}),
]),
},
);
applicationSignalsTransactionSearchXraySegmentDestination.node.addDependency(
applicationSignalsTransactionSearchLogsResourcePolicy,
);
const applicationSignalsTransactionSearchXrayIndexRule =
new AwsCustomResource(
this,
"ApplicationSignalsTransactionSearchXrayIndexRule",
{
onCreate: {
service: "@aws-sdk/client-xray",
action: "UpdateIndexingRule",
parameters: {
Name: "Default",
Rule: {
Probabilistic: {
DesiredSamplingPercentage: 100,
},
},
},
physicalResourceId: PhysicalResourceId.of(
"ApplicationSignalsTransactionSearchXrayIndexRule",
),
},
installLatestAwsSdk: true,
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE,
}),
},
);
Result
After some minutes the Transaction Search is visible in the Management Console.




Top comments (0)