Skip to content

Commit cb900ea

Browse files
authored
feat(instr-aws-sdk): add AWS_SNS_TOPIC_ARN semantic convention support for AWS SNS SDK (#2885)
1 parent 5988c79 commit cb900ea

File tree

6 files changed

+88
-20
lines changed

6 files changed

+88
-20
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/node/opentelemetry-instrumentation-aws-sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"@opentelemetry/core": "^2.0.0",
4848
"@opentelemetry/instrumentation": "^0.202.0",
4949
"@opentelemetry/propagation-utils": "^0.31.2",
50-
"@opentelemetry/semantic-conventions": "^1.31.0"
50+
"@opentelemetry/semantic-conventions": "^1.34.0"
5151
},
5252
"devDependencies": {
5353
"@aws-sdk/client-bedrock-runtime": "^3.587.0",

plugins/node/opentelemetry-instrumentation-aws-sdk/src/semconv.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,13 @@ export const GEN_AI_TOKEN_TYPE_VALUE_INPUT = 'input' as const;
158158
* Enum value "output" for attribute {@link ATTR_GEN_AI_TOKEN_TYPE}.
159159
*/
160160
export const GEN_AI_TOKEN_TYPE_VALUE_OUTPUT = 'output' as const;
161+
162+
/**
163+
* Originally from '@opentelemetry/semantic-conventions/incubating'
164+
* https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/aws.md#amazon-sns-attributes
165+
* The ARN of the AWS SNS Topic. An Amazon SNS [topic](https://docs.aws.amazon.com/sns/latest/dg/sns-create-topic.html)
166+
* is a logical access point that acts as a communication channel.
167+
* @example arn:aws:sns:us-east-1:123456789012:mystack-mytopic-NZJ5JSMVGFIE
168+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
169+
*/
170+
export const ATTR_AWS_SNS_TOPIC_ARN = 'aws.sns.topic.arn' as const;

plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/sns.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
SEMATTRS_MESSAGING_DESTINATION_KIND,
2121
SEMATTRS_MESSAGING_SYSTEM,
2222
} from '@opentelemetry/semantic-conventions';
23+
import { ATTR_AWS_SNS_TOPIC_ARN } from '../semconv';
2324
import {
2425
NormalizedRequest,
2526
NormalizedResponse,
@@ -58,6 +59,11 @@ export class SnsServiceExtension implements ServiceExtension {
5859
} send`;
5960
}
6061

62+
const topicArn = request.commandInput?.TopicArn;
63+
if (topicArn) {
64+
spanAttributes[ATTR_AWS_SNS_TOPIC_ARN] = topicArn;
65+
}
66+
6167
return {
6268
isIncoming: false,
6369
spanAttributes,
@@ -83,7 +89,12 @@ export class SnsServiceExtension implements ServiceExtension {
8389
span: Span,
8490
tracer: Tracer,
8591
config: AwsSdkInstrumentationConfig
86-
): void {}
92+
): void {
93+
const topicArn = response.data?.TopicArn;
94+
if (topicArn) {
95+
span.setAttribute(ATTR_AWS_SNS_TOPIC_ARN, topicArn);
96+
}
97+
}
8798

8899
extractDestinationName(
89100
topicArn: string,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0"?>
2+
<CreateTopicResponse xmlns="https://sns.amazonaws.com/doc/2010-03-31/">
3+
<CreateTopicResult>
4+
<TopicArn>arn:aws:sns:us-east-1:123456789012:sns-topic-foo</TopicArn>
5+
</CreateTopicResult>
6+
<ResponseMetadata>
7+
<RequestId>d74b8436-ae13-5ab4-a9ff-ce54dfea72a0</RequestId>
8+
</ResponseMetadata>
9+
</CreateTopicResponse>

plugins/node/opentelemetry-instrumentation-aws-sdk/test/sns.test.ts

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,30 @@ import {
2727
SEMATTRS_MESSAGING_SYSTEM,
2828
SEMATTRS_RPC_METHOD,
2929
} from '@opentelemetry/semantic-conventions';
30+
import { ATTR_AWS_SNS_TOPIC_ARN } from '@opentelemetry/semantic-conventions/incubating';
3031
import { SpanKind } from '@opentelemetry/api';
3132

3233
describe('SNS - v3', () => {
3334
let sns: any;
34-
beforeEach(() => {
35-
sns = new SNSv3({
36-
region: 'us-east-1',
37-
credentials: {
38-
accessKeyId: 'abcde',
39-
secretAccessKey: 'abcde',
40-
},
41-
});
42-
43-
nock('https://sns.us-east-1.amazonaws.com/')
44-
.post('/')
45-
.reply(
46-
200,
47-
fs.readFileSync('./test/mock-responses/sns-publish.xml', 'utf8')
48-
);
49-
});
5035

5136
describe('publish', () => {
37+
beforeEach(() => {
38+
sns = new SNSv3({
39+
region: 'us-east-1',
40+
credentials: {
41+
accessKeyId: 'abcde',
42+
secretAccessKey: 'abcde',
43+
},
44+
});
45+
46+
nock('https://sns.us-east-1.amazonaws.com/')
47+
.post('/')
48+
.reply(
49+
200,
50+
fs.readFileSync('./test/mock-responses/sns-publish.xml', 'utf8')
51+
);
52+
});
53+
5254
it('topic arn', async () => {
5355
const topicV3Name = 'dummy-sns-v3-topic';
5456
const topicV3ARN = `arn:aws:sns:us-east-1:000000000:${topicV3Name}`;
@@ -73,6 +75,7 @@ describe('SNS - v3', () => {
7375
expect(publishSpan.attributes['messaging.destination.name']).toBe(
7476
topicV3ARN
7577
);
78+
expect(publishSpan.attributes[ATTR_AWS_SNS_TOPIC_ARN]).toBe(topicV3ARN);
7679
expect(publishSpan.attributes[SEMATTRS_RPC_METHOD]).toBe('Publish');
7780
expect(publishSpan.attributes[SEMATTRS_MESSAGING_SYSTEM]).toBe('aws.sns');
7881
expect(publishSpan.kind).toBe(SpanKind.PRODUCER);
@@ -93,6 +96,41 @@ describe('SNS - v3', () => {
9396
expect(publishSpan.attributes[SEMATTRS_MESSAGING_DESTINATION]).toBe(
9497
PhoneNumber
9598
);
99+
expect(publishSpan.attributes[ATTR_AWS_SNS_TOPIC_ARN]).toBeUndefined();
100+
});
101+
});
102+
103+
describe('Create Topic', () => {
104+
beforeEach(() => {
105+
sns = new SNSv3({
106+
region: 'us-east-1',
107+
credentials: {
108+
accessKeyId: 'abcde',
109+
secretAccessKey: 'abcde',
110+
},
111+
});
112+
113+
nock('https://sns.us-east-1.amazonaws.com/')
114+
.post('/')
115+
.reply(
116+
200,
117+
fs.readFileSync('./test/mock-responses/sns-create-topic.xml', 'utf8')
118+
);
119+
});
120+
121+
it('should create topic ARN and capture expected trace attributes', async () => {
122+
const topicName = 'sns-topic-foo';
123+
const topicArn = `arn:aws:sns:us-east-1:123456789012:${topicName}`;
124+
await sns.createTopic({
125+
Name: topicName,
126+
});
127+
const createTopicSpans = getTestSpans().filter(
128+
(s: ReadableSpan) => s.name === 'SNS CreateTopic'
129+
);
130+
expect(createTopicSpans.length).toBe(1);
131+
const span = createTopicSpans[0];
132+
expect(span.attributes[ATTR_AWS_SNS_TOPIC_ARN]).toBe(topicArn);
133+
expect(span.kind).toBe(SpanKind.CLIENT);
96134
});
97135
});
98136
});

0 commit comments

Comments
 (0)