From dceb5c03990707c678d2a35c99d30fa6f3206b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Thu, 16 Apr 2020 08:32:37 -0500 Subject: [PATCH 1/7] ext/requests: Implement instrumentor interface Implement Instrumentor interface to allow user enabling instrumentation in the library and to work with autoinstrumentation. --- docs/examples/http/client.py | 9 ++- docs/examples/http/server.py | 15 ++-- .../flask_example.py | 7 +- docs/getting-started.rst | 2 +- ext/opentelemetry-ext-http-requests/setup.cfg | 5 ++ .../ext/http_requests/__init__.py | 69 ++++++++++++------- .../tests/test_requests_integration.py | 45 +++++++++--- tests/w3c_tracecontext_validation_server.py | 2 +- tox.ini | 4 +- 9 files changed, 110 insertions(+), 48 deletions(-) diff --git a/docs/examples/http/client.py b/docs/examples/http/client.py index 2b37d89597f..483e95b516a 100755 --- a/docs/examples/http/client.py +++ b/docs/examples/http/client.py @@ -28,15 +28,18 @@ # The preferred tracer implementation must be set, as the opentelemetry-api # defines the interface with a no-op implementation. +# It must be done before instrumenting any library. trace.set_tracer_provider(TracerProvider()) -tracer_provider = trace.get_tracer_provider() +# Enable instrumentation in the requests library. +http_requests.RequestsInstrumentor().instrument() + +# Configure a console span exporter. exporter = ConsoleSpanExporter() span_processor = BatchExportSpanProcessor(exporter) -tracer_provider.add_span_processor(span_processor) +trace.get_tracer_provider().add_span_processor(span_processor) # Integrations are the glue that binds the OpenTelemetry API and the # frameworks and libraries that are used together, automatically creating # Spans and propagating context as appropriate. -http_requests.enable(tracer_provider) response = requests.get(url="http://127.0.0.1:5000/") diff --git a/docs/examples/http/server.py b/docs/examples/http/server.py index 806bd0b88c4..46e2e22103b 100755 --- a/docs/examples/http/server.py +++ b/docs/examples/http/server.py @@ -30,20 +30,23 @@ # The preferred tracer implementation must be set, as the opentelemetry-api # defines the interface with a no-op implementation. +# It must be done before instrumenting any library. trace.set_tracer_provider(TracerProvider()) -tracer = trace.get_tracer(__name__) - -exporter = ConsoleSpanExporter() -span_processor = BatchExportSpanProcessor(exporter) -trace.get_tracer_provider().add_span_processor(span_processor) # Integrations are the glue that binds the OpenTelemetry API and the # frameworks and libraries that are used together, automatically creating # Spans and propagating context as appropriate. -http_requests.enable(trace.get_tracer_provider()) +http_requests.RequestsInstrumentor().instrument() app = flask.Flask(__name__) app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app) +# Configure a console span exporter. +exporter = ConsoleSpanExporter() +span_processor = BatchExportSpanProcessor(exporter) +trace.get_tracer_provider().add_span_processor(span_processor) + +tracer = trace.get_tracer(__name__) + @app.route("/") def hello(): diff --git a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py index 21a9962d864..98c97bd307e 100644 --- a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py +++ b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py @@ -29,13 +29,16 @@ ) trace.set_tracer_provider(TracerProvider()) + +opentelemetry.ext.http_requests.RequestsInstrumentor().instrument() +FlaskInstrumentor().instrument() + trace.get_tracer_provider().add_span_processor( SimpleExportSpanProcessor(ConsoleSpanExporter()) ) -FlaskInstrumentor().instrument() + app = flask.Flask(__name__) -opentelemetry.ext.http_requests.enable(trace.get_tracer_provider()) @app.route("/") diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 47c19e32fcc..f4e6918d96f 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -202,7 +202,7 @@ And let's write a small Flask application that sends an HTTP request, activating ) app = flask.Flask(__name__) - opentelemetry.ext.http_requests.enable(trace.get_tracer_provider()) + opentelemetry.ext.http_requests.RequestsInstrumentor().instrument() @app.route("/") def hello(): diff --git a/ext/opentelemetry-ext-http-requests/setup.cfg b/ext/opentelemetry-ext-http-requests/setup.cfg index d77e5247744..fc2ff724574 100644 --- a/ext/opentelemetry-ext-http-requests/setup.cfg +++ b/ext/opentelemetry-ext-http-requests/setup.cfg @@ -41,6 +41,7 @@ package_dir= packages=find_namespace: install_requires = opentelemetry-api == 0.7.dev0 + opentelemetry-auto-instrumentation == 0.7.dev0 requests ~= 2.0 [options.extras_require] @@ -50,3 +51,7 @@ test = [options.packages.find] where = src + +[options.entry_points] +opentelemetry_instrumentor = + requests = opentelemetry.ext.http_requests:RequestsInstrumentor diff --git a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py index cd6f3378a05..16d4aeaa78d 100644 --- a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py +++ b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py @@ -14,7 +14,7 @@ """ This library allows tracing HTTP requests made by the -`requests `_ library. +`requests `_ library. Usage ----- @@ -23,10 +23,10 @@ import requests import opentelemetry.ext.http_requests - from opentelemetry.trace import TracerProvider - opentelemetry.ext.http_requests.enable(TracerProvider()) - response = requests.get(url='https://www.example.org/') + # You can optionally pass a custom TracerProvider to RequestInstrumentor.instrument() + opentelemetry.ext.http_requests.RequestInstrumentor.instrument() + response = requests.get(url="https://www.example.org/") Limitations ----------- @@ -47,17 +47,16 @@ from requests.sessions import Session -from opentelemetry import context, propagators +from opentelemetry import context, propagators, trace +from opentelemetry.auto_instrumentation.instrumentor import BaseInstrumentor from opentelemetry.ext.http_requests.version import __version__ -from opentelemetry.trace import SpanKind +from opentelemetry.trace import SpanKind, get_tracer_provider +_tracer = None -# NOTE: Currently we force passing a tracer. But in turn, this forces the user -# to configure a SDK before enabling this integration. In turn, this means that -# if the SDK/tracer is already using `requests` they may, in theory, bypass our -# instrumentation when using `import from`, etc. (currently we only instrument -# a instance method so the probability for that is very low). -def enable(tracer_provider): + +# pylint: disable=unused-argument +def _instrument(tracer_provider=None): """Enables tracing of all requests calls that go through :code:`requests.session.Session.request` (this includes :code:`requests.get`, etc.).""" @@ -69,11 +68,6 @@ def enable(tracer_provider): # before v1.0.0, Dec 17, 2012, see # https://github.com/psf/requests/commit/4e5c4a6ab7bb0195dececdd19bb8505b872fe120) - # Guard against double instrumentation - disable() - - tracer = tracer_provider.get_tracer(__name__, __version__) - wrapped = Session.request @functools.wraps(wrapped) @@ -91,8 +85,20 @@ def instrumented_request(self, method, url, *args, **kwargs): if parsed_url is None: path = "" path = parsed_url.path - - with tracer.start_as_current_span(path, kind=SpanKind.CLIENT) as span: + # TODO: This is a workaround because currently the _instrument() + # method is called by the opentelemetry-auto-instrumentation command + # before configuring the SDK. This approach avoid getting a no-op + # tracer. + # pylint: disable=global-statement + global _tracer + if _tracer is None: + nonlocal tracer_provider + if tracer_provider is None: + tracer_provider = get_tracer_provider() + + _tracer = tracer_provider.get_tracer(__name__, __version__) + + with _tracer.start_as_current_span(path, kind=SpanKind.CLIENT) as span: span.set_attribute("component", "http") span.set_attribute("http.method", method.upper()) span.set_attribute("http.url", url) @@ -119,18 +125,31 @@ def instrumented_request(self, method, url, *args, **kwargs): # different, then push the current URL, pop it afterwards) -def disable(): +def _uninstrument(): + # pylint: disable=global-statement """Disables instrumentation of :code:`requests` through this module. Note that this only works if no other module also patches requests.""" + global _tracer if getattr(Session.request, "opentelemetry_ext_requests_applied", False): original = Session.request.__wrapped__ # pylint:disable=no-member Session.request = original + _tracer = None + + +class RequestsInstrumentor(BaseInstrumentor): + def _instrument(self, **kwargs): + _instrument(tracer_provider=kwargs.get("tracer_provider")) + def _uninstrument(self, **kwargs): + _uninstrument() -def disable_session(session): - """Disables instrumentation on the session object.""" - if getattr(session.request, "opentelemetry_ext_requests_applied", False): - original = session.request.__wrapped__ # pylint:disable=no-member - session.request = types.MethodType(original, session) + @staticmethod + def uninstrument_session(session): + """Disables instrumentation on the session object.""" + if getattr( + session.request, "opentelemetry_ext_requests_applied", False + ): + original = session.request.__wrapped__ # pylint:disable=no-member + session.request = types.MethodType(original, session) diff --git a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py index 67de0692f1d..5e182a65c40 100644 --- a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py +++ b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py @@ -18,8 +18,9 @@ import requests import urllib3 -import opentelemetry.ext.http_requests from opentelemetry import context, propagators, trace +from opentelemetry.ext import http_requests +from opentelemetry.sdk import resources from opentelemetry.test.mock_httptextformat import MockHTTPTextFormat from opentelemetry.test.test_base import TestBase @@ -29,7 +30,7 @@ class TestRequestsIntegration(TestBase): def setUp(self): super().setUp() - opentelemetry.ext.http_requests.enable(self.tracer_provider) + http_requests.RequestsInstrumentor().instrument() httpretty.enable() httpretty.register_uri( httpretty.GET, self.URL, body="Hello!", @@ -37,15 +38,17 @@ def setUp(self): def tearDown(self): super().tearDown() - opentelemetry.ext.http_requests.disable() + http_requests.RequestsInstrumentor().uninstrument() httpretty.disable() def test_basic(self): result = requests.get(self.URL) self.assertEqual(result.text, "Hello!") + span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 1) span = span_list[0] + self.assertIs(span.kind, trace.SpanKind.CLIENT) self.assertEqual(span.name, "/status/200") @@ -60,6 +63,12 @@ def test_basic(self): }, ) + self.assertIs( + span.status.canonical_code, trace.status.StatusCanonicalCode.OK + ) + + self.check_span_instrumentation_info(span, http_requests) + def test_invalid_url(self): url = "http://[::1/nope" exception_type = requests.exceptions.InvalidURL @@ -81,18 +90,18 @@ def test_invalid_url(self): {"component": "http", "http.method": "POST", "http.url": url}, ) - def test_disable(self): - opentelemetry.ext.http_requests.disable() + def test_uninstrument(self): + http_requests.RequestsInstrumentor().uninstrument() result = requests.get(self.URL) self.assertEqual(result.text, "Hello!") span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 0) + # instrument again to avoid annoying warning message + http_requests.RequestsInstrumentor().instrument() - opentelemetry.ext.http_requests.disable() - - def test_disable_session(self): + def test_uninstrument_session(self): session1 = requests.Session() - opentelemetry.ext.http_requests.disable_session(session1) + http_requests.RequestsInstrumentor().uninstrument_session(session1) result = session1.get(self.URL) self.assertEqual(result.text, "Hello!") @@ -152,3 +161,21 @@ def test_distributed_context(self): finally: propagators.set_global_httptextformat(previous_propagator) + + def test_custom_tracer_provider(self): + resource = resources.Resource.create({}) + result = self.create_tracer_provider(resource=resource) + tracer_provider, exporter = result + http_requests.RequestsInstrumentor().uninstrument() + http_requests.RequestsInstrumentor().instrument( + tracer_provider=tracer_provider + ) + + result = requests.get(self.URL) + self.assertEqual(result.text, "Hello!") + + span_list = exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + span = span_list[0] + + self.assertIs(span.resource, resource) diff --git a/tests/w3c_tracecontext_validation_server.py b/tests/w3c_tracecontext_validation_server.py index 7790fac12d9..3e4eb985d78 100644 --- a/tests/w3c_tracecontext_validation_server.py +++ b/tests/w3c_tracecontext_validation_server.py @@ -40,7 +40,7 @@ # frameworks and libraries that are used together, automatically creating # Spans and propagating context as appropriate. trace.set_tracer_provider(TracerProvider()) -http_requests.enable(trace.get_tracer_provider()) +http_requests.RequestsInstrumentor().instrument() # SpanExporter receives the spans and send them to the target location. span_processor = SimpleExportSpanProcessor(ConsoleSpanExporter()) diff --git a/tox.ini b/tox.ini index dc7f20aa8d1..ae5fa9805cb 100644 --- a/tox.ini +++ b/tox.ini @@ -146,6 +146,7 @@ commands_pre = example-app: pip install {toxinidir}/ext/opentelemetry-ext-flask example-app: pip install {toxinidir}/docs/examples/opentelemetry-example-app + example-http: pip install -e {toxinidir}/opentelemetry-auto-instrumentation example-http: pip install -e {toxinidir}/ext/opentelemetry-ext-http-requests example-http: pip install -e {toxinidir}/ext/opentelemetry-ext-wsgi example-http: pip install -r {toxinidir}/docs/examples/http/requirements.txt @@ -171,6 +172,7 @@ commands_pre = psycopg2: pip install {toxinidir}/ext/opentelemetry-ext-dbapi psycopg2: pip install {toxinidir}/ext/opentelemetry-ext-psycopg2 + http-requests: pip install {toxinidir}/opentelemetry-auto-instrumentation http-requests: pip install {toxinidir}/ext/opentelemetry-ext-http-requests[test] jaeger: pip install {toxinidir}/ext/opentelemetry-ext-jaeger @@ -254,9 +256,9 @@ deps = commands_pre = pip install -e {toxinidir}/opentelemetry-api \ -e {toxinidir}/opentelemetry-sdk \ + -e {toxinidir}/opentelemetry-auto-instrumentation \ -e {toxinidir}/ext/opentelemetry-ext-http-requests \ -e {toxinidir}/ext/opentelemetry-ext-wsgi \ - -e {toxinidir}/opentelemetry-auto-instrumentation \ -e {toxinidir}/ext/opentelemetry-ext-flask commands = From 35cd5483bddd2cf1c186d03f65ca01b01eabf38b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Mon, 20 Apr 2020 07:42:30 -0500 Subject: [PATCH 2/7] ext/requests: Set span status Set span status from http status code. --- .../ext/http_requests/__init__.py | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py index 16d4aeaa78d..d57a5c88310 100644 --- a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py +++ b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py @@ -51,6 +51,7 @@ from opentelemetry.auto_instrumentation.instrumentor import BaseInstrumentor from opentelemetry.ext.http_requests.version import __version__ from opentelemetry.trace import SpanKind, get_tracer_provider +from opentelemetry.trace.status import Status, StatusCanonicalCode _tracer = None @@ -109,12 +110,12 @@ def instrumented_request(self, method, url, *args, **kwargs): span.set_attribute("http.status_code", result.status_code) span.set_attribute("http.status_text", result.reason) + span.set_status( + Status(_http_status_to_canonical_code(result.status_code)) + ) return result - # TODO: How to handle exceptions? Should we create events for them? Set - # certain attributes? - instrumented_request.opentelemetry_ext_requests_applied = True Session.request = instrumented_request @@ -138,6 +139,37 @@ def _uninstrument(): _tracer = None +def _http_status_to_canonical_code(code: int, allow_redirect: bool = True): + # pylint:disable=too-many-branches,too-many-return-statements + if code < 100: + return StatusCanonicalCode.UNKNOWN + if code <= 299: + return StatusCanonicalCode.OK + if code <= 399: + if allow_redirect: + return StatusCanonicalCode.OK + return StatusCanonicalCode.DEADLINE_EXCEEDED + if code <= 499: + if code == 401: # HTTPStatus.UNAUTHORIZED: + return StatusCanonicalCode.UNAUTHENTICATED + if code == 403: # HTTPStatus.FORBIDDEN: + return StatusCanonicalCode.PERMISSION_DENIED + if code == 404: # HTTPStatus.NOT_FOUND: + return StatusCanonicalCode.NOT_FOUND + if code == 429: # HTTPStatus.TOO_MANY_REQUESTS: + return StatusCanonicalCode.RESOURCE_EXHAUSTED + return StatusCanonicalCode.INVALID_ARGUMENT + if code <= 599: + if code == 501: # HTTPStatus.NOT_IMPLEMENTED: + return StatusCanonicalCode.UNIMPLEMENTED + if code == 503: # HTTPStatus.SERVICE_UNAVAILABLE: + return StatusCanonicalCode.UNAVAILABLE + if code == 504: # HTTPStatus.GATEWAY_TIMEOUT: + return StatusCanonicalCode.DEADLINE_EXCEEDED + return StatusCanonicalCode.INTERNAL + return StatusCanonicalCode.UNKNOWN + + class RequestsInstrumentor(BaseInstrumentor): def _instrument(self, **kwargs): _instrument(tracer_provider=kwargs.get("tracer_provider")) From 16d9d1f263a56fbf131b3dda51f0c7cb545eff51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Tue, 21 Apr 2020 10:24:26 -0500 Subject: [PATCH 3/7] ext/requests: Implement some more tests --- .../tests/test_requests_integration.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py index 5e182a65c40..3cc0ac006a3 100644 --- a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py +++ b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py @@ -69,6 +69,26 @@ def test_basic(self): self.check_span_instrumentation_info(span, http_requests) + def test_not_foundbasic(self): + url_404 = "http://httpbin.org/status/404" + httpretty.register_uri( + httpretty.GET, url_404, status=404, + ) + result = requests.get(url_404) + self.assertEqual(result.status_code, 404) + + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + span = span_list[0] + + self.assertEqual(span.attributes.get("http.status_code"), 404) + self.assertEqual(span.attributes.get("http.status_text"), "Not Found") + + self.assertIs( + span.status.canonical_code, + trace.status.StatusCanonicalCode.NOT_FOUND, + ) + def test_invalid_url(self): url = "http://[::1/nope" exception_type = requests.exceptions.InvalidURL From 13950d0210cae5f418ca415c108cf6032c63015b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Fri, 24 Apr 2020 09:13:33 -0500 Subject: [PATCH 4/7] Remove workaround when tracer provider is not configured --- .../ext/http_requests/__init__.py | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py index d57a5c88310..fb8863ae47d 100644 --- a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py +++ b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py @@ -50,11 +50,9 @@ from opentelemetry import context, propagators, trace from opentelemetry.auto_instrumentation.instrumentor import BaseInstrumentor from opentelemetry.ext.http_requests.version import __version__ -from opentelemetry.trace import SpanKind, get_tracer_provider +from opentelemetry.trace import SpanKind, get_tracer from opentelemetry.trace.status import Status, StatusCanonicalCode -_tracer = None - # pylint: disable=unused-argument def _instrument(tracer_provider=None): @@ -71,6 +69,8 @@ def _instrument(tracer_provider=None): wrapped = Session.request + tracer = trace.get_tracer(__name__, __version__, tracer_provider) + @functools.wraps(wrapped) def instrumented_request(self, method, url, *args, **kwargs): if context.get_value("suppress_instrumentation"): @@ -86,20 +86,8 @@ def instrumented_request(self, method, url, *args, **kwargs): if parsed_url is None: path = "" path = parsed_url.path - # TODO: This is a workaround because currently the _instrument() - # method is called by the opentelemetry-auto-instrumentation command - # before configuring the SDK. This approach avoid getting a no-op - # tracer. - # pylint: disable=global-statement - global _tracer - if _tracer is None: - nonlocal tracer_provider - if tracer_provider is None: - tracer_provider = get_tracer_provider() - - _tracer = tracer_provider.get_tracer(__name__, __version__) - - with _tracer.start_as_current_span(path, kind=SpanKind.CLIENT) as span: + + with tracer.start_as_current_span(path, kind=SpanKind.CLIENT) as span: span.set_attribute("component", "http") span.set_attribute("http.method", method.upper()) span.set_attribute("http.url", url) @@ -131,12 +119,9 @@ def _uninstrument(): """Disables instrumentation of :code:`requests` through this module. Note that this only works if no other module also patches requests.""" - global _tracer - if getattr(Session.request, "opentelemetry_ext_requests_applied", False): original = Session.request.__wrapped__ # pylint:disable=no-member Session.request = original - _tracer = None def _http_status_to_canonical_code(code: int, allow_redirect: bool = True): From 60d53d52f181b36c5b27a9d17dbb85591183e767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Fri, 24 Apr 2020 10:49:26 -0500 Subject: [PATCH 5/7] update changelog --- ext/opentelemetry-ext-http-requests/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/opentelemetry-ext-http-requests/CHANGELOG.md b/ext/opentelemetry-ext-http-requests/CHANGELOG.md index 0e9be6e475a..a3f8a8f1fbd 100644 --- a/ext/opentelemetry-ext-http-requests/CHANGELOG.md +++ b/ext/opentelemetry-ext-http-requests/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Implement instrumentor interface ([#597](https://github.com/open-telemetry/opentelemetry-python/pull/597)) + ## 0.3a0 Released 2019-10-29 From 584f99dbe371e1dc958c48361833a077a26abc32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Mon, 27 Apr 2020 10:07:16 -0500 Subject: [PATCH 6/7] add comment about tracer provider --- .../src/opentelemetry_example_app/flask_example.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py index 98c97bd307e..1a9de310129 100644 --- a/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py +++ b/docs/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py @@ -28,6 +28,9 @@ SimpleExportSpanProcessor, ) +# The preferred tracer implementation must be set, as the opentelemetry-api +# defines the interface with a no-op implementation. +# It must be done before instrumenting any library trace.set_tracer_provider(TracerProvider()) opentelemetry.ext.http_requests.RequestsInstrumentor().instrument() From 7b7c9aad245366e6bcfea8a3295dbb97337ef37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Mon, 27 Apr 2020 10:08:45 -0500 Subject: [PATCH 7/7] update link to semantic conventions --- .../src/opentelemetry/ext/http_requests/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py index fb8863ae47d..9bb176dfd1e 100644 --- a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py +++ b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py @@ -77,7 +77,7 @@ def instrumented_request(self, method, url, *args, **kwargs): return wrapped(self, method, url, *args, **kwargs) # See - # https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md#http-client + # https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#http-client try: parsed_url = urlparse(url) except ValueError as exc: # Invalid URL