Compare commits
22 Commits
Author | SHA1 | Date |
---|---|---|
|
109173fec7 | |
|
b63ca133be | |
|
1f78c8acff | |
|
49fa53131d | |
|
333fc5dcb4 | |
|
80c357bb16 | |
|
3c4d18cc13 | |
|
b74633a552 | |
|
b1c2c7941b | |
|
b69ebb7224 | |
|
6977da3893 | |
|
ca079cbc56 | |
|
40d8942bf5 | |
|
78300e9642 | |
|
c4347e027c | |
|
0a03c9abf2 | |
|
85dbfe520a | |
|
b27225273b | |
|
591051f8bb | |
|
50cdeeee12 | |
|
04f8899252 | |
|
59cc34e9f3 |
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -11,10 +11,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## Unreleased
|
||||
|
||||
## Version 1.35.0/0.56b0 (2025-07-11)
|
||||
|
||||
### Added
|
||||
|
||||
- `opentelemetry-instrumentation-aiokafka` Add instrumentation of `consumer.getmany` (batch)
|
||||
([#3257](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3257))
|
||||
- `opentelemetry-instrumentation-pika` Added instrumentation for All `SelectConnection` adapters
|
||||
([#3584](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3584))
|
||||
- `opentelemetry-instrumentation-tornado` Add support for `WebSocketHandler` instrumentation
|
||||
([#3498](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3498))
|
||||
- `opentelemetry-util-http` Added support for redacting specific url query string values and url credentials in instrumentations
|
||||
([#3508](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3508))
|
||||
- `opentelemetry-instrumentation-pymongo` `aggregate` and `getMore` capture statements support
|
||||
([#3601](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3601))
|
||||
|
||||
### Fixed
|
||||
|
||||
- `opentelemetry-instrumentation-asgi`: fix excluded_urls in instrumentation-asgi
|
||||
([#3567](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3567))
|
||||
- `opentelemetry-resource-detector-containerid`: make it more quiet on platforms without cgroups
|
||||
([#3579](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3579))
|
||||
|
||||
## Version 1.34.0/0.55b0 (2025-06-04)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -71,7 +88,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
([#3513](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3513))
|
||||
- `opentelemetry-instrumentation` Allow re-raising exception when instrumentation fails
|
||||
([#3545](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3545))
|
||||
|
||||
- `opentelemetry-instrumentation-aiokafka` Add instrumentation of `consumer.getmany` (batch)
|
||||
([#3257](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3257))
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Drop support for Python 3.8, bump baseline to Python 3.9.
|
||||
|
|
48
README.md
48
README.md
|
@ -111,7 +111,16 @@ We meet weekly on Thursday at 9AM PT. The meeting is subject to change depending
|
|||
|
||||
Meeting notes are available as a public [Google doc](https://docs.google.com/document/d/1CIMGoIOZ-c3-igzbd6_Pnxx1SjAkjwqoYSUWxPY8XIs/edit). For edit access, get in touch on [GitHub Discussions](https://github.com/open-telemetry/opentelemetry-python/discussions).
|
||||
|
||||
Approvers ([@open-telemetry/python-approvers](https://github.com/orgs/open-telemetry/teams/python-approvers)):
|
||||
### Maintainers
|
||||
|
||||
- [Aaron Abbott](https://github.com/aabmass), Google
|
||||
- [Leighton Chen](https://github.com/lzchen), Microsoft
|
||||
- [Riccardo Magliocchetti](https://github.com/xrmx), Elastic
|
||||
- [Shalev Roda](https://github.com/shalevr), Cisco
|
||||
|
||||
For more information about the maintainer role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer).
|
||||
|
||||
### Approvers
|
||||
|
||||
- [Emídio Neto](https://github.com/emdneto), PicPay
|
||||
- [Jeremy Voss](https://github.com/jeremydvoss), Microsoft
|
||||
|
@ -121,34 +130,29 @@ Approvers ([@open-telemetry/python-approvers](https://github.com/orgs/open-telem
|
|||
- [Srikanth Chekuri](https://github.com/srikanthccv), signoz.io
|
||||
- [Tammy Baylis](https://github.com/tammy-baylis-swi), SolarWinds
|
||||
|
||||
Emeritus Approvers:
|
||||
For more information about the approver role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver).
|
||||
|
||||
- [Ashutosh Goel](https://github.com/ashu658), Cisco
|
||||
- [Héctor Hernández](https://github.com/hectorhdzg), Microsoft
|
||||
- [Nikolay Sokolik](https://github.com/oxeye-nikolay), Oxeye
|
||||
- [Nikolay Sokolik](https://github.com/nikosokolik), Oxeye
|
||||
- [Nathaniel Ruiz Nowell](https://github.com/NathanielRN), AWS
|
||||
### Emeritus Maintainers
|
||||
|
||||
*Find more about the approver role in [community repository](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver).*
|
||||
- [Alex Boten](https://github.com/codeboten)
|
||||
- [Diego Hurtado](https://github.com/ocelotl)
|
||||
- [Owais Lone](https://github.com/owais)
|
||||
- [Yusuke Tsutsumi](https://github.com/toumorokoshi)
|
||||
|
||||
Maintainers ([@open-telemetry/python-maintainers](https://github.com/orgs/open-telemetry/teams/python-maintainers)):
|
||||
For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager).
|
||||
|
||||
- [Aaron Abbott](https://github.com/aabmass), Google
|
||||
- [Leighton Chen](https://github.com/lzchen), Microsoft
|
||||
- [Riccardo Magliocchetti](https://github.com/xrmx), Elastic
|
||||
- [Shalev Roda](https://github.com/shalevr), Cisco
|
||||
### Emeritus Approvers
|
||||
|
||||
Emeritus Maintainers:
|
||||
- [Ashutosh Goel](https://github.com/ashu658)
|
||||
- [Héctor Hernández](https://github.com/hectorhdzg)
|
||||
- [Nathaniel Ruiz Nowell](https://github.com/NathanielRN)
|
||||
- [Nikolay Sokolik](https://github.com/nikosokolik)
|
||||
- [Nikolay Sokolik](https://github.com/oxeye-nikolay)
|
||||
|
||||
- [Alex Boten](https://github.com/codeboten), Lightstep
|
||||
- [Diego Hurtado](https://github.com/ocelotl), Lightstep
|
||||
- [Owais Lone](https://github.com/owais), Splunk
|
||||
- [Yusuke Tsutsumi](https://github.com/toumorokoshi), Google
|
||||
For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager).
|
||||
|
||||
*Find more about the maintainer role in [community repository](https://github.com/open-telemetry/community/blob/main/community-membership.md#maintainer).*
|
||||
|
||||
### Thanks to all the people who already contributed
|
||||
### Thanks to all of our contributors!
|
||||
|
||||
<a href="https://github.com/open-telemetry/opentelemetry-python-contrib/graphs/contributors">
|
||||
<img src="https://contributors-img.web.app/image?repo=open-telemetry/opentelemetry-python-contrib" />
|
||||
<img alt="Repo contributors" src="https://contrib.rocks/image?repo=open-telemetry/opentelemetry-python-contrib" />
|
||||
</a>
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -122,7 +122,7 @@ intersphinx_mapping = {
|
|||
"https://opentelemetry-python.readthedocs.io/en/latest/",
|
||||
None,
|
||||
),
|
||||
"redis": ("https://redis-py.readthedocs.io/en/latest/", None),
|
||||
"redis": ("https://redis.readthedocs.io/en/latest/", None),
|
||||
}
|
||||
|
||||
# http://www.sphinx-doc.org/en/master/config.html#confval-nitpicky
|
||||
|
|
|
@ -16,7 +16,7 @@ sortfirst=
|
|||
ext/*
|
||||
|
||||
[stable]
|
||||
version=1.34.0.dev
|
||||
version=1.36.0.dev
|
||||
|
||||
packages=
|
||||
opentelemetry-sdk
|
||||
|
@ -34,7 +34,7 @@ packages=
|
|||
opentelemetry-api
|
||||
|
||||
[prerelease]
|
||||
version=0.55b0.dev
|
||||
version=0.57b0.dev
|
||||
|
||||
packages=
|
||||
all
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -27,7 +27,7 @@ classifiers = [
|
|||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-sdk ~= 1.12",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"rich>=10.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## Unreleased
|
||||
|
||||
## Version 0.3b0 (2025-07-08)
|
||||
|
||||
- Add automatic instrumentation to tool call functions ([#3446](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3446))
|
||||
|
||||
## Version 0.2b0 (2025-04-28)
|
||||
|
|
|
@ -17,4 +17,4 @@
|
|||
# This version should stay below "1.0" until the fundamentals
|
||||
# in "TODOS.md" have been addressed. Please revisit the TODOs
|
||||
# listed there before bumping to a stable version.
|
||||
__version__ = "0.3b0.dev"
|
||||
__version__ = "0.4b0.dev"
|
||||
|
|
|
@ -26,7 +26,7 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.5",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,9 +26,9 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-util-http == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-util-http == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ from opentelemetry.semconv.metrics.http_metrics import (
|
|||
)
|
||||
from opentelemetry.trace import Span, SpanKind, TracerProvider, get_tracer
|
||||
from opentelemetry.trace.status import Status, StatusCode
|
||||
from opentelemetry.util.http import remove_url_credentials, sanitize_method
|
||||
from opentelemetry.util.http import redact_url, sanitize_method
|
||||
|
||||
_UrlFilterT = typing.Optional[typing.Callable[[yarl.URL], str]]
|
||||
_RequestHookT = typing.Optional[
|
||||
|
@ -311,9 +311,9 @@ def create_trace_config(
|
|||
method = params.method
|
||||
request_span_name = _get_span_name(method)
|
||||
request_url = (
|
||||
remove_url_credentials(trace_config_ctx.url_filter(params.url))
|
||||
redact_url(trace_config_ctx.url_filter(params.url))
|
||||
if callable(trace_config_ctx.url_filter)
|
||||
else remove_url_credentials(str(params.url))
|
||||
else redact_url(str(params.url))
|
||||
)
|
||||
|
||||
span_attributes = {}
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -762,16 +762,16 @@ class TestAioHttpIntegration(TestBase):
|
|||
)
|
||||
self.memory_exporter.clear()
|
||||
|
||||
def test_credential_removal(self):
|
||||
def test_remove_sensitive_params(self):
|
||||
trace_configs = [aiohttp_client.create_trace_config()]
|
||||
|
||||
app = HttpServerMock("test_credential_removal")
|
||||
app = HttpServerMock("test_remove_sensitive_params")
|
||||
|
||||
@app.route("/status/200")
|
||||
def index():
|
||||
return "hello"
|
||||
|
||||
url = "http://username:password@localhost:5000/status/200"
|
||||
url = "http://username:password@localhost:5000/status/200?Signature=secret"
|
||||
|
||||
with app.run("localhost", 5000):
|
||||
with self.subTest(url=url):
|
||||
|
@ -793,7 +793,9 @@ class TestAioHttpIntegration(TestBase):
|
|||
(StatusCode.UNSET, None),
|
||||
{
|
||||
HTTP_METHOD: "GET",
|
||||
HTTP_URL: ("http://localhost:5000/status/200"),
|
||||
HTTP_URL: (
|
||||
"http://REDACTED:REDACTED@localhost:5000/status/200?Signature=REDACTED"
|
||||
),
|
||||
HTTP_STATUS_CODE: int(HTTPStatus.OK),
|
||||
},
|
||||
)
|
||||
|
|
|
@ -26,9 +26,9 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-util-http == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-util-http == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ from opentelemetry.semconv._incubating.attributes.net_attributes import (
|
|||
)
|
||||
from opentelemetry.semconv.metrics import MetricInstruments
|
||||
from opentelemetry.trace.status import Status, StatusCode
|
||||
from opentelemetry.util.http import get_excluded_urls, remove_url_credentials
|
||||
from opentelemetry.util.http import get_excluded_urls, redact_url
|
||||
|
||||
_duration_attrs = [
|
||||
HTTP_METHOD,
|
||||
|
@ -148,6 +148,7 @@ def collect_request_attributes(request: web.Request) -> Dict:
|
|||
request.url.port,
|
||||
str(request.url),
|
||||
)
|
||||
|
||||
query_string = request.query_string
|
||||
if query_string and http_url:
|
||||
if isinstance(query_string, bytes):
|
||||
|
@ -161,7 +162,7 @@ def collect_request_attributes(request: web.Request) -> Dict:
|
|||
HTTP_ROUTE: _get_view_func(request),
|
||||
HTTP_FLAVOR: f"{request.version.major}.{request.version.minor}",
|
||||
HTTP_TARGET: request.path,
|
||||
HTTP_URL: remove_url_credentials(http_url),
|
||||
HTTP_URL: redact_url(http_url),
|
||||
}
|
||||
|
||||
http_method = request.method
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -152,3 +152,46 @@ async def test_suppress_instrumentation(
|
|||
await client.get("/test-path")
|
||||
|
||||
assert len(memory_exporter.get_finished_spans()) == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remove_sensitive_params(tracer, aiohttp_server):
|
||||
"""Test that sensitive information in URLs is properly redacted."""
|
||||
_, memory_exporter = tracer
|
||||
|
||||
# Set up instrumentation
|
||||
AioHttpServerInstrumentor().instrument()
|
||||
|
||||
# Create app with test route
|
||||
app = aiohttp.web.Application()
|
||||
|
||||
async def handler(request):
|
||||
return aiohttp.web.Response(text="hello")
|
||||
|
||||
app.router.add_get("/status/200", handler)
|
||||
|
||||
# Start the server
|
||||
server = await aiohttp_server(app)
|
||||
|
||||
# Make request with sensitive data in URL
|
||||
url = f"http://username:password@{server.host}:{server.port}/status/200?Signature=secret"
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url) as response:
|
||||
assert response.status == 200
|
||||
assert await response.text() == "hello"
|
||||
|
||||
# Verify redaction in span attributes
|
||||
spans = memory_exporter.get_finished_spans()
|
||||
assert len(spans) == 1
|
||||
|
||||
span = spans[0]
|
||||
assert span.attributes[HTTP_METHOD] == "GET"
|
||||
assert span.attributes[HTTP_STATUS_CODE] == 200
|
||||
assert (
|
||||
span.attributes[HTTP_URL]
|
||||
== f"http://{server.host}:{server.port}/status/200?Signature=REDACTED"
|
||||
)
|
||||
|
||||
# Clean up
|
||||
AioHttpServerInstrumentor().uninstrument()
|
||||
memory_exporter.clear()
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.27",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"typing_extensions ~= 4.1",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -27,9 +27,9 @@ classifiers = [
|
|||
dependencies = [
|
||||
"asgiref ~= 3.0",
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-util-http == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-util-http == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-locals,too-many-lines
|
||||
|
||||
"""
|
||||
The opentelemetry-instrumentation-asgi package provides an ASGI middleware that can be used
|
||||
|
@ -81,19 +81,38 @@ For example,
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
def server_request_hook(span: Span, scope: dict[str, Any]):
|
||||
from opentelemetry.trace import Span
|
||||
from typing import Any
|
||||
from asgiref.typing import Scope, ASGIReceiveEvent, ASGISendEvent
|
||||
from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
|
||||
|
||||
async def application(scope: Scope, receive: ASGIReceiveEvent, send: ASGISendEvent):
|
||||
await send({
|
||||
'type': 'http.response.start',
|
||||
'status': 200,
|
||||
'headers': [
|
||||
[b'content-type', b'text/plain'],
|
||||
],
|
||||
})
|
||||
|
||||
await send({
|
||||
'type': 'http.response.body',
|
||||
'body': b'Hello, world!',
|
||||
})
|
||||
|
||||
def server_request_hook(span: Span, scope: Scope):
|
||||
if span and span.is_recording():
|
||||
span.set_attribute("custom_user_attribute_from_request_hook", "some-value")
|
||||
|
||||
def client_request_hook(span: Span, scope: dict[str, Any], message: dict[str, Any]):
|
||||
def client_request_hook(span: Span, scope: Scope, message: dict[str, Any]):
|
||||
if span and span.is_recording():
|
||||
span.set_attribute("custom_user_attribute_from_client_request_hook", "some-value")
|
||||
|
||||
def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, Any]):
|
||||
def client_response_hook(span: Span, scope: Scope, message: dict[str, Any]):
|
||||
if span and span.is_recording():
|
||||
span.set_attribute("custom_user_attribute_from_response_hook", "some-value")
|
||||
|
||||
OpenTelemetryMiddleware().(application, server_request_hook=server_request_hook, client_request_hook=client_request_hook, client_response_hook=client_response_hook)
|
||||
OpenTelemetryMiddleware(application, server_request_hook=server_request_hook, client_request_hook=client_request_hook, client_response_hook=client_response_hook)
|
||||
|
||||
Capture HTTP request and response headers
|
||||
*****************************************
|
||||
|
@ -254,12 +273,14 @@ from opentelemetry.util.http import (
|
|||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS,
|
||||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST,
|
||||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE,
|
||||
ExcludeList,
|
||||
SanitizeValue,
|
||||
_parse_url_query,
|
||||
get_custom_headers,
|
||||
normalise_request_header_name,
|
||||
normalise_response_header_name,
|
||||
remove_url_credentials,
|
||||
parse_excluded_urls,
|
||||
redact_url,
|
||||
sanitize_method,
|
||||
)
|
||||
|
||||
|
@ -356,7 +377,7 @@ def collect_request_attributes(
|
|||
if _report_old(sem_conv_opt_in_mode):
|
||||
_set_http_url(
|
||||
result,
|
||||
remove_url_credentials(http_url),
|
||||
redact_url(http_url),
|
||||
_StabilityMode.DEFAULT,
|
||||
)
|
||||
http_method = scope.get("method", "")
|
||||
|
@ -537,7 +558,7 @@ class OpenTelemetryMiddleware:
|
|||
def __init__(
|
||||
self,
|
||||
app,
|
||||
excluded_urls=None,
|
||||
excluded_urls: ExcludeList | str | None = None,
|
||||
default_span_details=None,
|
||||
server_request_hook: ServerRequestHook = None,
|
||||
client_request_hook: ClientRequestHook = None,
|
||||
|
@ -619,6 +640,8 @@ class OpenTelemetryMiddleware:
|
|||
self.active_requests_counter = create_http_server_active_requests(
|
||||
self.meter
|
||||
)
|
||||
if isinstance(excluded_urls, str):
|
||||
excluded_urls = parse_excluded_urls(excluded_urls)
|
||||
self.excluded_urls = excluded_urls
|
||||
self.default_span_details = (
|
||||
default_span_details or get_default_span_details
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -1633,6 +1633,29 @@ class TestAsgiApplication(AsyncAsgiTestBase):
|
|||
await self.get_all_output()
|
||||
self.assertIsNone(self.memory_metrics_reader.get_metrics_data())
|
||||
|
||||
async def test_excluded_urls(self):
|
||||
self.scope["path"] = "/test_excluded_urls"
|
||||
app = otel_asgi.OpenTelemetryMiddleware(
|
||||
simple_asgi, excluded_urls="test_excluded_urls"
|
||||
)
|
||||
self.seed_app(app)
|
||||
await self.send_default_request()
|
||||
await self.get_all_output()
|
||||
spans = self.memory_exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 0)
|
||||
|
||||
async def test_no_excluded_urls(self):
|
||||
self.scope["path"] = "/test_excluded_urls"
|
||||
app = otel_asgi.OpenTelemetryMiddleware(
|
||||
simple_asgi, excluded_urls="test_excluded_urls"
|
||||
)
|
||||
self.seed_app(app)
|
||||
self.scope["path"] = "/test_no_excluded_urls"
|
||||
await self.send_default_request()
|
||||
await self.get_all_output()
|
||||
spans = self.memory_exporter.get_finished_spans()
|
||||
self.assertGreater(len(spans), 0)
|
||||
|
||||
|
||||
class TestAsgiAttributes(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
@ -1809,12 +1832,14 @@ class TestAsgiAttributes(unittest.TestCase):
|
|||
otel_asgi.set_status_code(self.span, "Invalid Status Code")
|
||||
self.assertEqual(self.span.set_status.call_count, 1)
|
||||
|
||||
def test_credential_removal(self):
|
||||
def test_remove_sensitive_params(self):
|
||||
self.scope["server"] = ("username:password@mock", 80)
|
||||
self.scope["path"] = "/status/200"
|
||||
self.scope["query_string"] = b"X-Goog-Signature=1234567890"
|
||||
attrs = otel_asgi.collect_request_attributes(self.scope)
|
||||
self.assertEqual(
|
||||
attrs[SpanAttributes.HTTP_URL], "http://mock/status/200"
|
||||
attrs[SpanAttributes.HTTP_URL],
|
||||
"http://REDACTED:REDACTED@mock/status/200?X-Goog-Signature=REDACTED",
|
||||
)
|
||||
|
||||
def test_collect_target_attribute_missing(self):
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"wrapt ~= 1.0",
|
||||
"typing_extensions ~= 4.12",
|
||||
]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.14",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -25,8 +25,8 @@ classifiers = [
|
|||
"Programming Language :: Python :: 3.13",
|
||||
]
|
||||
dependencies = [
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-propagator-aws-xray ~= 1.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -25,8 +25,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.30",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-propagator-aws-xray ~= 1.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -25,7 +25,7 @@ classifiers = [
|
|||
"Programming Language :: Python :: 3.13",
|
||||
]
|
||||
dependencies = [
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
||||
_instruments = tuple()
|
||||
|
|
|
@ -26,15 +26,15 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-wsgi == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-util-http == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-wsgi == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-util-http == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
asgi = [
|
||||
"opentelemetry-instrumentation-asgi == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-asgi == 0.57b0.dev",
|
||||
]
|
||||
instruments = [
|
||||
"django >= 1.10",
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,10 +26,10 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-wsgi == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-util-http == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-wsgi == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-util-http == 0.57b0.dev",
|
||||
"packaging >= 20.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -427,6 +427,20 @@ class TestFalconInstrumentation(TestFalconBase, WsgiTestBase):
|
|||
spans = self.memory_exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 0)
|
||||
|
||||
def test_no_op_tracer_provider(self):
|
||||
FalconInstrumentor().uninstrument()
|
||||
|
||||
FalconInstrumentor().instrument(
|
||||
tracer_provider=trace.NoOpTracerProvider()
|
||||
)
|
||||
|
||||
self.memory_exporter.clear()
|
||||
|
||||
self.client().simulate_get(path="/hello")
|
||||
|
||||
spans = self.memory_exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 0)
|
||||
|
||||
def test_exclude_lists(self):
|
||||
self.client().simulate_get(path="/ping")
|
||||
span_list = self.memory_exporter.get_finished_spans()
|
||||
|
|
|
@ -26,10 +26,10 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-asgi == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-util-http == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-asgi == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-util-http == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,10 +26,10 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-wsgi == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-util-http == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-wsgi == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-util-http == 0.57b0.dev",
|
||||
"packaging >= 21.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ Usage Aio Client
|
|||
grpc_client_instrumentor.instrument()
|
||||
|
||||
async def run():
|
||||
with grpc.aio.insecure_channel("localhost:50051") as channel:
|
||||
async with grpc.aio.insecure_channel("localhost:50051") as channel:
|
||||
|
||||
stub = helloworld_pb2_grpc.GreeterStub(channel)
|
||||
response = await stub.SayHello(helloworld_pb2.HelloRequest(name="YOU"))
|
||||
|
@ -168,7 +168,7 @@ You can also add the interceptor manually, rather than using
|
|||
|
||||
from opentelemetry.instrumentation.grpc import aio_client_interceptors
|
||||
|
||||
channel = grpc.aio.insecure_channel("localhost:12345", interceptors=aio_client_interceptors())
|
||||
async with grpc.aio.insecure_channel("localhost:50051", interceptors=aio_client_interceptors()) as channel:
|
||||
|
||||
|
||||
Usage Aio Server
|
||||
|
@ -253,6 +253,11 @@ You can also use the filters directly on the provided interceptors:
|
|||
|
||||
.. code-block::
|
||||
|
||||
import grpc
|
||||
from concurrent import futures
|
||||
from opentelemetry.instrumentation.grpc import filters
|
||||
from opentelemetry.instrumentation.grpc import server_interceptor
|
||||
|
||||
my_interceptor = server_interceptor(
|
||||
filter_ = filters.negate(filters.method_name("TestMethod"))
|
||||
)
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,9 +26,9 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-util-http == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-util-http == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ from opentelemetry.semconv.metrics.http_metrics import (
|
|||
from opentelemetry.trace import SpanKind, Tracer, TracerProvider, get_tracer
|
||||
from opentelemetry.trace.span import Span
|
||||
from opentelemetry.trace.status import StatusCode
|
||||
from opentelemetry.util.http import remove_url_credentials, sanitize_method
|
||||
from opentelemetry.util.http import redact_url, sanitize_method
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -313,7 +313,7 @@ def _extract_parameters(
|
|||
# In httpx >= 0.20.0, handle_request receives a Request object
|
||||
request: httpx.Request = args[0]
|
||||
method = request.method.encode()
|
||||
url = httpx.URL(remove_url_credentials(str(request.url)))
|
||||
url = httpx.URL(str(request.url))
|
||||
headers = request.headers
|
||||
stream = request.stream
|
||||
extensions = request.extensions
|
||||
|
@ -382,7 +382,7 @@ def _apply_request_client_attributes_to_span(
|
|||
)
|
||||
|
||||
# http semconv transition: http.url -> url.full
|
||||
_set_http_url(span_attributes, str(url), semconv)
|
||||
_set_http_url(span_attributes, redact_url(str(url)), semconv)
|
||||
|
||||
# Set HTTP method in metric labels
|
||||
_set_http_method(
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -1301,12 +1301,26 @@ class TestSyncIntegration(BaseTestCases.BaseManualTest):
|
|||
self.assert_span(num_spans=1)
|
||||
self.assert_metrics(num_metrics=1)
|
||||
|
||||
def test_credential_removal(self):
|
||||
new_url = "http://username:password@mock/status/200"
|
||||
def test_remove_sensitive_params(self):
|
||||
new_url = "http://username:password@mock/status/200?sig=secret"
|
||||
self.perform_request(new_url)
|
||||
span = self.assert_span()
|
||||
|
||||
self.assertEqual(span.attributes[SpanAttributes.HTTP_URL], self.URL)
|
||||
actual_url = span.attributes[SpanAttributes.HTTP_URL]
|
||||
|
||||
if "@" in actual_url:
|
||||
# If credentials are present, they must be redacted
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.HTTP_URL],
|
||||
"http://REDACTED:REDACTED@mock/status/200?sig=REDACTED",
|
||||
)
|
||||
else:
|
||||
# If credentials are removed completely, the query string should still be redacted
|
||||
self.assertIn(
|
||||
"http://mock/status/200?sig=REDACTED",
|
||||
actual_url,
|
||||
f"Basic URL structure is incorrect: {actual_url}",
|
||||
)
|
||||
|
||||
|
||||
class TestAsyncIntegration(BaseTestCases.BaseManualTest):
|
||||
|
@ -1373,12 +1387,24 @@ class TestAsyncIntegration(BaseTestCases.BaseManualTest):
|
|||
self.assert_span(num_spans=2)
|
||||
self.assert_metrics(num_metrics=1)
|
||||
|
||||
def test_credential_removal(self):
|
||||
new_url = "http://username:password@mock/status/200"
|
||||
def test_remove_sensitive_params(self):
|
||||
new_url = "http://username:password@mock/status/200?Signature=secret"
|
||||
self.perform_request(new_url)
|
||||
span = self.assert_span()
|
||||
|
||||
self.assertEqual(span.attributes[SpanAttributes.HTTP_URL], self.URL)
|
||||
actual_url = span.attributes[SpanAttributes.HTTP_URL]
|
||||
|
||||
if "@" in actual_url:
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.HTTP_URL],
|
||||
"http://REDACTED:REDACTED@mock/status/200?Signature=REDACTED",
|
||||
)
|
||||
else:
|
||||
self.assertIn(
|
||||
"http://mock/status/200?Signature=REDACTED",
|
||||
actual_url,
|
||||
f"If credentials are removed, the query string still should be redacted {actual_url}",
|
||||
)
|
||||
|
||||
|
||||
class TestSyncInstrumentationIntegration(BaseTestCases.BaseInstrumentorTest):
|
||||
|
|
|
@ -26,7 +26,7 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.5",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,7 +26,7 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
||||
_instruments = tuple()
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -20,7 +20,9 @@ import opentelemetry.instrumentation.mysql
|
|||
from opentelemetry import trace as trace_api
|
||||
from opentelemetry.instrumentation.mysql import MySQLInstrumentor
|
||||
from opentelemetry.sdk import resources
|
||||
from opentelemetry.semconv.trace import SpanAttributes
|
||||
from opentelemetry.semconv._incubating.attributes.db_attributes import (
|
||||
DB_STATEMENT,
|
||||
)
|
||||
from opentelemetry.test.test_base import TestBase
|
||||
|
||||
|
||||
|
@ -157,7 +159,7 @@ class TestMysqlIntegration(TestBase):
|
|||
f"Select 1 /*db_driver='mysql.connector%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
|
||||
)
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT],
|
||||
span.attributes[DB_STATEMENT],
|
||||
"Select 1;",
|
||||
)
|
||||
|
||||
|
@ -196,7 +198,7 @@ class TestMysqlIntegration(TestBase):
|
|||
f"Select 1 /*db_driver='mysql.connector%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
|
||||
)
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT],
|
||||
span.attributes[DB_STATEMENT],
|
||||
f"Select 1 /*db_driver='mysql.connector%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
|
||||
)
|
||||
|
||||
|
@ -239,7 +241,7 @@ class TestMysqlIntegration(TestBase):
|
|||
f"Select 1 /*db_driver='mysql.connector%%3Afoobar',dbapi_threadsafety='123',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
|
||||
)
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT],
|
||||
span.attributes[DB_STATEMENT],
|
||||
"Select 1;",
|
||||
)
|
||||
|
||||
|
@ -274,7 +276,7 @@ class TestMysqlIntegration(TestBase):
|
|||
spans_list = self.memory_exporter.get_finished_spans()
|
||||
span = spans_list[0]
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT],
|
||||
span.attributes[DB_STATEMENT],
|
||||
"Select 1;",
|
||||
)
|
||||
|
||||
|
@ -332,7 +334,7 @@ class TestMysqlIntegration(TestBase):
|
|||
f"Select 1 /*db_driver='mysql.connector%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
|
||||
)
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT],
|
||||
span.attributes[DB_STATEMENT],
|
||||
"Select 1;",
|
||||
)
|
||||
|
||||
|
@ -373,7 +375,7 @@ class TestMysqlIntegration(TestBase):
|
|||
f"Select 1 /*db_driver='mysql.connector%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
|
||||
)
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT],
|
||||
span.attributes[DB_STATEMENT],
|
||||
f"Select 1 /*db_driver='mysql.connector%%3Afoobar',dbapi_level='123',dbapi_threadsafety='123',driver_paramstyle='test',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
|
||||
)
|
||||
|
||||
|
@ -418,7 +420,7 @@ class TestMysqlIntegration(TestBase):
|
|||
f"Select 1 /*db_driver='mysql.connector%%3Afoobar',dbapi_threadsafety='123',mysql_client_version='foobaz',traceparent='00-{trace_id}-{span_id}-01'*/;",
|
||||
)
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT],
|
||||
span.attributes[DB_STATEMENT],
|
||||
"Select 1;",
|
||||
)
|
||||
|
||||
|
@ -453,7 +455,7 @@ class TestMysqlIntegration(TestBase):
|
|||
spans_list = self.memory_exporter.get_finished_spans()
|
||||
span = spans_list[0]
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT],
|
||||
span.attributes[DB_STATEMENT],
|
||||
"Select 1;",
|
||||
)
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -25,7 +25,7 @@ classifiers = [
|
|||
"Programming Language :: Python :: 3.13",
|
||||
]
|
||||
dependencies = [
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-api ~= 1.5",
|
||||
"packaging >= 20.0",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
# pylint: disable=unnecessary-dunder-call
|
||||
|
||||
from logging import getLogger
|
||||
from typing import Any, Collection, Dict, Optional
|
||||
from typing import Any, Collection, Dict, Optional, Union
|
||||
|
||||
import pika
|
||||
import wrapt
|
||||
|
@ -24,6 +24,8 @@ from pika.adapters.blocking_connection import (
|
|||
BlockingChannel,
|
||||
_QueueConsumerGeneratorInfo,
|
||||
)
|
||||
from pika.channel import Channel
|
||||
from pika.connection import Connection
|
||||
|
||||
from opentelemetry import trace
|
||||
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
||||
|
@ -53,12 +55,16 @@ class PikaInstrumentor(BaseInstrumentor): # type: ignore
|
|||
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
@staticmethod
|
||||
def _instrument_blocking_channel_consumers(
|
||||
channel: BlockingChannel,
|
||||
def _instrument_channel_consumers(
|
||||
channel: Union[BlockingChannel, Channel],
|
||||
tracer: Tracer,
|
||||
consume_hook: utils.HookT = utils.dummy_callback,
|
||||
) -> Any:
|
||||
for consumer_tag, consumer_info in channel._consumer_infos.items():
|
||||
if isinstance(channel, BlockingChannel):
|
||||
consumer_infos = channel._consumer_infos
|
||||
elif isinstance(channel, Channel):
|
||||
consumer_infos = channel._consumers
|
||||
for consumer_tag, consumer_info in consumer_infos.items():
|
||||
callback_attr = PikaInstrumentor.CONSUMER_CALLBACK_ATTR
|
||||
consumer_callback = getattr(consumer_info, callback_attr, None)
|
||||
if consumer_callback is None:
|
||||
|
@ -79,7 +85,7 @@ class PikaInstrumentor(BaseInstrumentor): # type: ignore
|
|||
|
||||
@staticmethod
|
||||
def _instrument_basic_publish(
|
||||
channel: BlockingChannel,
|
||||
channel: Union[BlockingChannel, Channel],
|
||||
tracer: Tracer,
|
||||
publish_hook: utils.HookT = utils.dummy_callback,
|
||||
) -> None:
|
||||
|
@ -93,7 +99,7 @@ class PikaInstrumentor(BaseInstrumentor): # type: ignore
|
|||
|
||||
@staticmethod
|
||||
def _instrument_channel_functions(
|
||||
channel: BlockingChannel,
|
||||
channel: Union[BlockingChannel, Channel],
|
||||
tracer: Tracer,
|
||||
publish_hook: utils.HookT = utils.dummy_callback,
|
||||
) -> None:
|
||||
|
@ -103,7 +109,9 @@ class PikaInstrumentor(BaseInstrumentor): # type: ignore
|
|||
)
|
||||
|
||||
@staticmethod
|
||||
def _uninstrument_channel_functions(channel: BlockingChannel) -> None:
|
||||
def _uninstrument_channel_functions(
|
||||
channel: Union[BlockingChannel, Channel],
|
||||
) -> None:
|
||||
for function_name in _FUNCTIONS_TO_UNINSTRUMENT:
|
||||
if not hasattr(channel, function_name):
|
||||
continue
|
||||
|
@ -115,7 +123,7 @@ class PikaInstrumentor(BaseInstrumentor): # type: ignore
|
|||
@staticmethod
|
||||
# Make sure that the spans are created inside hash them set as parent and not as brothers
|
||||
def instrument_channel(
|
||||
channel: BlockingChannel,
|
||||
channel: Union[BlockingChannel, Channel],
|
||||
tracer_provider: Optional[TracerProvider] = None,
|
||||
publish_hook: utils.HookT = utils.dummy_callback,
|
||||
consume_hook: utils.HookT = utils.dummy_callback,
|
||||
|
@ -133,7 +141,7 @@ class PikaInstrumentor(BaseInstrumentor): # type: ignore
|
|||
tracer_provider,
|
||||
schema_url="https://opentelemetry.io/schemas/1.11.0",
|
||||
)
|
||||
PikaInstrumentor._instrument_blocking_channel_consumers(
|
||||
PikaInstrumentor._instrument_channel_consumers(
|
||||
channel, tracer, consume_hook
|
||||
)
|
||||
PikaInstrumentor._decorate_basic_consume(channel, tracer, consume_hook)
|
||||
|
@ -178,16 +186,17 @@ class PikaInstrumentor(BaseInstrumentor): # type: ignore
|
|||
return channel
|
||||
|
||||
wrapt.wrap_function_wrapper(BlockingConnection, "channel", wrapper)
|
||||
wrapt.wrap_function_wrapper(Connection, "channel", wrapper)
|
||||
|
||||
@staticmethod
|
||||
def _decorate_basic_consume(
|
||||
channel: BlockingChannel,
|
||||
channel: Union[BlockingChannel, Channel],
|
||||
tracer: Optional[Tracer],
|
||||
consume_hook: utils.HookT = utils.dummy_callback,
|
||||
) -> None:
|
||||
def wrapper(wrapped, instance, args, kwargs):
|
||||
return_value = wrapped(*args, **kwargs)
|
||||
PikaInstrumentor._instrument_blocking_channel_consumers(
|
||||
PikaInstrumentor._instrument_channel_consumers(
|
||||
channel, tracer, consume_hook
|
||||
)
|
||||
return return_value
|
||||
|
@ -236,6 +245,7 @@ class PikaInstrumentor(BaseInstrumentor): # type: ignore
|
|||
if hasattr(self, "__opentelemetry_tracer_provider"):
|
||||
delattr(self, "__opentelemetry_tracer_provider")
|
||||
unwrap(BlockingConnection, "channel")
|
||||
unwrap(Connection, "channel")
|
||||
unwrap(_QueueConsumerGeneratorInfo, "__init__")
|
||||
|
||||
def instrumentation_dependencies(self) -> Collection[str]:
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -13,9 +13,13 @@
|
|||
# limitations under the License.
|
||||
from unittest import TestCase, mock
|
||||
|
||||
from pika.adapters import BlockingConnection
|
||||
from pika.adapters.blocking_connection import _QueueConsumerGeneratorInfo
|
||||
from pika.adapters import BaseConnection, BlockingConnection
|
||||
from pika.adapters.blocking_connection import (
|
||||
BlockingChannel,
|
||||
_QueueConsumerGeneratorInfo,
|
||||
)
|
||||
from pika.channel import Channel
|
||||
from pika.connection import Connection
|
||||
from wrapt import BoundFunctionWrapper
|
||||
|
||||
from opentelemetry.instrumentation.pika import PikaInstrumentor
|
||||
|
@ -31,11 +35,13 @@ from opentelemetry.trace import Tracer
|
|||
|
||||
class TestPika(TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.blocking_channel = mock.MagicMock(spec=BlockingChannel)
|
||||
self.channel = mock.MagicMock(spec=Channel)
|
||||
consumer_info = mock.MagicMock()
|
||||
callback_attr = PikaInstrumentor.CONSUMER_CALLBACK_ATTR
|
||||
setattr(consumer_info, callback_attr, mock.MagicMock())
|
||||
self.channel._consumer_infos = {"consumer-tag": consumer_info}
|
||||
self.blocking_channel._consumer_infos = {"consumer-tag": consumer_info}
|
||||
self.channel._consumers = {"consumer-tag": consumer_info}
|
||||
self.mock_callback = mock.MagicMock()
|
||||
|
||||
def test_instrument_api(self) -> None:
|
||||
|
@ -44,6 +50,10 @@ class TestPika(TestCase):
|
|||
self.assertTrue(
|
||||
isinstance(BlockingConnection.channel, BoundFunctionWrapper)
|
||||
)
|
||||
self.assertTrue(isinstance(Connection.channel, BoundFunctionWrapper))
|
||||
self.assertTrue(
|
||||
isinstance(BaseConnection.channel, BoundFunctionWrapper)
|
||||
)
|
||||
self.assertTrue(
|
||||
isinstance(
|
||||
_QueueConsumerGeneratorInfo.__init__, BoundFunctionWrapper
|
||||
|
@ -56,6 +66,10 @@ class TestPika(TestCase):
|
|||
self.assertFalse(
|
||||
isinstance(BlockingConnection.channel, BoundFunctionWrapper)
|
||||
)
|
||||
self.assertFalse(isinstance(Connection.channel, BoundFunctionWrapper))
|
||||
self.assertFalse(
|
||||
isinstance(BaseConnection.channel, BoundFunctionWrapper)
|
||||
)
|
||||
self.assertFalse(
|
||||
isinstance(
|
||||
_QueueConsumerGeneratorInfo.__init__, BoundFunctionWrapper
|
||||
|
@ -69,11 +83,34 @@ class TestPika(TestCase):
|
|||
"opentelemetry.instrumentation.pika.PikaInstrumentor._decorate_basic_consume"
|
||||
)
|
||||
@mock.patch(
|
||||
"opentelemetry.instrumentation.pika.PikaInstrumentor._instrument_blocking_channel_consumers"
|
||||
"opentelemetry.instrumentation.pika.PikaInstrumentor._instrument_channel_consumers"
|
||||
)
|
||||
def test_instrument_blocking_channel(
|
||||
self,
|
||||
instrument_channel_consumers: mock.MagicMock,
|
||||
instrument_basic_consume: mock.MagicMock,
|
||||
instrument_channel_functions: mock.MagicMock,
|
||||
):
|
||||
PikaInstrumentor.instrument_channel(channel=self.blocking_channel)
|
||||
assert hasattr(
|
||||
self.blocking_channel, "_is_instrumented_by_opentelemetry"
|
||||
), "channel is not marked as instrumented!"
|
||||
instrument_channel_consumers.assert_called_once()
|
||||
instrument_basic_consume.assert_called_once()
|
||||
instrument_channel_functions.assert_called_once()
|
||||
|
||||
@mock.patch(
|
||||
"opentelemetry.instrumentation.pika.PikaInstrumentor._instrument_channel_functions"
|
||||
)
|
||||
@mock.patch(
|
||||
"opentelemetry.instrumentation.pika.PikaInstrumentor._decorate_basic_consume"
|
||||
)
|
||||
@mock.patch(
|
||||
"opentelemetry.instrumentation.pika.PikaInstrumentor._instrument_channel_consumers"
|
||||
)
|
||||
def test_instrument_channel(
|
||||
self,
|
||||
instrument_blocking_channel_consumers: mock.MagicMock,
|
||||
instrument_channel_consumers: mock.MagicMock,
|
||||
instrument_basic_consume: mock.MagicMock,
|
||||
instrument_channel_functions: mock.MagicMock,
|
||||
):
|
||||
|
@ -81,12 +118,12 @@ class TestPika(TestCase):
|
|||
assert hasattr(
|
||||
self.channel, "_is_instrumented_by_opentelemetry"
|
||||
), "channel is not marked as instrumented!"
|
||||
instrument_blocking_channel_consumers.assert_called_once()
|
||||
instrument_channel_consumers.assert_called_once()
|
||||
instrument_basic_consume.assert_called_once()
|
||||
instrument_channel_functions.assert_called_once()
|
||||
|
||||
@mock.patch("opentelemetry.instrumentation.pika.utils._decorate_callback")
|
||||
def test_instrument_consumers(
|
||||
def test_instrument_consumers_on_blocking_channel(
|
||||
self, decorate_callback: mock.MagicMock
|
||||
) -> None:
|
||||
tracer = mock.MagicMock(spec=Tracer)
|
||||
|
@ -95,23 +132,63 @@ class TestPika(TestCase):
|
|||
mock.call(
|
||||
getattr(value, callback_attr), tracer, key, dummy_callback
|
||||
)
|
||||
for key, value in self.channel._consumer_infos.items()
|
||||
for key, value in self.blocking_channel._consumer_infos.items()
|
||||
]
|
||||
PikaInstrumentor._instrument_blocking_channel_consumers(
|
||||
self.channel, tracer
|
||||
PikaInstrumentor._instrument_channel_consumers(
|
||||
self.blocking_channel, tracer
|
||||
)
|
||||
decorate_callback.assert_has_calls(
|
||||
calls=expected_decoration_calls, any_order=True
|
||||
)
|
||||
assert all(
|
||||
hasattr(callback, "_original_callback")
|
||||
for callback in self.channel._consumer_infos.values()
|
||||
for callback in self.blocking_channel._consumer_infos.values()
|
||||
)
|
||||
|
||||
@mock.patch("opentelemetry.instrumentation.pika.utils._decorate_callback")
|
||||
def test_instrument_consumers_on_channel(
|
||||
self, decorate_callback: mock.MagicMock
|
||||
) -> None:
|
||||
tracer = mock.MagicMock(spec=Tracer)
|
||||
callback_attr = PikaInstrumentor.CONSUMER_CALLBACK_ATTR
|
||||
expected_decoration_calls = [
|
||||
mock.call(
|
||||
getattr(value, callback_attr), tracer, key, dummy_callback
|
||||
)
|
||||
for key, value in self.channel._consumers.items()
|
||||
]
|
||||
PikaInstrumentor._instrument_channel_consumers(self.channel, tracer)
|
||||
decorate_callback.assert_has_calls(
|
||||
calls=expected_decoration_calls, any_order=True
|
||||
)
|
||||
assert all(
|
||||
hasattr(callback, "_original_callback")
|
||||
for callback in self.channel._consumers.values()
|
||||
)
|
||||
|
||||
@mock.patch(
|
||||
"opentelemetry.instrumentation.pika.utils._decorate_basic_publish"
|
||||
)
|
||||
def test_instrument_basic_publish(
|
||||
def test_instrument_basic_publish_on_blocking_channel(
|
||||
self, decorate_basic_publish: mock.MagicMock
|
||||
) -> None:
|
||||
tracer = mock.MagicMock(spec=Tracer)
|
||||
original_function = self.blocking_channel.basic_publish
|
||||
PikaInstrumentor._instrument_basic_publish(
|
||||
self.blocking_channel, tracer
|
||||
)
|
||||
decorate_basic_publish.assert_called_once_with(
|
||||
original_function, self.blocking_channel, tracer, dummy_callback
|
||||
)
|
||||
self.assertEqual(
|
||||
self.blocking_channel.basic_publish,
|
||||
decorate_basic_publish.return_value,
|
||||
)
|
||||
|
||||
@mock.patch(
|
||||
"opentelemetry.instrumentation.pika.utils._decorate_basic_publish"
|
||||
)
|
||||
def test_instrument_basic_publish_on_channel(
|
||||
self, decorate_basic_publish: mock.MagicMock
|
||||
) -> None:
|
||||
tracer = mock.MagicMock(spec=Tracer)
|
||||
|
@ -141,6 +218,17 @@ class TestPika(TestCase):
|
|||
isinstance(generator_info.pending_events, ReadyMessagesDequeProxy)
|
||||
)
|
||||
|
||||
def test_uninstrument_blocking_channel_functions(self) -> None:
|
||||
original_function = self.blocking_channel.basic_publish
|
||||
self.blocking_channel.basic_publish = mock.MagicMock()
|
||||
self.blocking_channel.basic_publish._original_function = (
|
||||
original_function
|
||||
)
|
||||
PikaInstrumentor._uninstrument_channel_functions(self.blocking_channel)
|
||||
self.assertEqual(
|
||||
self.blocking_channel.basic_publish, original_function
|
||||
)
|
||||
|
||||
def test_uninstrument_channel_functions(self) -> None:
|
||||
original_function = self.channel.basic_publish
|
||||
self.channel.basic_publish = mock.MagicMock()
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -17,4 +17,6 @@ COMMAND_TO_ATTRIBUTE_MAPPING = {
|
|||
"delete": "deletes",
|
||||
"update": "updates",
|
||||
"find": "filter",
|
||||
"getMore": "collection",
|
||||
"aggregate": "pipeline",
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -57,14 +57,12 @@ class TestPymongo(TestBase):
|
|||
# pylint: disable=protected-access
|
||||
span = command_tracer._pop_span(mock_event)
|
||||
self.assertIs(span.kind, trace_api.SpanKind.CLIENT)
|
||||
self.assertEqual(span.name, "database_name.command_name")
|
||||
self.assertEqual(span.name, "database_name.find")
|
||||
self.assertEqual(span.attributes[SpanAttributes.DB_SYSTEM], "mongodb")
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_NAME], "database_name"
|
||||
)
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT], "command_name"
|
||||
)
|
||||
self.assertEqual(span.attributes[SpanAttributes.DB_STATEMENT], "find")
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.NET_PEER_NAME], "test.com"
|
||||
)
|
||||
|
@ -181,7 +179,7 @@ class TestPymongo(TestBase):
|
|||
|
||||
self.assertEqual(len(spans_list), 1)
|
||||
span = spans_list[0]
|
||||
self.assertEqual(span.name, "database_name.command_name")
|
||||
self.assertEqual(span.name, "database_name.123")
|
||||
|
||||
def test_no_op_tracer(self):
|
||||
mock_event = MockEvent({})
|
||||
|
@ -194,6 +192,90 @@ class TestPymongo(TestBase):
|
|||
spans_list = self.memory_exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans_list), 0)
|
||||
|
||||
def test_capture_statement_getmore(self):
|
||||
command_attrs = {
|
||||
"command_name": "getMore",
|
||||
"collection": "test_collection",
|
||||
}
|
||||
mock_event = MockEvent(command_attrs)
|
||||
|
||||
command_tracer = CommandTracer(self.tracer, capture_statement=True)
|
||||
command_tracer.started(event=mock_event)
|
||||
command_tracer.succeeded(event=mock_event)
|
||||
|
||||
spans_list = self.memory_exporter.get_finished_spans()
|
||||
|
||||
self.assertEqual(len(spans_list), 1)
|
||||
span = spans_list[0]
|
||||
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT],
|
||||
"getMore test_collection",
|
||||
)
|
||||
|
||||
def test_capture_statement_aggregate(self):
|
||||
pipeline = [
|
||||
{"$match": {"status": "active"}},
|
||||
{"$group": {"_id": "$category", "count": {"$sum": 1}}},
|
||||
]
|
||||
command_attrs = {
|
||||
"command_name": "aggregate",
|
||||
"pipeline": pipeline,
|
||||
}
|
||||
command_tracer = CommandTracer(self.tracer, capture_statement=True)
|
||||
mock_event = MockEvent(command_attrs)
|
||||
command_tracer.started(event=mock_event)
|
||||
command_tracer.succeeded(event=mock_event)
|
||||
|
||||
spans_list = self.memory_exporter.get_finished_spans()
|
||||
|
||||
self.assertEqual(len(spans_list), 1)
|
||||
span = spans_list[0]
|
||||
|
||||
expected_statement = f"aggregate {pipeline}"
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT], expected_statement
|
||||
)
|
||||
|
||||
def test_capture_statement_disabled_getmore(self):
|
||||
command_attrs = {
|
||||
"command_name": "getMore",
|
||||
"collection": "test_collection",
|
||||
}
|
||||
command_tracer = CommandTracer(self.tracer, capture_statement=False)
|
||||
mock_event = MockEvent(command_attrs)
|
||||
command_tracer.started(event=mock_event)
|
||||
command_tracer.succeeded(event=mock_event)
|
||||
|
||||
spans_list = self.memory_exporter.get_finished_spans()
|
||||
|
||||
self.assertEqual(len(spans_list), 1)
|
||||
span = spans_list[0]
|
||||
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT], "getMore"
|
||||
)
|
||||
|
||||
def test_capture_statement_disabled_aggregate(self):
|
||||
pipeline = [{"$match": {"status": "active"}}]
|
||||
command_attrs = {
|
||||
"command_name": "aggregate",
|
||||
"pipeline": pipeline,
|
||||
}
|
||||
command_tracer = CommandTracer(self.tracer, capture_statement=False)
|
||||
mock_event = MockEvent(command_attrs)
|
||||
command_tracer.started(event=mock_event)
|
||||
command_tracer.succeeded(event=mock_event)
|
||||
|
||||
spans_list = self.memory_exporter.get_finished_spans()
|
||||
|
||||
self.assertEqual(len(spans_list), 1)
|
||||
span = spans_list[0]
|
||||
|
||||
self.assertEqual(
|
||||
span.attributes[SpanAttributes.DB_STATEMENT], "aggregate"
|
||||
)
|
||||
|
||||
|
||||
class MockCommand:
|
||||
def __init__(self, command_attrs):
|
||||
|
@ -206,6 +288,7 @@ class MockCommand:
|
|||
class MockEvent:
|
||||
def __init__(self, command_attrs, connection_id=None, request_id=""):
|
||||
self.command = MockCommand(command_attrs)
|
||||
self.command_name = self.command.get("command_name")
|
||||
self.connection_id = connection_id
|
||||
self.request_id = request_id
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,8 +26,8 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-dbapi == 0.57b0.dev",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__version__ = "0.55b0.dev"
|
||||
__version__ = "0.57b0.dev"
|
||||
|
|
|
@ -26,10 +26,10 @@ classifiers = [
|
|||
]
|
||||
dependencies = [
|
||||
"opentelemetry-api ~= 1.12",
|
||||
"opentelemetry-instrumentation == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation-wsgi == 0.55b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.55b0.dev",
|
||||
"opentelemetry-util-http == 0.55b0.dev",
|
||||
"opentelemetry-instrumentation == 0.57b0.dev",
|
||||
"opentelemetry-instrumentation-wsgi == 0.57b0.dev",
|
||||
"opentelemetry-semantic-conventions == 0.57b0.dev",
|
||||
"opentelemetry-util-http == 0.57b0.dev",
|
||||
"wrapt >= 1.0.0, < 2.0.0",
|
||||
]
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue