Skip to content

Commit 1479771

Browse files
authored
Merge branch 'main' into httpx-0.23
2 parents 14b6d42 + 46e4b1d commit 1479771

File tree

21 files changed

+482
-58
lines changed

21 files changed

+482
-58
lines changed

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
- `opentelemetry-instrumentation-system-metrics` Add `process.` prefix to `runtime.memory`, `runtime.cpu.time`, and `runtime.gc_count`. Change `runtime.memory` from count to UpDownCounter. ([#1735](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1735))
1111
- Instrument all httpx versions >= 0.18. ([#1748](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1748))
12+
- Add request and response hooks for GRPC instrumentation (client only)
13+
([#1706](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1706))
14+
- `opentelemetry-instrumentation-pymemcache` Update instrumentation to support pymemcache >4
15+
([#1764](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1764))
1216

1317
### Added
1418

1519
- Add `excluded_urls` functionality to `urllib` and `urllib3` instrumentations
1620
([#1733](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1733))
1721
- Make Django request span attributes available for `start_span`.
1822
([#1730](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1730))
23+
- Make ASGI request span attributes available for `start_span`.
24+
([#1762](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1762))
25+
- `opentelemetry-instrumentation-celery` Add support for anonymous tasks.
26+
([#1407](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1407)
27+
1928

2029
### Fixed
2130

31+
- Fix elasticsearch db.statement attribute to be sanitized by default
32+
([#1758](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1758))
2233
- Fix `AttributeError` when AWS Lambda handler receives a list event
2334
([#1738](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1738))
24-
35+
- Fix `None does not implement middleware` error when there are no middlewares registered
36+
([#1766](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1766))
2537

2638
## Version 1.17.0/0.38b0 (2023-03-22)
2739

instrumentation/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
| [opentelemetry-instrumentation-mysql](./opentelemetry-instrumentation-mysql) | mysql-connector-python ~= 8.0 | No
2727
| [opentelemetry-instrumentation-pika](./opentelemetry-instrumentation-pika) | pika >= 0.12.0 | No
2828
| [opentelemetry-instrumentation-psycopg2](./opentelemetry-instrumentation-psycopg2) | psycopg2 >= 2.7.3.1 | No
29-
| [opentelemetry-instrumentation-pymemcache](./opentelemetry-instrumentation-pymemcache) | pymemcache >= 1.3.5, < 4 | No
29+
| [opentelemetry-instrumentation-pymemcache](./opentelemetry-instrumentation-pymemcache) | pymemcache >= 1.3.5, < 5 | No
3030
| [opentelemetry-instrumentation-pymongo](./opentelemetry-instrumentation-pymongo) | pymongo >= 3.1, < 5.0 | No
3131
| [opentelemetry-instrumentation-pymysql](./opentelemetry-instrumentation-pymysql) | PyMySQL < 2 | No
3232
| [opentelemetry-instrumentation-pyramid](./opentelemetry-instrumentation-pyramid) | pyramid >= 1.7 | Yes

instrumentation/opentelemetry-instrumentation-aiohttp-client/tests/test_aiohttp_client_integration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def test_status_codes(self):
122122
(span_status, None),
123123
{
124124
SpanAttributes.HTTP_METHOD: "GET",
125-
SpanAttributes.HTTP_URL: f"http://{host}:{port}/test-path?query=param#foobar",
125+
SpanAttributes.HTTP_URL: f"http://{host}:{port}/test-path#foobar",
126126
SpanAttributes.HTTP_STATUS_CODE: int(
127127
status_code
128128
),

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -531,15 +531,16 @@ async def __call__(self, scope, receive, send):
531531

532532
span_name, additional_attributes = self.default_span_details(scope)
533533

534+
attributes = collect_request_attributes(scope)
535+
attributes.update(additional_attributes)
534536
span, token = _start_internal_or_server_span(
535537
tracer=self.tracer,
536538
span_name=span_name,
537539
start_time=None,
538540
context_carrier=scope,
539541
context_getter=asgi_getter,
542+
attributes=attributes,
540543
)
541-
attributes = collect_request_attributes(scope)
542-
attributes.update(additional_attributes)
543544
active_requests_count_attrs = _parse_active_request_count_attrs(
544545
attributes
545546
)

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,17 @@ def _trace_before_publish(self, *args, **kwargs):
183183
task = utils.retrieve_task_from_sender(kwargs)
184184
task_id = utils.retrieve_task_id_from_message(kwargs)
185185

186-
if task is None or task_id is None:
186+
if task_id is None:
187187
return
188188

189-
operation_name = f"{_TASK_APPLY_ASYNC}/{task.name}"
189+
if task is None:
190+
# task is an anonymous task send using send_task or using canvas workflow
191+
# Signatures() to send to a task not in the current processes dependency
192+
# tree
193+
task_name = kwargs.get("sender", "unknown")
194+
else:
195+
task_name = task.name
196+
operation_name = f"{_TASK_APPLY_ASYNC}/{task_name}"
190197
span = self._tracer.start_span(
191198
operation_name, kind=trace.SpanKind.PRODUCER
192199
)
@@ -195,7 +202,7 @@ def _trace_before_publish(self, *args, **kwargs):
195202
if span.is_recording():
196203
span.set_attribute(_TASK_TAG_KEY, _TASK_APPLY_ASYNC)
197204
span.set_attribute(SpanAttributes.MESSAGING_MESSAGE_ID, task_id)
198-
span.set_attribute(_TASK_NAME_KEY, task.name)
205+
span.set_attribute(_TASK_NAME_KEY, task_name)
199206
utils.set_attributes_from_context(span, kwargs)
200207

201208
activation = trace.use_span(span, end_on_exit=True)

instrumentation/opentelemetry-instrumentation-celery/src/opentelemetry/instrumentation/celery/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ def attach_span(task, task_id, span, is_publish=False):
132132
NOTE: We cannot test for this well yet, because we do not run a celery worker,
133133
and cannot run `task.apply_async()`
134134
"""
135+
if task is None:
136+
return
135137
span_dict = getattr(task, CTX_KEY, None)
136138
if span_dict is None:
137139
span_dict = {}

instrumentation/opentelemetry-instrumentation-celery/tests/test_tasks.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def tearDown(self):
3636
CeleryInstrumentor().uninstrument()
3737
self._worker.stop()
3838
self._thread.join()
39+
CeleryInstrumentor().uninstrument()
3940

4041
def test_task(self):
4142
CeleryInstrumentor().instrument()
@@ -97,3 +98,52 @@ def test_uninstrument(self):
9798

9899
spans = self.memory_exporter.get_finished_spans()
99100
self.assertEqual(len(spans), 0)
101+
102+
103+
class TestCelerySignatureTask(TestBase):
104+
def setUp(self):
105+
super().setUp()
106+
107+
def start_app(*args, **kwargs):
108+
# Add an additional task that will not be registered with parent thread
109+
@app.task
110+
def hidden_task(num_a):
111+
return num_a * 2
112+
113+
self._worker = app.Worker(app=app, pool="solo", concurrency=1)
114+
return self._worker.start(*args, **kwargs)
115+
116+
self._thread = threading.Thread(target=start_app)
117+
self._worker = app.Worker(app=app, pool="solo", concurrency=1)
118+
self._thread.daemon = True
119+
self._thread.start()
120+
121+
def tearDown(self):
122+
super().tearDown()
123+
self._worker.stop()
124+
self._thread.join()
125+
CeleryInstrumentor().uninstrument()
126+
127+
def test_hidden_task(self):
128+
# no-op since already instrumented
129+
CeleryInstrumentor().instrument()
130+
131+
res = app.signature("tests.test_tasks.hidden_task", (2,)).apply_async()
132+
while not res.ready():
133+
time.sleep(0.05)
134+
spans = self.sorted_spans(self.memory_exporter.get_finished_spans())
135+
self.assertEqual(len(spans), 2)
136+
137+
consumer, producer = spans
138+
139+
self.assertEqual(consumer.name, "run/tests.test_tasks.hidden_task")
140+
self.assertEqual(consumer.kind, SpanKind.CONSUMER)
141+
142+
self.assertEqual(
143+
producer.name, "apply_async/tests.test_tasks.hidden_task"
144+
)
145+
self.assertEqual(producer.kind, SpanKind.PRODUCER)
146+
147+
self.assertNotEqual(consumer.parent, producer.context)
148+
self.assertEqual(consumer.parent.span_id, producer.context.span_id)
149+
self.assertEqual(consumer.context.trace_id, producer.context.trace_id)

instrumentation/opentelemetry-instrumentation-celery/tests/test_utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ def fn_task():
185185
utils.detach_span(fn_task, task_id)
186186
self.assertEqual(utils.retrieve_span(fn_task, task_id), (None, None))
187187

188+
def test_optional_task_span_attach(self):
189+
task_id = "7c6731af-9533-40c3-83a9-25b58f0d837f"
190+
span = trace._Span("name", mock.Mock(spec=trace_api.SpanContext))
191+
192+
# assert this is is a no-aop
193+
self.assertIsNone(utils.attach_span(None, task_id, span))
194+
188195
def test_span_delete_empty(self):
189196
# ensure detach_span doesn't raise an exception if span is not present
190197
@self.app.task

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

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
4545
The instrument() method accepts the following keyword args:
4646
tracer_provider (TracerProvider) - an optional tracer provider
47-
sanitize_query (bool) - an optional query sanitization flag
4847
request_hook (Callable) - a function with extra user-defined logic to be performed before performing the request
4948
this function signature is:
5049
def request_hook(span: Span, method: str, url: str, kwargs)
@@ -138,13 +137,11 @@ def _instrument(self, **kwargs):
138137
tracer = get_tracer(__name__, __version__, tracer_provider)
139138
request_hook = kwargs.get("request_hook")
140139
response_hook = kwargs.get("response_hook")
141-
sanitize_query = kwargs.get("sanitize_query", False)
142140
_wrap(
143141
elasticsearch,
144142
"Transport.perform_request",
145143
_wrap_perform_request(
146144
tracer,
147-
sanitize_query,
148145
self._span_name_prefix,
149146
request_hook,
150147
response_hook,
@@ -163,7 +160,6 @@ def _uninstrument(self, **kwargs):
163160

164161
def _wrap_perform_request(
165162
tracer,
166-
sanitize_query,
167163
span_name_prefix,
168164
request_hook=None,
169165
response_hook=None,
@@ -225,10 +221,9 @@ def wrapper(wrapped, _, args, kwargs):
225221
if method:
226222
attributes["elasticsearch.method"] = method
227223
if body:
228-
statement = str(body)
229-
if sanitize_query:
230-
statement = sanitize_body(body)
231-
attributes[SpanAttributes.DB_STATEMENT] = statement
224+
attributes[SpanAttributes.DB_STATEMENT] = sanitize_body(
225+
body
226+
)
232227
if params:
233228
attributes["elasticsearch.params"] = str(params)
234229
if doc_id:

instrumentation/opentelemetry-instrumentation-elasticsearch/src/opentelemetry/instrumentation/elasticsearch/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def _flatten_dict(d, parent_key=""):
2929
items = []
3030
for k, v in d.items():
3131
new_key = parent_key + "." + k if parent_key else k
32-
if isinstance(v, dict):
32+
# recursive call _flatten_dict for a non-empty dict value
33+
if isinstance(v, dict) and v:
3334
items.extend(_flatten_dict(v, new_key).items())
3435
else:
3536
items.append((new_key, v))

0 commit comments

Comments
 (0)