Skip to content

Commit 41c974d

Browse files
authored
Merge branch 'main' into fix-aiohttp-readmes
2 parents af49c1c + 31b2e4a commit 41c974d

File tree

17 files changed

+537
-308
lines changed

17 files changed

+537
-308
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515

1616
- `opentelemetry-instrumentation-aiohttp-client`: add support for url exclusions via `OTEL_PYTHON_EXCLUDED_URLS` / `OTEL_PYTHON_AIOHTTP_CLIENT_EXCLUDED_URLS`
1717
([#3850](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3850))
18+
- `opentelemetry-instrumentation-httpx`: add support for url exclusions via `OTEL_PYTHON_EXCLUDED_URLS` / `OTEL_PYTHON_HTTPX_EXCLUDED_URLS`
19+
([#3837](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3837))
20+
- `opentelemetry-instrumentation-flask`: improve readthedocs for sqlcommenter configuration.
21+
([#3883](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3883))
22+
- `opentelemetry-instrumentation-sqlalchemy`: improve readthedocs for sqlcommenter configuration.
23+
([#3886](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3886))
24+
- `opentelemetry-instrumentation-mysql`, `opentelemetry-instrumentation-mysqlclient`, `opentelemetry-instrumentation-pymysql`: improve readthedocs for sqlcommenter configuration.
25+
([#3885](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3885))
26+
- `opentelemetry-instrumentation-django`: improve readthedocs for sqlcommenter configuration.
27+
([#3884](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3884))
1828

1929
### Fixed
2030

2131
- `opentelemetry-instrumentation-botocore`: Handle dict input in _decode_tool_use for Bedrock streaming
2232
([#3875](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3875))
2333
- `opentelemetry-instrumentation-aiohttp-client`, `opentelemetry-instrumentation-aiohttp-server`: Fix readme links and text
2434
([#3902](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3902))
35+
- `opentelemetry-instrumentation-aws-lambda`: Fix ImportError with slash-delimited handler paths
36+
([#3894](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3894))
37+
- `opentelemetry-exporter-richconsole`: Prevent deadlock when parent span is not part of the batch
38+
([#3900](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3900))
2539

2640
## Version 1.38.0/0.59b0 (2025-10-16)
2741

exporter/opentelemetry-exporter-richconsole/src/opentelemetry/exporter/richconsole/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,17 @@ def spans_to_tree(spans: typing.Sequence[ReadableSpan]) -> Dict[str, Tree]:
173173
trees = {}
174174
parents = {}
175175
spans = list(spans)
176+
span_ids = {s.context.span_id for s in spans}
176177
while spans:
177178
for span in spans:
178-
if not span.parent:
179+
if not span.parent or span.parent.span_id not in span_ids:
179180
trace_id = opentelemetry.trace.format_trace_id(
180181
span.context.trace_id
181182
)
182-
trees[trace_id] = Tree(label=f"Trace {trace_id}")
183-
child = trees[trace_id].add(
183+
tree = trees.setdefault(
184+
trace_id, Tree(label=f"Trace {trace_id}")
185+
)
186+
child = tree.add(
184187
label=Text.from_markup(
185188
f"[blue][{_ns_to_time(span.start_time)}][/blue] [bold]{span.name}[/bold], span {opentelemetry.trace.format_span_id(span.context.span_id)}"
186189
)

exporter/opentelemetry-exporter-richconsole/test-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pluggy==1.5.0
99
py-cpuinfo==9.0.0
1010
Pygments==2.17.2
1111
pytest==7.4.4
12+
pytest-timeout==2.3.1
1213
rich==13.7.1
1314
tomli==2.0.1
1415
typing_extensions==4.12.2

exporter/opentelemetry-exporter-richconsole/tests/test_rich_exporter.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,15 @@ def test_multiple_traces(tracer_provider):
9696
parent_2.name in child.label
9797
for child in trees[traceid_1].children[0].children
9898
)
99+
100+
101+
@pytest.mark.timeout(30)
102+
def test_no_deadlock(tracer_provider):
103+
# non-regression test for https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3254
104+
105+
tracer = tracer_provider.get_tracer(__name__)
106+
with tracer.start_as_current_span("parent"):
107+
with tracer.start_as_current_span("child") as child:
108+
pass
109+
110+
RichConsoleSpanExporter.spans_to_tree((child,))

instrumentation-genai/opentelemetry-instrumentation-google-genai/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
- Minor change to check LRU cache in Completion Hook before acquiring semaphore/thread ([#3907](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3907)).
11+
1012
## Version 0.4b0 (2025-10-16)
1113

1214
- Implement the new semantic convention changes made in https://github.com/open-telemetry/semantic-conventions/pull/2179.

instrumentation-genai/opentelemetry-instrumentation-langchain/examples/manual/README.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
OpenTelemetry Langcahin Instrumentation Example
1+
OpenTelemetry Langchain Instrumentation Example
22
===============================================
33

44
This is an example of how to instrument Langchain when configuring OpenTelemetry SDK and instrumentations manually.
@@ -8,14 +8,14 @@ Traces include details such as the span name and other attributes.
88

99
Note: `.env <.env>`_ file configures additional environment variables:
1010
- :code:`OTEL_LOGS_EXPORTER=otlp` to specify exporter type.
11-
- :code:`OPENAI_API_KEY` open AI key for accessing the OpenAI API.
11+
- :code:`OPENAI_API_KEY` key for accessing the OpenAI API.
1212
- :code:`OTEL_EXPORTER_OTLP_ENDPOINT` to specify the endpoint for exporting traces (default is http://localhost:4317).
1313

1414
Setup
1515
-----
1616

1717
Minimally, update the `.env <.env>`_ file with your :code:`OPENAI_API_KEY`.
18-
An OTLP compatible endpoint should be listening for traces http://localhost:4317.
18+
An OTLP compatible endpoint should be listening for traces at http://localhost:4317.
1919
If not, update :code:`OTEL_EXPORTER_OTLP_ENDPOINT` as well.
2020

2121
Next, set up a virtual environment like this:

instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,8 @@ def _instrument(self, **kwargs):
460460
)
461461
return
462462
# pylint: disable=attribute-defined-outside-init
463+
# Convert slash-delimited paths to dot-delimited for valid Python imports
464+
lambda_handler = lambda_handler.replace("/", ".")
463465
(
464466
self._wrapped_module_name,
465467
self._wrapped_function_name,

instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,53 @@ def test_sqs_event_sets_attributes(self):
727727
MOCK_LAMBDA_CONTEXT_ATTRIBUTES,
728728
)
729729

730+
def test_slash_delimited_handler_path(self):
731+
"""Test that slash-delimited handler paths work correctly.
732+
733+
AWS Lambda accepts both slash-delimited (python/functions/api.handler)
734+
and dot-delimited (python.functions.api.handler) handler paths.
735+
This test ensures the instrumentation handles both formats.
736+
"""
737+
# Test slash-delimited format
738+
slash_env_patch = mock.patch.dict(
739+
"os.environ",
740+
{_HANDLER: "tests/mocks/lambda_function.handler"},
741+
)
742+
slash_env_patch.start()
743+
AwsLambdaInstrumentor().instrument()
744+
745+
mock_execute_lambda()
746+
747+
spans = self.memory_exporter.get_finished_spans()
748+
self.assertEqual(len(spans), 1)
749+
self.assertSpanHasAttributes(
750+
spans[0],
751+
MOCK_LAMBDA_CONTEXT_ATTRIBUTES,
752+
)
753+
754+
slash_env_patch.stop()
755+
AwsLambdaInstrumentor().uninstrument()
756+
self.memory_exporter.clear()
757+
758+
# Test dot-delimited format (should still work)
759+
dot_env_patch = mock.patch.dict(
760+
"os.environ",
761+
{_HANDLER: "tests.mocks.lambda_function.handler"},
762+
)
763+
dot_env_patch.start()
764+
AwsLambdaInstrumentor().instrument()
765+
766+
mock_execute_lambda()
767+
768+
spans = self.memory_exporter.get_finished_spans()
769+
self.assertEqual(len(spans), 1)
770+
self.assertSpanHasAttributes(
771+
spans[0],
772+
MOCK_LAMBDA_CONTEXT_ATTRIBUTES,
773+
)
774+
775+
dot_env_patch.stop()
776+
730777
def test_lambda_handles_handler_exception_with_api_gateway_proxy_event(
731778
self,
732779
):

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

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -170,64 +170,61 @@ def response_hook(span, request, response):
170170
Note:
171171
The environment variable names used to capture HTTP headers are still experimental, and thus are subject to change.
172172
173-
SQLCOMMENTER
174-
*****************************************
175-
You can optionally configure Django instrumentation to enable sqlcommenter which enriches
176-
the query with contextual information.
173+
SQLCommenter
174+
************
175+
You can optionally enable sqlcommenter which enriches the query with contextual
176+
information. Queries made after setting up trace integration with sqlcommenter
177+
enabled will have configurable key-value pairs appended to them, e.g.
178+
``Users().objects.all()`` will result in
179+
``"select * from auth_users; /*traceparent=00-01234567-abcd-01*/"``. This
180+
supports context propagation between database client and server when database log
181+
records are enabled. For more information, see:
182+
183+
* `Semantic Conventions - Database Spans <https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-spans.md#sql-commenter>`_
184+
* `sqlcommenter <https://google.github.io/sqlcommenter/>`_
177185
178186
.. code:: python
179187
180188
from opentelemetry.instrumentation.django import DjangoInstrumentor
181189
182190
DjangoInstrumentor().instrument(is_sql_commentor_enabled=True)
183191
184-
185-
For example,
186-
::
187-
188-
Invoking Users().objects.all() will lead to sql query "select * from auth_users" but when SQLCommenter is enabled
189-
the query will get appended with some configurable tags like "select * from auth_users /*metrics=value*/;"
190-
191-
192-
SQLCommenter Configurations
193-
***************************
194-
We can configure the tags to be appended to the sqlquery log by adding below variables to the settings.py
195-
196-
SQLCOMMENTER_WITH_FRAMEWORK = True(Default) or False
197-
198-
For example,
199-
::
200-
Enabling this flag will add django framework and it's version which is /*framework='django%3A2.2.3*/
201-
202-
SQLCOMMENTER_WITH_CONTROLLER = True(Default) or False
203-
204-
For example,
205-
::
206-
Enabling this flag will add controller name that handles the request /*controller='index'*/
207-
208-
SQLCOMMENTER_WITH_ROUTE = True(Default) or False
209-
210-
For example,
211-
::
212-
Enabling this flag will add url path that handles the request /*route='polls/'*/
213-
214-
SQLCOMMENTER_WITH_APP_NAME = True(Default) or False
215-
216-
For example,
217-
::
218-
Enabling this flag will add app name that handles the request /*app_name='polls'*/
219-
220-
SQLCOMMENTER_WITH_OPENTELEMETRY = True(Default) or False
221-
222-
For example,
223-
::
224-
Enabling this flag will add opentelemetry traceparent /*traceparent='00-fd720cffceba94bbf75940ff3caaf3cc-4fd1a2bdacf56388-01'*/
225-
226-
SQLCOMMENTER_WITH_DB_DRIVER = True(Default) or False
227-
228-
For example,
229-
::
230-
Enabling this flag will add name of the db driver /*db_driver='django.db.backends.postgresql'*/
192+
Warning:
193+
Duplicate sqlcomments may be appended to the sqlquery log if DjangoInstrumentor
194+
sqlcommenter is enabled in addition to sqlcommenter for an active instrumentation
195+
of a database driver or object-relational mapper (ORM) in the same database client
196+
stack. For example, if psycopg2 driver is used and Psycopg2Instrumentor has
197+
sqlcommenter enabled, then both DjangoInstrumentor and Psycopg2Instrumentor will
198+
append comments to the query statement.
199+
200+
SQLCommenter with commenter_options
201+
***********************************
202+
The key-value pairs appended to the query can be configured using
203+
variables in Django ``settings.py``. When sqlcommenter is enabled, all
204+
available KVs/tags are calculated by default, i.e. ``True`` for each. The
205+
``settings.py`` values support *opting out* of specific KVs.
206+
207+
Available settings.py commenter options
208+
#######################################
209+
210+
We can configure the tags to be appended to the sqlquery log by adding below variables to
211+
``settings.py``, e.g. ``SQLCOMMENTER_WITH_FRAMEWORK = False``
212+
213+
+-------------------------------------+-----------------------------------------------------------+---------------------------------------------------------------------------+
214+
| ``settings.py`` variable | Description | Example |
215+
+=====================================+===========================================================+===========================================================================+
216+
| ``SQLCOMMENTER_WITH_FRAMEWORK`` | Django framework name with version (URL encoded). | ``framework='django%%%%3A4.2.0'`` |
217+
+-------------------------------------+-----------------------------------------------------------+---------------------------------------------------------------------------+
218+
| ``SQLCOMMENTER_WITH_CONTROLLER`` | Django controller/view name that handles the request. | ``controller='index'`` |
219+
+-------------------------------------+-----------------------------------------------------------+---------------------------------------------------------------------------+
220+
| ``SQLCOMMENTER_WITH_ROUTE`` | URL path pattern that handles the request. | ``route='polls/'`` |
221+
+-------------------------------------+-----------------------------------------------------------+---------------------------------------------------------------------------+
222+
| ``SQLCOMMENTER_WITH_APP_NAME`` | Django app name that handles the request. | ``app_name='polls'`` |
223+
+-------------------------------------+-----------------------------------------------------------+---------------------------------------------------------------------------+
224+
| ``SQLCOMMENTER_WITH_OPENTELEMETRY`` | OpenTelemetry context as traceparent at time of query. | ``traceparent='00-fd720cffceba94bbf75940ff3caaf3cc-4fd1a2bdacf56388-01'`` |
225+
+-------------------------------------+-----------------------------------------------------------+---------------------------------------------------------------------------+
226+
| ``SQLCOMMENTER_WITH_DB_DRIVER`` | Database driver name used by Django. | ``db_driver='django.db.backends.postgresql'`` |
227+
+-------------------------------------+-----------------------------------------------------------+---------------------------------------------------------------------------+
231228
232229
API
233230
---

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

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -189,54 +189,66 @@ def response_hook(span: Span, status: str, response_headers: List):
189189
Note:
190190
The environment variable names used to capture HTTP headers are still experimental, and thus are subject to change.
191191
192-
SQLCOMMENTER
193-
*****************************************
194-
You can optionally configure Flask instrumentation to enable sqlcommenter which enriches
195-
the query with contextual information.
192+
SQLCommenter
193+
************
194+
You can optionally enable sqlcommenter which enriches the query with contextual
195+
information. Queries made after setting up trace integration with sqlcommenter
196+
enabled will have configurable key-value pairs appended to them, e.g.
197+
``"select * from auth_users; /*framework=flask%%3A2.9.3*/"``. This
198+
supports context propagation between database client and server when database log
199+
records are enabled. For more information, see:
200+
201+
* `Semantic Conventions - Database Spans <https://github.com/open-telemetry/semantic-conventions/blob/main/docs/database/database-spans.md#sql-commenter>`_
202+
* `sqlcommenter <https://google.github.io/sqlcommenter/>`_
196203
197204
.. code:: python
198205
199206
from opentelemetry.instrumentation.flask import FlaskInstrumentor
200207
201-
FlaskInstrumentor().instrument(enable_commenter=True, commenter_options={})
202-
203-
For example, FlaskInstrumentor when used with SQLAlchemyInstrumentor or Psycopg2Instrumentor,
204-
invoking ``cursor.execute("select * from auth_users")`` will lead to sql query
205-
``select * from auth_users`` but when SQLCommenter is enabled the query will get appended with
206-
some configurable tags like:
207-
208-
.. code::
209-
210-
select * from auth_users /*metrics=value*/;"
208+
FlaskInstrumentor().instrument(enable_commenter=True)
211209
212-
Inorder for the commenter to append flask related tags to sql queries, the commenter needs
213-
to enabled on the respective SQLAlchemyInstrumentor or Psycopg2Instrumentor framework too.
214-
215-
SQLCommenter Configurations
216-
***************************
217-
We can configure the tags to be appended to the sqlquery log by adding configuration
218-
inside ``commenter_options={}`` dict.
219-
220-
For example, enabling this flag will add flask and it's version which
221-
is ``/*flask%%3A2.9.3*/`` to the SQL query as a comment (default is True):
210+
Note:
211+
FlaskInstrumentor sqlcommenter requires that sqlcommenter is also
212+
enabled for an active instrumentation of a database driver or object-relational
213+
mapper (ORM) in the same database client stack. The latter, such as
214+
Psycopg2Instrumentor of SQLAlchemyInstrumentor, will create a base sqlcomment
215+
that is enhanced by FlaskInstrumentor with additional values from context
216+
before appending to the query statement.
217+
218+
SQLCommenter with commenter_options
219+
***********************************
220+
The key-value pairs appended to the query can be configured using
221+
``commenter_options``. When sqlcommenter is enabled, all available KVs/tags
222+
are calculated by default. ``commenter_options`` supports *opting out*
223+
of specific KVs.
222224
223225
.. code:: python
224226
225-
framework = True
226-
227-
For example, enabling this flag will add route uri ``/*route='/home'*/``
228-
to the SQL query as a comment (default is True):
229-
230-
.. code:: python
227+
from opentelemetry.instrumentation.flask import FlaskInstrumentor
231228
232-
route = True
229+
# Opts into sqlcomment for Flask trace integration.
230+
# Opts out of tags for controller.
231+
FlaskInstrumentor().instrument(
232+
enable_commenter=True,
233+
commenter_options={
234+
"controller": False,
235+
}
236+
)
233237
234-
For example, enabling this flag will add controller name ``/*controller='home_view'*/``
235-
to the SQL query as a comment (default is True):
238+
Available commenter_options
239+
###########################
236240
237-
.. code:: python
241+
The following sqlcomment key-values can be opted out of through ``commenter_options``:
238242
239-
controller = True
243+
+-------------------+----------------------------------------------------+----------------------------------------+
244+
| Commenter Option | Description | Example |
245+
+===================+====================================================+========================================+
246+
| ``framework`` | Flask framework name with version (URL encoded). | ``framework='flask%%%%3A2.9.3'`` |
247+
+-------------------+----------------------------------------------------+----------------------------------------+
248+
| ``route`` | Flask route URI pattern. | ``route='/home'`` |
249+
+-------------------+----------------------------------------------------+----------------------------------------+
250+
| ``controller`` | Flask controller/endpoint name. | ``controller='home_view'`` |
251+
+-------------------+----------------------------------------------------+----------------------------------------+
240252
241253
API
242254
---

0 commit comments

Comments
 (0)