Skip to content

Commit 0cad73a

Browse files
authored
fix(aws): limit api params as span tags [backport #4781 to 1.6] (#4793)
Backport #4781
1 parent c5c5bec commit 0cad73a

File tree

12 files changed

+1052
-622
lines changed

12 files changed

+1052
-622
lines changed

ddtrace/contrib/aiobotocore/__init__.py

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,44 @@
11
"""
22
The aiobotocore integration will trace all AWS calls made with the ``aiobotocore``
3-
library. This integration isn't enabled when applying the default patching.
4-
To enable it, you must run ``patch_all(aiobotocore=True)``
3+
library. This integration is not enabled by default.
54
6-
::
5+
Enabling
6+
~~~~~~~~
77
8-
import aiobotocore.session
9-
from ddtrace import patch
8+
The aiobotocore integration is not enabled by default. Use
9+
:func:`patch()<ddtrace.patch>` to enable the integration::
1010
11-
# If not patched yet, you can patch botocore specifically
11+
from ddtrace import patch
1212
patch(aiobotocore=True)
1313
14-
# This will report spans with the default instrumentation
15-
aiobotocore.session.get_session()
16-
lambda_client = session.create_client('lambda', region_name='us-east-1')
14+
Configuration
15+
~~~~~~~~~~~~~
16+
17+
.. py:data:: ddtrace.config.aiobotocore['tag_no_params']
18+
19+
This opts out of the default behavior of adding span tags for a narrow set of API parameters.
20+
21+
To not collect any API parameters, ``ddtrace.config.aiobotocore.tag_no_params = True`` or by setting the environment
22+
variable ``DD_AWS_TAG_NO_PARAMS=true``.
23+
24+
25+
Default: ``False``
26+
27+
.. py:data:: ddtrace.config.aiobotocore['tag_all_params']
28+
29+
**Deprecated**: This retains the deprecated behavior of adding span tags for
30+
all API parameters that are not explicitly excluded by the integration.
31+
These deprecated span tags will be added along with the API parameters
32+
enabled by default.
33+
34+
This configuration is ignored if ``tag_no_parms`` (``DD_AWS_TAG_NO_PARAMS``)
35+
is set to ``True``.
36+
37+
To collect all API parameters, ``ddtrace.config.botocore.tag_all_params =
38+
True`` or by setting the environment variable ``DD_AWS_TAG_ALL_PARAMS=true``.
39+
1740
18-
# This query generates a trace
19-
lambda_client.list_functions()
41+
Default: ``False``
2042
"""
2143
from ...internal.utils.importlib import require_modules
2244

ddtrace/contrib/aiobotocore/patch.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import os
2+
13
import aiobotocore.client
24

35
from ddtrace import config
46
from ddtrace.internal.utils.version import parse_version
7+
from ddtrace.vendor import debtcollector
58
from ddtrace.vendor import wrapt
69

710
from ...constants import ANALYTICS_SAMPLE_RATE_KEY
@@ -12,6 +15,7 @@
1215
from ...internal.compat import PYTHON_VERSION_INFO
1316
from ...internal.utils import ArgumentError
1417
from ...internal.utils import get_argument_value
18+
from ...internal.utils.formats import asbool
1519
from ...internal.utils.formats import deep_getattr
1620
from ...pin import Pin
1721
from ..trace_utils import unwrap
@@ -31,6 +35,22 @@
3135
TRACED_ARGS = {"params", "path", "verb"}
3236

3337

38+
if os.getenv("DD_AWS_TAG_ALL_PARAMS") is not None:
39+
debtcollector.deprecate(
40+
"Using environment variable 'DD_AWS_TAG_ALL_PARAMS' is deprecated",
41+
message="The aiobotocore integration no longer includes all API parameters by default.",
42+
removal_version="2.0.0",
43+
)
44+
45+
config._add(
46+
"aiobotocore",
47+
{
48+
"tag_no_params": asbool(os.getenv("DD_AWS_TAG_NO_PARAMS", default=False)),
49+
"tag_all_params": asbool(os.getenv("DD_AWS_TAG_ALL_PARAMS", default=False)),
50+
},
51+
)
52+
53+
3454
def patch():
3555
if getattr(aiobotocore.client, "_datadog_patch", False):
3656
return
@@ -94,13 +114,20 @@ async def _wrapped_api_call(original_func, instance, args, kwargs):
94114
span.set_tag(SPAN_MEASURED_KEY)
95115

96116
try:
117+
97118
operation = get_argument_value(args, kwargs, 0, "operation_name")
119+
params = get_argument_value(args, kwargs, 1, "params")
120+
98121
span.resource = "{}.{}".format(endpoint_name, operation.lower())
122+
123+
if params and not config.aiobotocore["tag_no_params"]:
124+
aws._add_api_param_span_tags(span, endpoint_name, params)
99125
except ArgumentError:
100126
operation = None
101127
span.resource = endpoint_name
102128

103-
aws.add_span_arg_tags(span, endpoint_name, args, ARGS_NAME, TRACED_ARGS)
129+
if not config.aiobotocore["tag_no_params"] and config.aiobotocore["tag_all_params"]:
130+
aws.add_span_arg_tags(span, endpoint_name, args, ARGS_NAME, TRACED_ARGS)
104131

105132
region_name = deep_getattr(instance, "meta.region_name")
106133

ddtrace/contrib/boto/__init__.py

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,47 @@
11
"""
22
Boto integration will trace all AWS calls made via boto2.
3-
This integration is automatically patched when using ``patch_all()``::
43
5-
import boto.ec2
6-
from ddtrace import patch
4+
Enabling
5+
~~~~~~~~
6+
7+
The boto integration is enabled automatically when using
8+
:ref:`ddtrace-run<ddtracerun>` or :func:`patch_all()<ddtrace.patch_all>`.
79
8-
# If not patched yet, you can patch boto specifically
10+
Or use :func:`patch()<ddtrace.patch>` to manually enable the integration::
11+
12+
from ddtrace import patch
913
patch(boto=True)
1014
11-
# This will report spans with the default instrumentation
12-
ec2 = boto.ec2.connect_to_region("us-west-2")
13-
# Example of instrumented query
14-
ec2.get_all_instances()
15+
Configuration
16+
~~~~~~~~~~~~~
17+
18+
.. py:data:: ddtrace.config.boto['tag_no_params']
19+
20+
This opts out of the default behavior of collecting a narrow set of API
21+
parameters as span tags.
22+
23+
To not collect any API parameters, ``ddtrace.config.boto.tag_no_params =
24+
True`` or by setting the environment variable ``DD_AWS_TAG_NO_PARAMS=true``.
25+
26+
27+
Default: ``False``
28+
29+
.. py:data:: ddtrace.config.boto['tag_all_params']
30+
31+
**Deprecated**: This retains the deprecated behavior of adding span tags for
32+
all API parameters that are not explicitly excluded by the integration.
33+
These deprecated span tags will be added along with the API parameters
34+
enabled by default.
35+
36+
This configuration is ignored if ``tag_no_parms`` (``DD_AWS_TAG_NO_PARAMS``)
37+
is set to ``True``.
38+
39+
To collect all API parameters, ``ddtrace.config.botocore.tag_all_params =
40+
True`` or by setting the environment variable ``DD_AWS_TAG_ALL_PARAMS=true``.
41+
42+
43+
Default: ``False``
44+
1545
"""
1646

1747
from ...internal.utils.importlib import require_modules

ddtrace/contrib/boto/patch.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import inspect
2+
import os
23

34
import boto.connection
45

@@ -10,9 +11,11 @@
1011
from ddtrace.ext import http
1112
from ddtrace.internal.utils.wrappers import unwrap
1213
from ddtrace.pin import Pin
14+
from ddtrace.vendor import debtcollector
1315
from ddtrace.vendor import wrapt
1416

1517
from ...internal.utils import get_argument_value
18+
from ...internal.utils.formats import asbool
1619

1720

1821
# Original boto client class
@@ -32,6 +35,22 @@
3235
AWS_AUTH_TRACED_ARGS = {"path", "data", "host"}
3336

3437

38+
if os.getenv("DD_AWS_TAG_ALL_PARAMS") is not None:
39+
debtcollector.deprecate(
40+
"Using environment variable 'DD_AWS_TAG_ALL_PARAMS' is deprecated",
41+
message="The boto integration no longer includes all API parameters by default.",
42+
removal_version="2.0.0",
43+
)
44+
45+
config._add(
46+
"boto",
47+
{
48+
"tag_no_params": asbool(os.getenv("DD_AWS_TAG_NO_PARAMS", default=False)),
49+
"tag_all_params": asbool(os.getenv("DD_AWS_TAG_ALL_PARAMS", default=False)),
50+
},
51+
)
52+
53+
3554
def patch():
3655
if getattr(boto.connection, "_datadog_patch", False):
3756
return
@@ -72,11 +91,17 @@ def patched_query_request(original_func, instance, args, kwargs):
7291
operation_name = None
7392
if args:
7493
operation_name = get_argument_value(args, kwargs, 0, "action")
94+
params = get_argument_value(args, kwargs, 1, "params")
95+
7596
span.resource = "%s.%s" % (endpoint_name, operation_name.lower())
97+
98+
if params and not config.boto["tag_no_params"]:
99+
aws._add_api_param_span_tags(span, endpoint_name, params)
76100
else:
77101
span.resource = endpoint_name
78102

79-
aws.add_span_arg_tags(span, endpoint_name, args, AWS_QUERY_ARGS_NAME, AWS_QUERY_TRACED_ARGS)
103+
if not config.boto["tag_no_params"] and config.boto["tag_all_params"]:
104+
aws.add_span_arg_tags(span, endpoint_name, args, AWS_QUERY_ARGS_NAME, AWS_QUERY_TRACED_ARGS)
80105

81106
# Obtaining region name
82107
region_name = _get_instance_region_name(instance)
@@ -140,7 +165,8 @@ def patched_auth_request(original_func, instance, args, kwargs):
140165
else:
141166
span.resource = endpoint_name
142167

143-
aws.add_span_arg_tags(span, endpoint_name, args, AWS_AUTH_ARGS_NAME, AWS_AUTH_TRACED_ARGS)
168+
if not config.boto["tag_no_params"] and config.boto["tag_all_params"]:
169+
aws.add_span_arg_tags(span, endpoint_name, args, AWS_AUTH_ARGS_NAME, AWS_AUTH_TRACED_ARGS)
144170

145171
# Obtaining region name
146172
region_name = _get_instance_region_name(instance)

ddtrace/contrib/botocore/__init__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,32 @@
5252
5353
See :ref:`HTTP - Custom Error Codes<http-custom-error>` documentation for more examples.
5454
55+
.. py:data:: ddtrace.config.botocore['tag_no_params']
56+
57+
This opts out of the default behavior of collecting a narrow set of API parameters as span tags.
58+
59+
To not collect any API parameters, ``ddtrace.config.botocore.tag_no_params = True`` or by setting the environment
60+
variable ``DD_AWS_TAG_NO_PARAMS=true``.
61+
62+
63+
Default: ``False``
64+
65+
.. py:data:: ddtrace.config.botocore['tag_all_params']
66+
67+
**Deprecated**: This retains the deprecated behavior of adding span tags for
68+
all API parameters that are not explicitly excluded by the integration.
69+
These deprecated span tags will be added along with the API parameters
70+
enabled by default.
71+
72+
This configuration is ignored if ``tag_no_parms`` (``DD_AWS_TAG_NO_PARAMS``)
73+
is set to ``True``.
74+
75+
To collect all API parameters, ``ddtrace.config.botocore.tag_all_params =
76+
True`` or by setting the environment variable ``DD_AWS_TAG_ALL_PARAMS=true``.
77+
78+
79+
Default: ``False``
80+
5581
5682
Example::
5783

ddtrace/contrib/botocore/patch.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from ddtrace import config
1818
from ddtrace.settings.config import Config
19+
from ddtrace.vendor import debtcollector
1920
from ddtrace.vendor import wrapt
2021

2122
from ...constants import ANALYTICS_SAMPLE_RATE_KEY
@@ -47,13 +48,23 @@
4748
log = get_logger(__name__)
4849

4950

51+
if os.getenv("DD_AWS_TAG_ALL_PARAMS") is not None:
52+
debtcollector.deprecate(
53+
"Using environment variable 'DD_AWS_TAG_ALL_PARAMS' is deprecated",
54+
message="The botocore integration no longer includes all API parameters by default.",
55+
removal_version="2.0.0",
56+
)
57+
58+
5059
# Botocore default settings
5160
config._add(
5261
"botocore",
5362
{
5463
"distributed_tracing": asbool(os.getenv("DD_BOTOCORE_DISTRIBUTED_TRACING", default=True)),
5564
"invoke_with_legacy_context": asbool(os.getenv("DD_BOTOCORE_INVOKE_WITH_LEGACY_CONTEXT", default=False)),
5665
"operations": collections.defaultdict(Config._HTTPServerConfig),
66+
"tag_no_params": asbool(os.getenv("DD_AWS_TAG_NO_PARAMS", default=False)),
67+
"tag_all_params": asbool(os.getenv("DD_AWS_TAG_ALL_PARAMS", default=False)),
5768
},
5869
)
5970

@@ -325,10 +336,14 @@ def patched_api_call(original_func, instance, args, kwargs):
325336
except Exception:
326337
log.warning("Unable to inject trace context", exc_info=True)
327338

339+
if params and not config.botocore["tag_no_params"]:
340+
aws._add_api_param_span_tags(span, endpoint_name, params)
341+
328342
else:
329343
span.resource = endpoint_name
330344

331-
aws.add_span_arg_tags(span, endpoint_name, args, ARGS_NAME, TRACED_ARGS)
345+
if not config.botocore["tag_no_params"] and config.botocore["tag_all_params"]:
346+
aws.add_span_arg_tags(span, endpoint_name, args, ARGS_NAME, TRACED_ARGS)
332347

333348
region_name = deep_getattr(instance, "meta.region_name")
334349

ddtrace/ext/aws.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from typing import Any
2+
from typing import Dict
23
from typing import FrozenSet
34
from typing import Set
45
from typing import TYPE_CHECKING
@@ -47,6 +48,38 @@ def add_span_arg_tags(
4748
)
4849

4950

51+
def _add_api_param_span_tags(span, endpoint_name, params):
52+
# type: (Span, str, Dict[str, Any]) -> None
53+
if endpoint_name == "cloudwatch":
54+
log_group_name = params.get("logGroupName")
55+
if log_group_name:
56+
span.set_tag_str("aws.cloudwatch.logs.log_group_name", log_group_name)
57+
elif endpoint_name == "dynamodb":
58+
table_name = params.get("TableName")
59+
if table_name:
60+
span.set_tag_str("aws.dynamodb.table_name", table_name)
61+
elif endpoint_name == "kinesis":
62+
stream_name = params.get("StreamName")
63+
if stream_name:
64+
span.set_tag_str("aws.kinesis.stream_name", stream_name)
65+
elif endpoint_name == "redshift":
66+
cluster_identifier = params.get("ClusterIdentifier")
67+
if cluster_identifier:
68+
span.set_tag_str("aws.redshift.cluster_identifier", cluster_identifier)
69+
elif endpoint_name == "s3":
70+
bucket_name = params.get("Bucket")
71+
if bucket_name:
72+
span.set_tag_str("aws.s3.bucket_name", bucket_name)
73+
elif endpoint_name == "sns":
74+
topic_arn = params.get("TopicArn")
75+
if topic_arn:
76+
span.set_tag_str("aws.sns.topic_arn", topic_arn)
77+
elif endpoint_name == "sqs":
78+
queue_name = params.get("QueueName") or params.get("QueueUrl")
79+
if queue_name:
80+
span.set_tag_str("aws.sqs.queue_name", queue_name)
81+
82+
5083
REGION = "aws.region"
5184
AGENT = "aws.agent"
5285
OPERATION = "aws.operation"

docs/spelling_wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ asyncpg
3232
attrs
3333
autodetected
3434
autopatching
35+
aws
3536
backend
3637
backends
3738
backport
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
deprecations:
3+
- |
4+
aws: The boto, botocore and aiobotocore integrations no longer include all API parameters by default. To retain the deprecated behavior, set the environment variable ``DD_AWS_TAG_ALL_PARAMS=1``. The deprecated behavior and environment variable will be removed in v2.0.0.
5+
fixes:
6+
- |
7+
aws: We are reducing the number of API parameters that the boto, botocore and aiobotocore integrations collect as span tags by default. This change limits span tags to a narrow set of parameters for specific AWS APIs using standard tag names. To opt out of the new default behavior and collect no API parameters, set the environment variable ``DD_AWS_TAG_NO_PARAMS=1``. To retain the deprecated behavior and collect all API parameters, set the environment variable ``DD_AWS_TAG_ALL_PARAMS=1``.

0 commit comments

Comments
 (0)