|
11 | 11 | AWS_QUEUE_NAME, |
12 | 12 | AWS_QUEUE_URL, |
13 | 13 | AWS_REMOTE_OPERATION, |
| 14 | + AWS_REMOTE_RESOURCE_IDENTIFIER, |
| 15 | + AWS_REMOTE_RESOURCE_TYPE, |
14 | 16 | AWS_REMOTE_SERVICE, |
15 | | - AWS_REMOTE_TARGET, |
16 | 17 | AWS_SPAN_KIND, |
17 | 18 | AWS_STREAM_NAME, |
18 | 19 | ) |
|
65 | 66 | _AWS_TABLE_NAMES: str = SpanAttributes.AWS_DYNAMODB_TABLE_NAMES |
66 | 67 | _AWS_BUCKET_NAME: str = SpanAttributes.AWS_S3_BUCKET |
67 | 68 |
|
| 69 | +# Normalized remote service names for supported AWS services |
| 70 | +_NORMALIZED_DYNAMO_DB_SERVICE_NAME: str = "AWS::DynamoDB" |
| 71 | +_NORMALIZED_KINESIS_SERVICE_NAME: str = "AWS::Kinesis" |
| 72 | +_NORMALIZED_S3_SERVICE_NAME: str = "AWS::S3" |
| 73 | +_NORMALIZED_SQS_SERVICE_NAME: str = "AWS::SQS" |
| 74 | + |
68 | 75 | # Special DEPENDENCY attribute value if GRAPHQL_OPERATION_TYPE attribute key is present. |
69 | 76 | _GRAPHQL: str = "graphql" |
70 | 77 |
|
@@ -110,7 +117,7 @@ def _generate_dependency_metric_attributes(span: ReadableSpan, resource: Resourc |
110 | 117 | _set_service(resource, span, attributes) |
111 | 118 | _set_egress_operation(span, attributes) |
112 | 119 | _set_remote_service_and_operation(span, attributes) |
113 | | - _set_remote_target(span, attributes) |
| 120 | + _set_remote_type_and_identifier(span, attributes) |
114 | 121 | _set_span_kind_for_dependency(span, attributes) |
115 | 122 | return attributes |
116 | 123 |
|
@@ -198,7 +205,7 @@ def _set_remote_service_and_operation(span: ReadableSpan, attributes: BoundedAtt |
198 | 205 | remote_service = _get_remote_service(span, AWS_REMOTE_SERVICE) |
199 | 206 | remote_operation = _get_remote_operation(span, AWS_REMOTE_OPERATION) |
200 | 207 | elif is_key_present(span, _RPC_SERVICE) or is_key_present(span, _RPC_METHOD): |
201 | | - remote_service = _normalize_service_name(span, _get_remote_service(span, _RPC_SERVICE)) |
| 208 | + remote_service = _normalize_remote_service_name(span, _get_remote_service(span, _RPC_SERVICE)) |
202 | 209 | remote_operation = _get_remote_operation(span, _RPC_METHOD) |
203 | 210 | elif is_key_present(span, _DB_SYSTEM) or is_key_present(span, _DB_OPERATION) or is_key_present(span, _DB_STATEMENT): |
204 | 211 | remote_service = _get_remote_service(span, _DB_SYSTEM) |
@@ -268,10 +275,14 @@ def _get_db_statement_remote_operation(span: ReadableSpan, statement_key: str) - |
268 | 275 | return remote_operation |
269 | 276 |
|
270 | 277 |
|
271 | | -def _normalize_service_name(span: ReadableSpan, service_name: str) -> str: |
| 278 | +def _normalize_remote_service_name(span: ReadableSpan, service_name: str) -> str: |
| 279 | + """ |
| 280 | + If the span is an AWS SDK span, normalize the name to align with <a |
| 281 | + href="https://docs.aws.amazon.com/cloudcontrolapi/latest/userguide/supported-resources.html">AWS Cloud Control |
| 282 | + resource format</a> as much as possible. Long term, we would like to normalize service name in the upstream. |
| 283 | + """ |
272 | 284 | if is_aws_sdk_span(span): |
273 | | - return "AWS.SDK." + service_name |
274 | | - |
| 285 | + return "AWS::" + service_name |
275 | 286 | return service_name |
276 | 287 |
|
277 | 288 |
|
@@ -320,38 +331,39 @@ def _generate_remote_operation(span: ReadableSpan) -> str: |
320 | 331 | return remote_operation |
321 | 332 |
|
322 | 333 |
|
323 | | -def _set_remote_target(span: ReadableSpan, attributes: BoundedAttributes) -> None: |
324 | | - remote_target: Optional[str] = _get_remote_target(span) |
325 | | - if remote_target is not None: |
326 | | - attributes[AWS_REMOTE_TARGET] = remote_target |
327 | | - |
328 | | - |
329 | | -def _get_remote_target(span: ReadableSpan) -> Optional[str]: |
| 334 | +def _set_remote_type_and_identifier(span: ReadableSpan, attributes: BoundedAttributes) -> None: |
330 | 335 | """ |
331 | | - RemoteTarget attribute AWS_REMOTE_TARGET is used to store the resource |
332 | | - name of the remote invokes, such as S3 bucket name, mysql table name, etc. |
333 | | - TODO: currently only support AWS resource name, will be extended to support |
334 | | - the general remote targets, such as ActiveMQ name, etc. |
335 | | - """ |
336 | | - if is_key_present(span, _AWS_BUCKET_NAME): |
337 | | - return "::s3:::" + span.attributes.get(_AWS_BUCKET_NAME) |
338 | | - |
339 | | - if is_key_present(span, AWS_QUEUE_URL): |
340 | | - arn = SqsUrlParser.get_sqs_remote_target(span.attributes.get(AWS_QUEUE_URL)) |
341 | | - if arn: |
342 | | - return arn |
343 | | - |
344 | | - if is_key_present(span, AWS_QUEUE_NAME): |
345 | | - return "::sqs:::" + span.attributes.get(AWS_QUEUE_NAME) |
| 336 | + Remote resource attributes {@link AwsAttributeKeys#AWS_REMOTE_RESOURCE_TYPE} and {@link |
| 337 | + AwsAttributeKeys#AWS_REMOTE_RESOURCE_IDENTIFIER} are used to store information about the resource associated with |
| 338 | + the remote invocation, such as S3 bucket name, etc. We should only ever set both type and identifier or neither. |
346 | 339 |
|
347 | | - if is_key_present(span, AWS_STREAM_NAME): |
348 | | - return "::kinesis:::stream/" + span.attributes.get(AWS_STREAM_NAME) |
| 340 | + AWS resources type and identifier adhere to <a |
| 341 | + href="https://docs.aws.amazon.com/cloudcontrolapi/latest/userguide/supported-resources.html">AWS Cloud Control |
| 342 | + resource format</a>. |
| 343 | + """ |
| 344 | + remote_resource_type: Optional[str] = None |
| 345 | + remote_resource_identifier: Optional[str] = None |
349 | 346 |
|
350 | 347 | # Only extract the table name when _AWS_TABLE_NAMES has size equals to one |
351 | 348 | if is_key_present(span, _AWS_TABLE_NAMES) and len(span.attributes.get(_AWS_TABLE_NAMES)) == 1: |
352 | | - return "::dynamodb:::table/" + span.attributes.get(_AWS_TABLE_NAMES)[0] |
353 | | - |
354 | | - return None |
| 349 | + remote_resource_type = _NORMALIZED_DYNAMO_DB_SERVICE_NAME + "::Table" |
| 350 | + remote_resource_identifier = span.attributes.get(_AWS_TABLE_NAMES)[0] |
| 351 | + elif is_key_present(span, AWS_STREAM_NAME): |
| 352 | + remote_resource_type = _NORMALIZED_KINESIS_SERVICE_NAME + "::Stream" |
| 353 | + remote_resource_identifier = span.attributes.get(AWS_STREAM_NAME) |
| 354 | + elif is_key_present(span, _AWS_BUCKET_NAME): |
| 355 | + remote_resource_type = _NORMALIZED_S3_SERVICE_NAME + "::Bucket" |
| 356 | + remote_resource_identifier = span.attributes.get(_AWS_BUCKET_NAME) |
| 357 | + elif is_key_present(span, AWS_QUEUE_NAME): |
| 358 | + remote_resource_type = _NORMALIZED_SQS_SERVICE_NAME + "::Queue" |
| 359 | + remote_resource_identifier = span.attributes.get(AWS_QUEUE_NAME) |
| 360 | + elif is_key_present(span, AWS_QUEUE_URL): |
| 361 | + remote_resource_type = _NORMALIZED_SQS_SERVICE_NAME + "::Queue" |
| 362 | + remote_resource_identifier = SqsUrlParser.get_queue_name(span.attributes.get(AWS_QUEUE_URL)) |
| 363 | + |
| 364 | + if remote_resource_type is not None and remote_resource_identifier is not None: |
| 365 | + attributes[AWS_REMOTE_RESOURCE_TYPE] = remote_resource_type |
| 366 | + attributes[AWS_REMOTE_RESOURCE_IDENTIFIER] = remote_resource_identifier |
355 | 367 |
|
356 | 368 |
|
357 | 369 | def _set_span_kind_for_dependency(span: ReadableSpan, attributes: BoundedAttributes) -> None: |
|
0 commit comments