Skip to content

Commit 8462981

Browse files
authored
Merge branch 'main' into redis-query-sanitization
2 parents af4957e + 43d0c6c commit 8462981

File tree

12 files changed

+573
-7
lines changed

12 files changed

+573
-7
lines changed

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- `opentelemetry-instrumentation-redis` Add `sanitize_query` config option to allow query sanitization. Enabled by default.
1313
([#1572](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1572))
14+
- `opentelemetry/sdk/extension/aws` Implement [`aws.ecs.*`](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/cloud_provider/aws/ecs.md) and [`aws.logs.*`](https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/cloud_provider/aws/logs/) resource attributes in the `AwsEcsResourceDetector` detector when the ECS Metadata v4 is available
15+
([#1212](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1212))
1416

15-
## Fixed
17+
### Fixed
1618

1719
- Fix aiopg instrumentation to work with aiopg < 2.0.0
1820
([#1473](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1473))
1921
- `opentelemetry-instrumentation-aws-lambda` Adds an option to configure `disable_aws_context_propagation` by
2022
environment variable: `OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION`
2123
([#1507](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1507))
22-
24+
- Fix pymongo to collect the property DB_MONGODB_COLLECTION
25+
([#1555](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1555))
2326

2427
## Version 1.15.0/0.36b0 (2022-12-10)
2528

instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ def started(self, event: monitoring.CommandStartedEvent):
126126
statement = event.command_name
127127
if command:
128128
statement += " " + str(command)
129+
collection = event.command.get(event.command_name)
129130

130131
try:
131132
span = self._tracer.start_span(name, kind=SpanKind.CLIENT)
@@ -135,6 +136,10 @@ def started(self, event: monitoring.CommandStartedEvent):
135136
)
136137
span.set_attribute(SpanAttributes.DB_NAME, event.database_name)
137138
span.set_attribute(SpanAttributes.DB_STATEMENT, statement)
139+
if collection:
140+
span.set_attribute(
141+
SpanAttributes.DB_MONGODB_COLLECTION, collection
142+
)
138143
if event.connection_id is not None:
139144
span.set_attribute(
140145
SpanAttributes.NET_PEER_NAME, event.connection_id[0]

instrumentation/opentelemetry-instrumentation-redis/tests/test_redis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def test_query_sanitizer_disabled(self):
184184

185185
def test_no_op_tracer_provider(self):
186186
RedisInstrumentor().uninstrument()
187-
tracer_provider = trace.NoOpTracerProvider
187+
tracer_provider = trace.NoOpTracerProvider()
188188
RedisInstrumentor().instrument(tracer_provider=tracer_provider)
189189

190190
redis_client = redis.Redis()

instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def test_no_op_tracer_provider(self):
258258
engine = create_engine("sqlite:///:memory:")
259259
SQLAlchemyInstrumentor().instrument(
260260
engine=engine,
261-
tracer_provider=trace.NoOpTracerProvider,
261+
tracer_provider=trace.NoOpTracerProvider(),
262262
)
263263
cnx = engine.connect()
264264
cnx.execute("SELECT 1 + 1;").fetchall()

instrumentation/opentelemetry-instrumentation-urllib/tests/test_urllib_integration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ def response_hook(span, request_obj, response):
351351

352352
def test_no_op_tracer_provider(self):
353353
URLLibInstrumentor().uninstrument()
354-
tracer_provider = trace.NoOpTracerProvider
354+
tracer_provider = trace.NoOpTracerProvider()
355355
URLLibInstrumentor().instrument(tracer_provider=tracer_provider)
356356

357357
result = self.perform_request(self.URL)

sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/resource/ecs.py

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import json
1516
import logging
1617
import os
18+
import re
1719
import socket
20+
from urllib.request import Request, urlopen
1821

1922
from opentelemetry.sdk.resources import Resource, ResourceDetector
2023
from opentelemetry.semconv.resource import (
@@ -58,18 +61,127 @@ def detect(self) -> "Resource":
5861
"Failed to get container ID on ECS: %s.", exception
5962
)
6063

61-
return Resource(
64+
base_resource = Resource(
6265
{
6366
ResourceAttributes.CLOUD_PROVIDER: CloudProviderValues.AWS.value,
6467
ResourceAttributes.CLOUD_PLATFORM: CloudPlatformValues.AWS_ECS.value,
6568
ResourceAttributes.CONTAINER_NAME: socket.gethostname(),
6669
ResourceAttributes.CONTAINER_ID: container_id,
6770
}
6871
)
72+
73+
metadata_v4_endpoint = os.environ.get(
74+
"ECS_CONTAINER_METADATA_URI_V4"
75+
)
76+
77+
if not metadata_v4_endpoint:
78+
return base_resource
79+
80+
# Returns https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v4.html#task-metadata-endpoint-v4-response
81+
metadata_container = json.loads(_http_get(metadata_v4_endpoint))
82+
metadata_task = json.loads(
83+
_http_get(f"{metadata_v4_endpoint}/task")
84+
)
85+
86+
task_arn = metadata_task["TaskARN"]
87+
base_arn = task_arn[0 : task_arn.rindex(":")] # noqa
88+
cluster: str = metadata_task["Cluster"]
89+
cluster_arn = (
90+
cluster
91+
if cluster.startswith("arn:")
92+
else f"{base_arn}:cluster/{cluster}"
93+
)
94+
95+
logs_resource = _get_logs_resource(metadata_container)
96+
97+
return base_resource.merge(logs_resource).merge(
98+
Resource(
99+
{
100+
ResourceAttributes.AWS_ECS_CONTAINER_ARN: metadata_container[
101+
"ContainerARN"
102+
],
103+
ResourceAttributes.AWS_ECS_CLUSTER_ARN: cluster_arn,
104+
ResourceAttributes.AWS_ECS_LAUNCHTYPE: metadata_task[
105+
"LaunchType"
106+
].lower(),
107+
ResourceAttributes.AWS_ECS_TASK_ARN: task_arn,
108+
ResourceAttributes.AWS_ECS_TASK_FAMILY: metadata_task[
109+
"Family"
110+
],
111+
ResourceAttributes.AWS_ECS_TASK_REVISION: metadata_task[
112+
"Revision"
113+
],
114+
}
115+
)
116+
)
69117
# pylint: disable=broad-except
70118
except Exception as exception:
71119
if self.raise_on_error:
72120
raise exception
73121

74122
logger.warning("%s failed: %s", self.__class__.__name__, exception)
75123
return Resource.get_empty()
124+
125+
126+
def _get_logs_resource(metadata_container):
127+
if metadata_container.get("LogDriver") == "awslogs":
128+
log_options = metadata_container.get("LogOptions")
129+
if log_options:
130+
logs_region = log_options.get("awslogs-region")
131+
logs_group_name = log_options.get("awslogs-group")
132+
logs_stream_name = log_options.get("awslogs-stream")
133+
134+
container_arn = metadata_container["ContainerARN"]
135+
136+
if not logs_region:
137+
aws_region_match = re.match(
138+
r"arn:aws:ecs:([^:]+):.*", container_arn
139+
)
140+
if aws_region_match:
141+
logs_region = aws_region_match.group(1)
142+
143+
else:
144+
logger.warning("Cannot parse AWS region out of ECS ARN")
145+
146+
# We need to retrieve the account ID from some other ARN to create the
147+
# log-group and log-stream ARNs
148+
aws_account = None
149+
aws_account_match = re.match(
150+
r"arn:aws:ecs:[^:]+:([^:]+):.*", container_arn
151+
)
152+
if aws_account_match:
153+
aws_account = aws_account_match.group(1)
154+
155+
logs_group_arn = None
156+
logs_stream_arn = None
157+
if logs_region and aws_account:
158+
if logs_group_name:
159+
logs_group_arn = f"arn:aws:logs:{logs_region}:{aws_account}:log-group:{logs_group_name}"
160+
161+
if logs_stream_name:
162+
logs_stream_arn = f"arn:aws:logs:{logs_region}:{aws_account}:log-group:{logs_group_name}:log-stream:{logs_stream_name}"
163+
164+
return Resource(
165+
{
166+
ResourceAttributes.AWS_LOG_GROUP_NAMES: [logs_group_name],
167+
ResourceAttributes.AWS_LOG_GROUP_ARNS: [logs_group_arn],
168+
ResourceAttributes.AWS_LOG_STREAM_NAMES: [
169+
logs_stream_name
170+
],
171+
ResourceAttributes.AWS_LOG_STREAM_ARNS: [logs_stream_arn],
172+
}
173+
)
174+
175+
logger.warning(
176+
"The metadata endpoint v4 has returned 'awslogs' as 'LogDriver', but there is no 'LogOptions' data"
177+
)
178+
179+
return Resource.get_empty()
180+
181+
182+
def _http_get(url):
183+
with urlopen(
184+
Request(url, method="GET"),
185+
timeout=5,
186+
) as response:
187+
return response.read().decode("utf-8")
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"DockerId": "ea32192c8553fbff06c9340478a2ff089b2bb5646fb718b4ee206641c9086d66",
3+
"Name": "curl",
4+
"DockerName": "ecs-curltest-24-curl-cca48e8dcadd97805600",
5+
"Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest",
6+
"ImageID": "sha256:d691691e9652791a60114e67b365688d20d19940dde7c4736ea30e660d8d3553",
7+
"Labels": {
8+
"com.amazonaws.ecs.cluster": "default",
9+
"com.amazonaws.ecs.container-name": "curl",
10+
"com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/8f03e41243824aea923aca126495f665",
11+
"com.amazonaws.ecs.task-definition-family": "curltest",
12+
"com.amazonaws.ecs.task-definition-version": "24"
13+
},
14+
"DesiredStatus": "RUNNING",
15+
"KnownStatus": "RUNNING",
16+
"Limits": {
17+
"CPU": 10,
18+
"Memory": 128
19+
},
20+
"CreatedAt": "2020-10-02T00:15:07.620912337Z",
21+
"StartedAt": "2020-10-02T00:15:08.062559351Z",
22+
"Type": "NORMAL",
23+
"LogDriver": "awslogs",
24+
"LogOptions": {
25+
"awslogs-create-group": "true",
26+
"awslogs-group": "/ecs/metadata",
27+
"awslogs-region": "us-west-2",
28+
"awslogs-stream": "ecs/curl/8f03e41243824aea923aca126495f665"
29+
},
30+
"ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9",
31+
"Networks": [
32+
{
33+
"NetworkMode": "awsvpc",
34+
"IPv4Addresses": [
35+
"10.0.2.100"
36+
],
37+
"AttachmentIndex": 0,
38+
"MACAddress": "0e:9e:32:c7:48:85",
39+
"IPv4SubnetCIDRBlock": "10.0.2.0/24",
40+
"PrivateDNSName": "ip-10-0-2-100.us-west-2.compute.internal",
41+
"SubnetGatewayIpv4Address": "10.0.2.1/24"
42+
}
43+
]
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"DockerId": "cd189a933e5849daa93386466019ab50-2495160603",
3+
"Name": "curl",
4+
"DockerName": "curl",
5+
"Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest",
6+
"ImageID": "sha256:25f3695bedfb454a50f12d127839a68ad3caf91e451c1da073db34c542c4d2cb",
7+
"Labels": {
8+
"com.amazonaws.ecs.cluster": "arn:aws:ecs:us-west-2:111122223333:cluster/default",
9+
"com.amazonaws.ecs.container-name": "curl",
10+
"com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/cd189a933e5849daa93386466019ab50",
11+
"com.amazonaws.ecs.task-definition-family": "curltest",
12+
"com.amazonaws.ecs.task-definition-version": "2"
13+
},
14+
"DesiredStatus": "RUNNING",
15+
"KnownStatus": "RUNNING",
16+
"Limits": {
17+
"CPU": 10,
18+
"Memory": 128
19+
},
20+
"CreatedAt": "2020-10-08T20:09:11.44527186Z",
21+
"StartedAt": "2020-10-08T20:09:11.44527186Z",
22+
"Type": "NORMAL",
23+
"Networks": [
24+
{
25+
"NetworkMode": "awsvpc",
26+
"IPv4Addresses": [
27+
"192.0.2.3"
28+
],
29+
"AttachmentIndex": 0,
30+
"MACAddress": "0a:de:f6:10:51:e5",
31+
"IPv4SubnetCIDRBlock": "192.0.2.0/24",
32+
"DomainNameServers": [
33+
"192.0.2.2"
34+
],
35+
"DomainNameSearchList": [
36+
"us-west-2.compute.internal"
37+
],
38+
"PrivateDNSName": "ip-10-0-0-222.us-west-2.compute.internal",
39+
"SubnetGatewayIpv4Address": "192.0.2.0/24"
40+
}
41+
],
42+
"ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/05966557-f16c-49cb-9352-24b3a0dcd0e1",
43+
"LogOptions": {
44+
"awslogs-create-group": "true",
45+
"awslogs-group": "/ecs/containerlogs",
46+
"awslogs-region": "us-west-2",
47+
"awslogs-stream": "ecs/curl/cd189a933e5849daa93386466019ab50"
48+
},
49+
"LogDriver": "awslogs"
50+
}

0 commit comments

Comments
 (0)