Skip to content

Commit

Permalink
Merge branch 'main' into kludex/types-wsgi
Browse files Browse the repository at this point in the history
  • Loading branch information
Kludex authored Jan 10, 2025
2 parents 9c8207a + 0ad779a commit 285c01c
Show file tree
Hide file tree
Showing 26 changed files with 1,230 additions and 137 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#3100](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3100))
- Add support to database stability opt-in in `_semconv` utilities and add tests
([#3111](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3111))
- `opentelemetry-instrumentation-system-metrics` Add `py.typed` file to enable PEP 561
([#3132](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3132))
- `opentelemetry-opentelemetry-sqlite3` Add `py.typed` file to enable PEP 561
([#3133](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3133))
- `opentelemetry-instrumentation-falcon` add support version to v4
([#3086](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3086))
- `opentelemetry-instrumentation-wsgi` always record span status code to have it available in metrics
([#3148](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3148))
- add support to Python 3.13
([#3134](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3134))
- `opentelemetry-opentelemetry-wsgi` Add `py.typed` file to enable PEP 561
([#3129](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3129))
- `opentelemetry-util-http` Add `py.typed` file to enable PEP 561
([#3127](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3127))

### Fixed

- `opentelemetry-instrumentation-httpx` Fix `RequestInfo`/`ResponseInfo` type hints
([#3105](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3105))
- `opentelemetry-instrumentation-click` Disable tracing of well-known server click commands
([#3174](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3174))
- `opentelemetry-instrumentation` Fix `get_dist_dependency_conflicts` if no distribution requires
([#3168](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3168))

### Breaking changes

- `opentelemetry-instrumentation-sqlalchemy` including sqlcomment in `db.statement` span attribute value is now opt-in
([#3112](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3112))

### Breaking changes

- `opentelemetry-instrumentation-dbapi` including sqlcomment in `db.statement` span attribute value is now opt-in
([#3115](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3115))


## Version 1.29.0/0.50b0 (2024-12-11)
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The Python auto-instrumentation libraries for [OpenTelemetry](https://openteleme
* [Installation](#installation)
* [Releasing](#releasing)
* [Releasing a package as `1.0` stable](#releasing-a-package-as-10-stable)
* [Semantic Convention status of instrumentations](#semantic-convention-status-of-instrumentations)
* [Contributing](#contributing)
* [Thanks to all the people who already contributed](#thanks-to-all-the-people-who-already-contributed)

Expand Down Expand Up @@ -100,7 +101,7 @@ To release a package as `1.0` stable, the package:

## Semantic Convention status of instrumentations

In our efforts to maintain optimal user experience and prevent breaking changes for transitioning into stable semantic conventions, OpenTelemetry Python is adopting the [semantic convention migration plan](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/migration-guide.md) for several instrumentations. Currently this plan is only being adopted for HTTP-related instrumentations, but will eventually cover all types. Please refer to the `semconv status` column of the [instrumentation README](instrumentation/README.md) of the current status of instrumentations' semantic conventions. The possible values are `experimental`, `stable` and `migration` referring to [status](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.31.0/specification/document-status.md#lifecycle-status) of that particular semantic convention. `Migration` refers to an instrumentation that currently supports the migration plan.
In our efforts to maintain optimal user experience and prevent breaking changes for transitioning into stable semantic conventions, OpenTelemetry Python is adopting the semantic convention migration plan for several instrumentations. Currently this plan is only being adopted for [HTTP-related instrumentations](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/http-migration.md), but will eventually cover all types. Please refer to the `semconv status` column of the [instrumentation README](instrumentation/README.md) of the current status of instrumentations' semantic conventions. The possible values are `experimental`, `stable` and `migration` referring to [status](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.31.0/specification/document-status.md#lifecycle-status) of that particular semantic convention. `Migration` refers to an instrumentation that currently supports the migration plan.

## Contributing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from asyncpg import Connection, Record, cursor
from wrapt import ObjectProxy

from opentelemetry import trace as trace_api
from opentelemetry.instrumentation.asyncpg import AsyncPGInstrumentor
from opentelemetry.test.test_base import TestBase

Expand Down Expand Up @@ -105,3 +106,36 @@ async def exec_mock(*args, **kwargs):
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 2)
self.assertEqual([span.status.is_ok for span in spans], [True, True])

def test_no_op_tracer_provider(self):
AsyncPGInstrumentor().uninstrument()
AsyncPGInstrumentor().instrument(
tracer_provider=trace_api.NoOpTracerProvider()
)

# Mock out all interaction with postgres
async def bind_mock(*args, **kwargs):
return []

async def exec_mock(*args, **kwargs):
return [], None, True

conn = mock.Mock()
conn.is_closed = lambda: False

conn._protocol = mock.Mock()
conn._protocol.bind = bind_mock
conn._protocol.execute = exec_mock
conn._protocol.bind_execute = exec_mock
conn._protocol.close_portal = bind_mock

state = mock.Mock()
state.closed = False

# init the cursor and fetch a single record
crs = cursor.Cursor(conn, "SELECT * FROM test", state, [], Record)
asyncio.run(crs._init(1))
asyncio.run(crs.fetch(1))

spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0)
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def lambda_handler(event, context):
.. code:: python
from opentelemetry.instrumentation.aws_lambda import AwsLambdaInstrumentor
from opentelemetry.propagate import get_global_textmap
def custom_event_context_extractor(lambda_event):
# If the `TraceContextTextMapPropagator` is the global propagator, we
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
# limitations under the License.

"""
Instrument `click`_ CLI applications.
Instrument `click`_ CLI applications. The instrumentor will avoid instrumenting
well-known servers (e.g. *flask run* and *uvicorn*) to avoid unexpected effects
like every request having the same Trace ID.
.. _click: https://pypi.org/project/click/
Expand Down Expand Up @@ -47,6 +49,12 @@ def hello():
import click
from wrapt import wrap_function_wrapper

try:
from flask.cli import ScriptInfo as FlaskScriptInfo
except ImportError:
FlaskScriptInfo = None


from opentelemetry import trace
from opentelemetry.instrumentation.click.package import _instruments
from opentelemetry.instrumentation.click.version import __version__
Expand All @@ -66,6 +74,20 @@ def hello():
_logger = getLogger(__name__)


def _skip_servers(ctx: click.Context):
# flask run
if (
ctx.info_name == "run"
and FlaskScriptInfo
and isinstance(ctx.obj, FlaskScriptInfo)
):
return True
# uvicorn
if ctx.info_name == "uvicorn":
return True
return False


def _command_invoke_wrapper(wrapped, instance, args, kwargs, tracer):
# Subclasses of Command include groups and CLI runners, but
# we only want to instrument the actual commands which are
Expand All @@ -74,6 +96,12 @@ def _command_invoke_wrapper(wrapped, instance, args, kwargs, tracer):
return wrapped(*args, **kwargs)

ctx = args[0]

# we don't want to create a root span for long running processes like servers
# otherwise all requests would have the same trace id
if _skip_servers(ctx):
return wrapped(*args, **kwargs)

span_name = ctx.info_name
span_attributes = {
PROCESS_COMMAND_ARGS: sys.argv,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
asgiref==3.8.1
blinker==1.7.0
click==8.1.7
Deprecated==1.2.14
Flask==3.0.2
iniconfig==2.0.0
itsdangerous==2.1.2
Jinja2==3.1.4
MarkupSafe==2.1.2
packaging==24.0
pluggy==1.5.0
py-cpuinfo==9.0.0
pytest==7.4.4
pytest-asyncio==0.23.5
tomli==2.0.1
typing_extensions==4.12.2
Werkzeug==3.0.6
wrapt==1.16.0
zipp==3.19.2
-e opentelemetry-instrumentation
-e instrumentation/opentelemetry-instrumentation-click
-e instrumentation/opentelemetry-instrumentation-flask
-e instrumentation/opentelemetry-instrumentation-wsgi
-e util/opentelemetry-util-http
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@
from unittest import mock

import click
import pytest
from click.testing import CliRunner

try:
from flask import cli as flask_cli
except ImportError:
flask_cli = None

from opentelemetry.instrumentation.click import ClickInstrumentor
from opentelemetry.test.test_base import TestBase
from opentelemetry.trace import SpanKind
Expand Down Expand Up @@ -60,7 +66,7 @@ def command():
)

@mock.patch("sys.argv", ["flask", "command"])
def test_flask_run_command_wrapping(self):
def test_flask_command_wrapping(self):
@click.command()
def command():
pass
Expand Down Expand Up @@ -162,6 +168,27 @@ def command_raises():
},
)

def test_uvicorn_cli_command_ignored(self):
@click.command("uvicorn")
def command_uvicorn():
pass

runner = CliRunner()
result = runner.invoke(command_uvicorn)
self.assertEqual(result.exit_code, 0)

self.assertFalse(self.memory_exporter.get_finished_spans())

@pytest.mark.skipif(flask_cli is None, reason="requires flask")
def test_flask_run_command_ignored(self):
runner = CliRunner()
result = runner.invoke(
flask_cli.run_command, obj=flask_cli.ScriptInfo()
)
self.assertEqual(result.exit_code, 2)

self.assertFalse(self.memory_exporter.get_finished_spans())

def test_uninstrument(self):
ClickInstrumentor().uninstrument()

Expand Down
Loading

0 comments on commit 285c01c

Please sign in to comment.