mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-28 20:52:57 +08:00
Ensure clean http url (#538)
This commit is contained in:
@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
([#530](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/530))
|
([#530](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/530))
|
||||||
- Fix weak reference error for pyodbc cursor in SQLAlchemy instrumentation.
|
- Fix weak reference error for pyodbc cursor in SQLAlchemy instrumentation.
|
||||||
([#469](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/469))
|
([#469](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/469))
|
||||||
|
- Implemented specification that HTTP span attributes must not contain username and password.
|
||||||
|
([#538](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/538))
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- `opentelemetry-instrumentation-httpx` Add `httpx` instrumentation
|
- `opentelemetry-instrumentation-httpx` Add `httpx` instrumentation
|
||||||
|
@ -41,6 +41,7 @@ install_requires =
|
|||||||
opentelemetry-api == 1.4.0.dev0
|
opentelemetry-api == 1.4.0.dev0
|
||||||
opentelemetry-semantic-conventions == 0.23.dev0
|
opentelemetry-semantic-conventions == 0.23.dev0
|
||||||
opentelemetry-instrumentation == 0.23.dev0
|
opentelemetry-instrumentation == 0.23.dev0
|
||||||
|
opentelemetry-util-http == 0.23.dev0
|
||||||
wrapt >= 1.0.0, < 2.0.0
|
wrapt >= 1.0.0, < 2.0.0
|
||||||
|
|
||||||
[options.packages.find]
|
[options.packages.find]
|
||||||
|
@ -82,6 +82,7 @@ from opentelemetry.propagate import inject
|
|||||||
from opentelemetry.semconv.trace import SpanAttributes
|
from opentelemetry.semconv.trace import SpanAttributes
|
||||||
from opentelemetry.trace import SpanKind, TracerProvider, get_tracer
|
from opentelemetry.trace import SpanKind, TracerProvider, get_tracer
|
||||||
from opentelemetry.trace.status import Status, StatusCode
|
from opentelemetry.trace.status import Status, StatusCode
|
||||||
|
from opentelemetry.util.http import remove_url_credentials
|
||||||
|
|
||||||
_UrlFilterT = typing.Optional[typing.Callable[[str], str]]
|
_UrlFilterT = typing.Optional[typing.Callable[[str], str]]
|
||||||
_SpanNameT = typing.Optional[
|
_SpanNameT = typing.Optional[
|
||||||
@ -173,11 +174,11 @@ def create_trace_config(
|
|||||||
if trace_config_ctx.span.is_recording():
|
if trace_config_ctx.span.is_recording():
|
||||||
attributes = {
|
attributes = {
|
||||||
SpanAttributes.HTTP_METHOD: http_method,
|
SpanAttributes.HTTP_METHOD: http_method,
|
||||||
SpanAttributes.HTTP_URL: trace_config_ctx.url_filter(
|
SpanAttributes.HTTP_URL: remove_url_credentials(
|
||||||
params.url
|
trace_config_ctx.url_filter(params.url)
|
||||||
)
|
)
|
||||||
if callable(trace_config_ctx.url_filter)
|
if callable(trace_config_ctx.url_filter)
|
||||||
else str(params.url),
|
else remove_url_credentials(str(params.url)),
|
||||||
}
|
}
|
||||||
for key, value in attributes.items():
|
for key, value in attributes.items():
|
||||||
trace_config_ctx.span.set_attribute(key, value)
|
trace_config_ctx.span.set_attribute(key, value)
|
||||||
|
@ -321,6 +321,37 @@ class TestAioHttpIntegration(TestBase):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_credential_removal(self):
|
||||||
|
trace_configs = [aiohttp_client.create_trace_config()]
|
||||||
|
|
||||||
|
url = "http://username:password@httpbin.org/status/200"
|
||||||
|
with self.subTest(url=url):
|
||||||
|
|
||||||
|
async def do_request(url):
|
||||||
|
async with aiohttp.ClientSession(
|
||||||
|
trace_configs=trace_configs,
|
||||||
|
) as session:
|
||||||
|
async with session.get(url):
|
||||||
|
pass
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(do_request(url))
|
||||||
|
|
||||||
|
self.assert_spans(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"HTTP GET",
|
||||||
|
(StatusCode.UNSET, None),
|
||||||
|
{
|
||||||
|
SpanAttributes.HTTP_METHOD: "GET",
|
||||||
|
SpanAttributes.HTTP_URL: "http://httpbin.org/status/200",
|
||||||
|
SpanAttributes.HTTP_STATUS_CODE: int(HTTPStatus.OK),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.memory_exporter.clear()
|
||||||
|
|
||||||
|
|
||||||
class TestAioHttpClientInstrumentor(TestBase):
|
class TestAioHttpClientInstrumentor(TestBase):
|
||||||
URL = "/test-path"
|
URL = "/test-path"
|
||||||
|
@ -41,6 +41,7 @@ install_requires =
|
|||||||
opentelemetry-api == 1.4.0.dev0
|
opentelemetry-api == 1.4.0.dev0
|
||||||
opentelemetry-semantic-conventions == 0.23.dev0
|
opentelemetry-semantic-conventions == 0.23.dev0
|
||||||
opentelemetry-instrumentation == 0.23.dev0
|
opentelemetry-instrumentation == 0.23.dev0
|
||||||
|
opentelemetry-util-http == 0.23.dev0
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
test =
|
test =
|
||||||
|
@ -32,6 +32,7 @@ from opentelemetry.propagate import extract
|
|||||||
from opentelemetry.propagators.textmap import Getter
|
from opentelemetry.propagators.textmap import Getter
|
||||||
from opentelemetry.semconv.trace import SpanAttributes
|
from opentelemetry.semconv.trace import SpanAttributes
|
||||||
from opentelemetry.trace.status import Status, StatusCode
|
from opentelemetry.trace.status import Status, StatusCode
|
||||||
|
from opentelemetry.util.http import remove_url_credentials
|
||||||
|
|
||||||
|
|
||||||
class ASGIGetter(Getter):
|
class ASGIGetter(Getter):
|
||||||
@ -86,7 +87,7 @@ def collect_request_attributes(scope):
|
|||||||
SpanAttributes.NET_HOST_PORT: port,
|
SpanAttributes.NET_HOST_PORT: port,
|
||||||
SpanAttributes.HTTP_FLAVOR: scope.get("http_version"),
|
SpanAttributes.HTTP_FLAVOR: scope.get("http_version"),
|
||||||
SpanAttributes.HTTP_TARGET: scope.get("path"),
|
SpanAttributes.HTTP_TARGET: scope.get("path"),
|
||||||
SpanAttributes.HTTP_URL: http_url,
|
SpanAttributes.HTTP_URL: remove_url_credentials(http_url),
|
||||||
}
|
}
|
||||||
http_method = scope.get("method")
|
http_method = scope.get("method")
|
||||||
if http_method:
|
if http_method:
|
||||||
|
@ -430,6 +430,14 @@ class TestAsgiAttributes(unittest.TestCase):
|
|||||||
otel_asgi.set_status_code(self.span, "Invalid Status Code")
|
otel_asgi.set_status_code(self.span, "Invalid Status Code")
|
||||||
self.assertEqual(self.span.set_status.call_count, 1)
|
self.assertEqual(self.span.set_status.call_count, 1)
|
||||||
|
|
||||||
|
def test_credential_removal(self):
|
||||||
|
self.scope["server"] = ("username:password@httpbin.org", 80)
|
||||||
|
self.scope["path"] = "/status/200"
|
||||||
|
attrs = otel_asgi.collect_request_attributes(self.scope)
|
||||||
|
self.assertEqual(
|
||||||
|
attrs[SpanAttributes.HTTP_URL], "http://httpbin.org/status/200"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -41,6 +41,7 @@ install_requires =
|
|||||||
opentelemetry-api == 1.4.0.dev0
|
opentelemetry-api == 1.4.0.dev0
|
||||||
opentelemetry-semantic-conventions == 0.23.dev0
|
opentelemetry-semantic-conventions == 0.23.dev0
|
||||||
opentelemetry-instrumentation == 0.23.dev0
|
opentelemetry-instrumentation == 0.23.dev0
|
||||||
|
opentelemetry-util-http == 0.23.dev0
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
test =
|
test =
|
||||||
|
@ -50,6 +50,7 @@ from opentelemetry.propagate import inject
|
|||||||
from opentelemetry.semconv.trace import SpanAttributes
|
from opentelemetry.semconv.trace import SpanAttributes
|
||||||
from opentelemetry.trace import SpanKind, get_tracer
|
from opentelemetry.trace import SpanKind, get_tracer
|
||||||
from opentelemetry.trace.status import Status
|
from opentelemetry.trace.status import Status
|
||||||
|
from opentelemetry.util.http import remove_url_credentials
|
||||||
|
|
||||||
# A key to a context variable to avoid creating duplicate spans when instrumenting
|
# A key to a context variable to avoid creating duplicate spans when instrumenting
|
||||||
# both, Session.request and Session.send, since Session.request calls into Session.send
|
# both, Session.request and Session.send, since Session.request calls into Session.send
|
||||||
@ -124,6 +125,8 @@ def _instrument(tracer, span_callback=None, name_callback=None):
|
|||||||
if not span_name or not isinstance(span_name, str):
|
if not span_name or not isinstance(span_name, str):
|
||||||
span_name = get_default_span_name(method)
|
span_name = get_default_span_name(method)
|
||||||
|
|
||||||
|
url = remove_url_credentials(url)
|
||||||
|
|
||||||
labels = {}
|
labels = {}
|
||||||
labels[SpanAttributes.HTTP_METHOD] = method
|
labels[SpanAttributes.HTTP_METHOD] = method
|
||||||
labels[SpanAttributes.HTTP_URL] = url
|
labels[SpanAttributes.HTTP_URL] = url
|
||||||
|
@ -357,6 +357,13 @@ class TestRequestsIntegration(RequestsIntegrationTestBase, TestBase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(span.status.status_code, StatusCode.ERROR)
|
self.assertEqual(span.status.status_code, StatusCode.ERROR)
|
||||||
|
|
||||||
|
def test_credential_removal(self):
|
||||||
|
new_url = "http://username:password@httpbin.org/status/200"
|
||||||
|
self.perform_request(new_url)
|
||||||
|
span = self.assert_span()
|
||||||
|
|
||||||
|
self.assertEqual(span.attributes[SpanAttributes.HTTP_URL], self.URL)
|
||||||
|
|
||||||
def test_if_headers_equals_none(self):
|
def test_if_headers_equals_none(self):
|
||||||
result = requests.get(self.URL, headers=None)
|
result = requests.get(self.URL, headers=None)
|
||||||
self.assertEqual(result.text, "Hello!")
|
self.assertEqual(result.text, "Hello!")
|
||||||
|
@ -22,6 +22,7 @@ from opentelemetry.propagate import inject
|
|||||||
from opentelemetry.semconv.trace import SpanAttributes
|
from opentelemetry.semconv.trace import SpanAttributes
|
||||||
from opentelemetry.trace.status import Status
|
from opentelemetry.trace.status import Status
|
||||||
from opentelemetry.util._time import _time_ns
|
from opentelemetry.util._time import _time_ns
|
||||||
|
from opentelemetry.util.http import remove_url_credentials
|
||||||
|
|
||||||
|
|
||||||
def _normalize_request(args, kwargs):
|
def _normalize_request(args, kwargs):
|
||||||
@ -61,7 +62,7 @@ def fetch_async(tracer, request_hook, response_hook, func, _, args, kwargs):
|
|||||||
|
|
||||||
if span.is_recording():
|
if span.is_recording():
|
||||||
attributes = {
|
attributes = {
|
||||||
SpanAttributes.HTTP_URL: request.url,
|
SpanAttributes.HTTP_URL: remove_url_credentials(request.url),
|
||||||
SpanAttributes.HTTP_METHOD: request.method,
|
SpanAttributes.HTTP_METHOD: request.method,
|
||||||
}
|
}
|
||||||
for key, value in attributes.items():
|
for key, value in attributes.items():
|
||||||
|
@ -455,6 +455,29 @@ class TestTornadoInstrumentation(TornadoTest):
|
|||||||
self.memory_exporter.clear()
|
self.memory_exporter.clear()
|
||||||
set_global_response_propagator(orig)
|
set_global_response_propagator(orig)
|
||||||
|
|
||||||
|
def test_credential_removal(self):
|
||||||
|
response = self.fetch(
|
||||||
|
"http://username:password@httpbin.org/status/200"
|
||||||
|
)
|
||||||
|
self.assertEqual(response.code, 200)
|
||||||
|
|
||||||
|
spans = self.sorted_spans(self.memory_exporter.get_finished_spans())
|
||||||
|
self.assertEqual(len(spans), 1)
|
||||||
|
client = spans[0]
|
||||||
|
|
||||||
|
self.assertEqual(client.name, "GET")
|
||||||
|
self.assertEqual(client.kind, SpanKind.CLIENT)
|
||||||
|
self.assert_span_has_attributes(
|
||||||
|
client,
|
||||||
|
{
|
||||||
|
SpanAttributes.HTTP_URL: "http://httpbin.org/status/200",
|
||||||
|
SpanAttributes.HTTP_METHOD: "GET",
|
||||||
|
SpanAttributes.HTTP_STATUS_CODE: 200,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.memory_exporter.clear()
|
||||||
|
|
||||||
|
|
||||||
class TornadoHookTest(TornadoTest):
|
class TornadoHookTest(TornadoTest):
|
||||||
_client_request_hook = None
|
_client_request_hook = None
|
||||||
|
@ -41,6 +41,7 @@ install_requires =
|
|||||||
opentelemetry-api == 1.4.0.dev0
|
opentelemetry-api == 1.4.0.dev0
|
||||||
opentelemetry-semantic-conventions == 0.23.dev0
|
opentelemetry-semantic-conventions == 0.23.dev0
|
||||||
opentelemetry-instrumentation == 0.23.dev0
|
opentelemetry-instrumentation == 0.23.dev0
|
||||||
|
opentelemetry-util-http == 0.23.dev0
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
test =
|
test =
|
||||||
|
@ -53,6 +53,7 @@ from opentelemetry.propagate import inject
|
|||||||
from opentelemetry.semconv.trace import SpanAttributes
|
from opentelemetry.semconv.trace import SpanAttributes
|
||||||
from opentelemetry.trace import SpanKind, get_tracer
|
from opentelemetry.trace import SpanKind, get_tracer
|
||||||
from opentelemetry.trace.status import Status
|
from opentelemetry.trace.status import Status
|
||||||
|
from opentelemetry.util.http import remove_url_credentials
|
||||||
|
|
||||||
# A key to a context variable to avoid creating duplicate spans when instrumenting
|
# A key to a context variable to avoid creating duplicate spans when instrumenting
|
||||||
_SUPPRESS_HTTP_INSTRUMENTATION_KEY = "suppress_http_instrumentation"
|
_SUPPRESS_HTTP_INSTRUMENTATION_KEY = "suppress_http_instrumentation"
|
||||||
@ -142,6 +143,8 @@ def _instrument(tracer, span_callback=None, name_callback=None):
|
|||||||
if not span_name or not isinstance(span_name, str):
|
if not span_name or not isinstance(span_name, str):
|
||||||
span_name = get_default_span_name(method)
|
span_name = get_default_span_name(method)
|
||||||
|
|
||||||
|
url = remove_url_credentials(url)
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
SpanAttributes.HTTP_METHOD: method,
|
SpanAttributes.HTTP_METHOD: method,
|
||||||
SpanAttributes.HTTP_URL: url,
|
SpanAttributes.HTTP_URL: url,
|
||||||
|
@ -35,6 +35,8 @@ from opentelemetry.test.mock_textmap import MockTextMapPropagator
|
|||||||
from opentelemetry.test.test_base import TestBase
|
from opentelemetry.test.test_base import TestBase
|
||||||
from opentelemetry.trace import StatusCode
|
from opentelemetry.trace import StatusCode
|
||||||
|
|
||||||
|
# pylint: disable=too-many-public-methods
|
||||||
|
|
||||||
|
|
||||||
class RequestsIntegrationTestBase(abc.ABC):
|
class RequestsIntegrationTestBase(abc.ABC):
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
@ -318,6 +320,15 @@ class RequestsIntegrationTestBase(abc.ABC):
|
|||||||
span = self.assert_span()
|
span = self.assert_span()
|
||||||
self.assertEqual(span.status.status_code, StatusCode.ERROR)
|
self.assertEqual(span.status.status_code, StatusCode.ERROR)
|
||||||
|
|
||||||
|
def test_credential_removal(self):
|
||||||
|
url = "http://username:password@httpbin.org/status/200"
|
||||||
|
|
||||||
|
with self.assertRaises(Exception):
|
||||||
|
self.perform_request(url)
|
||||||
|
|
||||||
|
span = self.assert_span()
|
||||||
|
self.assertEqual(span.attributes[SpanAttributes.HTTP_URL], self.URL)
|
||||||
|
|
||||||
|
|
||||||
class TestRequestsIntegration(RequestsIntegrationTestBase, TestBase):
|
class TestRequestsIntegration(RequestsIntegrationTestBase, TestBase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -287,3 +287,9 @@ class TestURLLib3Instrumentor(TestBase):
|
|||||||
|
|
||||||
response = self.perform_request(self.HTTP_URL + "?e=mcc")
|
response = self.perform_request(self.HTTP_URL + "?e=mcc")
|
||||||
self.assert_success_span(response, self.HTTP_URL)
|
self.assert_success_span(response, self.HTTP_URL)
|
||||||
|
|
||||||
|
def test_credential_removal(self):
|
||||||
|
url = "http://username:password@httpbin.org/status/200"
|
||||||
|
|
||||||
|
response = self.perform_request(url)
|
||||||
|
self.assert_success_span(response, self.HTTP_URL)
|
||||||
|
@ -41,6 +41,7 @@ install_requires =
|
|||||||
opentelemetry-api == 1.4.0.dev0
|
opentelemetry-api == 1.4.0.dev0
|
||||||
opentelemetry-semantic-conventions == 0.23.dev0
|
opentelemetry-semantic-conventions == 0.23.dev0
|
||||||
opentelemetry-instrumentation == 0.23.dev0
|
opentelemetry-instrumentation == 0.23.dev0
|
||||||
|
opentelemetry-util-http == 0.23.dev0
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
test =
|
test =
|
||||||
|
@ -65,6 +65,7 @@ from opentelemetry.propagate import extract
|
|||||||
from opentelemetry.propagators.textmap import Getter
|
from opentelemetry.propagators.textmap import Getter
|
||||||
from opentelemetry.semconv.trace import SpanAttributes
|
from opentelemetry.semconv.trace import SpanAttributes
|
||||||
from opentelemetry.trace.status import Status, StatusCode
|
from opentelemetry.trace.status import Status, StatusCode
|
||||||
|
from opentelemetry.util.http import remove_url_credentials
|
||||||
|
|
||||||
_HTTP_VERSION_PREFIX = "HTTP/"
|
_HTTP_VERSION_PREFIX = "HTTP/"
|
||||||
_CARRIER_KEY_PREFIX = "HTTP_"
|
_CARRIER_KEY_PREFIX = "HTTP_"
|
||||||
@ -128,7 +129,9 @@ def collect_request_attributes(environ):
|
|||||||
if target is not None:
|
if target is not None:
|
||||||
result[SpanAttributes.HTTP_TARGET] = target
|
result[SpanAttributes.HTTP_TARGET] = target
|
||||||
else:
|
else:
|
||||||
result[SpanAttributes.HTTP_URL] = wsgiref_util.request_uri(environ)
|
result[SpanAttributes.HTTP_URL] = remove_url_credentials(
|
||||||
|
wsgiref_util.request_uri(environ)
|
||||||
|
)
|
||||||
|
|
||||||
remote_addr = environ.get("REMOTE_ADDR")
|
remote_addr = environ.get("REMOTE_ADDR")
|
||||||
if remote_addr:
|
if remote_addr:
|
||||||
|
@ -364,6 +364,18 @@ class TestWsgiAttributes(unittest.TestCase):
|
|||||||
self.assertEqual(self.span.set_attribute.call_count, len(expected))
|
self.assertEqual(self.span.set_attribute.call_count, len(expected))
|
||||||
self.span.set_attribute.assert_has_calls(expected, any_order=True)
|
self.span.set_attribute.assert_has_calls(expected, any_order=True)
|
||||||
|
|
||||||
|
def test_credential_removal(self):
|
||||||
|
self.environ["HTTP_HOST"] = "username:password@httpbin.com"
|
||||||
|
self.environ["PATH_INFO"] = "/status/200"
|
||||||
|
expected = {
|
||||||
|
SpanAttributes.HTTP_URL: "http://httpbin.com/status/200",
|
||||||
|
SpanAttributes.NET_HOST_PORT: 80,
|
||||||
|
}
|
||||||
|
self.assertGreaterEqual(
|
||||||
|
otel_wsgi.collect_request_attributes(self.environ).items(),
|
||||||
|
expected.items(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestWsgiMiddlewareWithTracerProvider(WsgiTestBase):
|
class TestWsgiMiddlewareWithTracerProvider(WsgiTestBase):
|
||||||
def validate_response(
|
def validate_response(
|
||||||
|
5
tox.ini
5
tox.ini
@ -237,7 +237,7 @@ commands_pre =
|
|||||||
|
|
||||||
grpc: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test]
|
grpc: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test]
|
||||||
|
|
||||||
falcon,flask,django,pyramid,tornado,starlette,fastapi: pip install {toxinidir}/util/opentelemetry-util-http[test]
|
falcon,flask,django,pyramid,tornado,starlette,fastapi,aiohttp,asgi,requests,urllib,wsgi: pip install {toxinidir}/util/opentelemetry-util-http[test]
|
||||||
wsgi,falcon,flask,django,pyramid: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi[test]
|
wsgi,falcon,flask,django,pyramid: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi[test]
|
||||||
asgi,starlette,fastapi: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi[test]
|
asgi,starlette,fastapi: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi[test]
|
||||||
|
|
||||||
@ -413,6 +413,7 @@ deps =
|
|||||||
protobuf>=3.13.0
|
protobuf>=3.13.0
|
||||||
requests==2.25.0
|
requests==2.25.0
|
||||||
pyodbc~=4.0.30
|
pyodbc~=4.0.30
|
||||||
|
|
||||||
changedir =
|
changedir =
|
||||||
tests/opentelemetry-docker-tests/tests
|
tests/opentelemetry-docker-tests/tests
|
||||||
|
|
||||||
@ -435,13 +436,13 @@ commands_pre =
|
|||||||
-e {toxinidir}/opentelemetry-python-core/exporter/opentelemetry-exporter-opencensus
|
-e {toxinidir}/opentelemetry-python-core/exporter/opentelemetry-exporter-opencensus
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
python check_availability.py
|
python check_availability.py
|
||||||
|
|
||||||
commands =
|
commands =
|
||||||
pytest {posargs}
|
pytest {posargs}
|
||||||
|
|
||||||
commands_post =
|
commands_post =
|
||||||
docker-compose down -v
|
docker-compose down -v
|
||||||
|
|
||||||
|
|
||||||
[testenv:generate]
|
[testenv:generate]
|
||||||
deps =
|
deps =
|
||||||
-r {toxinidir}/gen-requirements.txt
|
-r {toxinidir}/gen-requirements.txt
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
from os import environ
|
from os import environ
|
||||||
from re import compile as re_compile
|
from re import compile as re_compile
|
||||||
from re import search
|
from re import search
|
||||||
|
from urllib.parse import urlparse, urlunparse
|
||||||
|
|
||||||
|
|
||||||
class ExcludeList:
|
class ExcludeList:
|
||||||
@ -57,3 +58,30 @@ def get_excluded_urls(instrumentation):
|
|||||||
]
|
]
|
||||||
|
|
||||||
return ExcludeList(excluded_urls)
|
return ExcludeList(excluded_urls)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_url_credentials(url: str) -> str:
|
||||||
|
"""Given a string url, remove the username and password only if it is a valid url"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
parsed = urlparse(url)
|
||||||
|
if all([parsed.scheme, parsed.netloc]): # checks for valid url
|
||||||
|
parsed_url = urlparse(url)
|
||||||
|
netloc = (
|
||||||
|
(":".join(((parsed_url.hostname or ""), str(parsed_url.port))))
|
||||||
|
if parsed_url.port
|
||||||
|
else (parsed_url.hostname or "")
|
||||||
|
)
|
||||||
|
return urlunparse(
|
||||||
|
(
|
||||||
|
parsed_url.scheme,
|
||||||
|
netloc,
|
||||||
|
parsed_url.path,
|
||||||
|
parsed_url.params,
|
||||||
|
parsed_url.query,
|
||||||
|
parsed_url.fragment,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except ValueError: # an unparseable url was passed
|
||||||
|
pass
|
||||||
|
return url
|
||||||
|
Reference in New Issue
Block a user