|
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