Remove Configuration from instrumentations (#285)

This commit is contained in:
Diego Hurtado
2021-02-04 10:02:37 -06:00
committed by GitHub
parent f0adb23143
commit 2fd68a2bf9
41 changed files with 359 additions and 110 deletions

View File

@ -6,7 +6,7 @@ on:
- 'release/*'
pull_request:
env:
CORE_REPO_SHA: f3ee81243b4266729ba5196a7883ce897549aaba
CORE_REPO_SHA: 09b010cfcc85e2aa07326e9204541b80a7dd52f0
jobs:
build:

View File

@ -79,6 +79,7 @@ disable=missing-docstring,
super-init-not-called, # temp-pylint-upgrade
invalid-overridden-method, # temp-pylint-upgrade
missing-module-docstring, # temp-pylint-upgrade
import-error, # needed as a workaround as reported here: https://github.com/open-telemetry/opentelemetry-python-contrib/issues/290
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option

View File

@ -75,6 +75,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update TraceState to adhere to specs
([#276](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/276))
### Removed
- Remove Configuration
([#285](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/285))
## [0.16b1](https://github.com/open-telemetry/opentelemetry-python-contrib/releases/tag/v0.16b1) - 2020-11-26
## [0.16b0](https://github.com/open-telemetry/opentelemetry-python-contrib/releases/tag/v0.16b0) - 2020-11-25

View File

@ -4,7 +4,6 @@ class_references=
opentelemetry.trace.propagation.textmap.TextMapPropagator
; - AwsXRayFormat
opentelemetry.trace.propagation.textmap.DictGetter
; - instrumentation.asgi.CarrierGetter
; API
opentelemetry.trace.propagation.textmap.Getter
; - DatadogFormat

View File

@ -7,6 +7,7 @@ ignore=
opentelemetry-python-core
sortfirst=
util/opentelemetry-util-http
instrumentation/opentelemetry-instrumentation-wsgi
instrumentation/opentelemetry-instrumentation-dbapi
instrumentation/opentelemetry-instrumentation-asgi

View File

@ -18,7 +18,6 @@ on any ASGI framework (such as Django-channels / Quart) to track requests
timing through OpenTelemetry.
"""
import operator
import typing
import urllib
from functools import wraps

View File

@ -84,8 +84,6 @@ class BotoInstrumentor(BaseInstrumentor):
# For exemple EC2 uses AWSQueryConnection and S3 uses
# AWSAuthConnection
# FIXME should the tracer provider be accessed via Configuration
# instead?
# pylint: disable=attribute-defined-outside-init
self._tracer = get_tracer(
__name__, __version__, kwargs.get("tracer_provider")

View File

@ -40,6 +40,7 @@ package_dir=
packages=find_namespace:
install_requires =
django >= 1.10
opentelemetry-util-http == 0.18.dev0
opentelemetry-instrumentation-wsgi == 0.18.dev0
opentelemetry-instrumentation == 0.18.dev0
opentelemetry-api == 0.18.dev0

View File

@ -13,10 +13,13 @@
# limitations under the License.
from logging import getLogger
from os import environ
from django.conf import settings
from opentelemetry.configuration import Configuration
from opentelemetry.instrumentation.django.environment_variables import (
OTEL_PYTHON_DJANGO_INSTRUMENT,
)
from opentelemetry.instrumentation.django.middleware import _DjangoMiddleware
from opentelemetry.instrumentation.django.version import __version__
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
@ -43,11 +46,7 @@ class DjangoInstrumentor(BaseInstrumentor, MetricMixin):
# FIXME this is probably a pattern that will show up in the rest of the
# ext. Find a better way of implementing this.
# FIXME Probably the evaluation of strings into boolean values can be
# built inside the Configuration class itself with the magic method
# __bool__
if Configuration().DJANGO_INSTRUMENT is False:
if environ.get(OTEL_PYTHON_DJANGO_INSTRUMENT) == "False":
return
# This can not be solved, but is an inherent problem of this approach:

View File

@ -0,0 +1,15 @@
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
OTEL_PYTHON_DJANGO_INSTRUMENT = "OTEL_PYTHON_DJANGO_INSTRUMENT"

View File

@ -12,12 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import time
from logging import getLogger
from time import time
from django.conf import settings
from opentelemetry.configuration import Configuration
from opentelemetry.context import attach, detach
from opentelemetry.instrumentation.django.version import __version__
from opentelemetry.instrumentation.utils import extract_attributes_from_object
@ -28,6 +27,7 @@ from opentelemetry.instrumentation.wsgi import (
)
from opentelemetry.propagators import extract
from opentelemetry.trace import SpanKind, get_tracer
from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs
try:
from django.core.urlresolvers import ( # pylint: disable=no-name-in-module
@ -61,9 +61,8 @@ class _DjangoMiddleware(MiddlewareMixin):
_environ_span_key = "opentelemetry-instrumentor-django.span_key"
_environ_exception_key = "opentelemetry-instrumentor-django.exception_key"
_excluded_urls = Configuration()._excluded_urls("django")
_traced_request_attrs = Configuration()._traced_request_attrs("django")
_traced_request_attrs = get_traced_request_attrs("DJANGO")
_excluded_urls = get_excluded_urls("DJANGO")
@staticmethod
def _get_span_name(request):
@ -111,23 +110,23 @@ class _DjangoMiddleware(MiddlewareMixin):
return
# pylint:disable=W0212
request._otel_start_time = time.time()
request._otel_start_time = time()
environ = request.META
request_meta = request.META
token = attach(extract(carrier_getter, environ))
token = attach(extract(carrier_getter, request_meta))
tracer = get_tracer(__name__, __version__)
span = tracer.start_span(
self._get_span_name(request),
kind=SpanKind.SERVER,
start_time=environ.get(
start_time=request_meta.get(
"opentelemetry-instrumentor-django.starttime_key"
),
)
attributes = collect_request_attributes(environ)
attributes = collect_request_attributes(request_meta)
# pylint:disable=W0212
request._otel_labels = self._get_metric_labels_from_attributes(
attributes
@ -215,7 +214,7 @@ class _DjangoMiddleware(MiddlewareMixin):
if metric_recorder is not None:
# pylint:disable=W0212
metric_recorder.record_server_duration_range(
request._otel_start_time, time.time(), request._otel_labels
request._otel_start_time, time(), request._otel_labels
)
except Exception as ex: # pylint: disable=W0703
_logger.warning("Error recording duration metrics: %s", ex)

View File

@ -21,13 +21,13 @@ from django.conf.urls import url
from django.test import Client
from django.test.utils import setup_test_environment, teardown_test_environment
from opentelemetry.configuration import Configuration
from opentelemetry.instrumentation.django import DjangoInstrumentor
from opentelemetry.sdk.util import get_dict_as_key
from opentelemetry.test.test_base import TestBase
from opentelemetry.test.wsgitestutil import WsgiTestBase
from opentelemetry.trace import SpanKind
from opentelemetry.trace.status import StatusCode
from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs
# pylint: disable=import-error
from .views import (
@ -64,7 +64,6 @@ class TestMiddleware(TestBase, WsgiTestBase):
super().setUp()
setup_test_environment()
_django_instrumentor.instrument()
Configuration._reset() # pylint: disable=protected-access
self.env_patch = patch.dict(
"os.environ",
{
@ -75,11 +74,11 @@ class TestMiddleware(TestBase, WsgiTestBase):
self.env_patch.start()
self.exclude_patch = patch(
"opentelemetry.instrumentation.django.middleware._DjangoMiddleware._excluded_urls",
Configuration()._excluded_urls("django"),
get_excluded_urls("DJANGO"),
)
self.traced_patch = patch(
"opentelemetry.instrumentation.django.middleware._DjangoMiddleware._traced_request_attrs",
Configuration()._traced_request_attrs("django"),
get_traced_request_attrs("DJANGO"),
)
self.exclude_patch.start()
self.traced_patch.start()

View File

@ -42,6 +42,7 @@ packages=find_namespace:
install_requires =
falcon ~= 2.0
opentelemetry-instrumentation-wsgi == 0.18.dev0
opentelemetry-util-http == 0.18.dev0
opentelemetry-instrumentation == 0.18.dev0
opentelemetry-api == 0.18.dev0

View File

@ -43,14 +43,13 @@ API
---
"""
import sys
from logging import getLogger
from sys import exc_info
import falcon
import opentelemetry.instrumentation.wsgi as otel_wsgi
from opentelemetry import configuration, context, propagators, trace
from opentelemetry.configuration import Configuration
from opentelemetry import context, propagators, trace
from opentelemetry.instrumentation.falcon.version import __version__
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.utils import (
@ -59,6 +58,7 @@ from opentelemetry.instrumentation.utils import (
)
from opentelemetry.trace.status import Status
from opentelemetry.util import time_ns
from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs
_logger = getLogger(__name__)
@ -68,8 +68,9 @@ _ENVIRON_ACTIVATION_KEY = "opentelemetry-falcon.activation_key"
_ENVIRON_TOKEN = "opentelemetry-falcon.token"
_ENVIRON_EXC = "opentelemetry-falcon.exc"
cfg = configuration.Configuration()
_excluded_urls = cfg._excluded_urls("falcon")
_excluded_urls = get_excluded_urls("FALCON")
_traced_request_attrs = get_traced_request_attrs("FALCON")
class FalconInstrumentor(BaseInstrumentor):
@ -149,7 +150,7 @@ class _TraceMiddleware:
def __init__(self, tracer=None, traced_request_attrs=None):
self.tracer = tracer
self._traced_request_attrs = cfg._traced_request_attrs("falcon")
self._traced_request_attrs = _traced_request_attrs
def process_request(self, req, resp):
span = req.env.get(_ENVIRON_SPAN_KEY)
@ -186,7 +187,7 @@ class _TraceMiddleware:
status = "404"
reason = "NotFound"
exc_type, exc, _ = sys.exc_info()
exc_type, exc, _ = exc_info()
if exc_type and not req_succeeded:
if "HTTPNotFound" in exc_type.__name__:
status = "404"

View File

@ -16,10 +16,10 @@ from unittest.mock import Mock, patch
from falcon import testing
from opentelemetry.configuration import Configuration
from opentelemetry.instrumentation.falcon import FalconInstrumentor
from opentelemetry.test.test_base import TestBase
from opentelemetry.trace.status import StatusCode
from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs
from .app import make_app
@ -30,7 +30,6 @@ class TestFalconInstrumentation(TestBase):
FalconInstrumentor().instrument()
self.app = make_app()
# pylint: disable=protected-access
Configuration()._reset()
self.env_patch = patch.dict(
"os.environ",
{
@ -41,7 +40,7 @@ class TestFalconInstrumentation(TestBase):
self.env_patch.start()
self.exclude_patch = patch(
"opentelemetry.instrumentation.falcon._excluded_urls",
Configuration()._excluded_urls("falcon"),
get_excluded_urls("FALCON"),
)
middleware = self.app._middleware[0][ # pylint:disable=W0212
0
@ -49,7 +48,7 @@ class TestFalconInstrumentation(TestBase):
self.traced_patch = patch.object(
middleware,
"_traced_request_attrs",
Configuration()._traced_request_attrs("falcon"),
get_traced_request_attrs("FALCON"),
)
self.exclude_patch.start()
self.traced_patch.start()

View File

@ -40,6 +40,7 @@ packages=find_namespace:
install_requires =
opentelemetry-api == 0.18.dev0
opentelemetry-instrumentation-asgi == 0.18.dev0
opentelemetry-util-http == 0.18.dev0
[options.entry_points]
opentelemetry_instrumentor =

View File

@ -11,17 +11,15 @@
# 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.
from typing import Optional
import fastapi
from starlette.routing import Match
from opentelemetry.configuration import Configuration
from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
from opentelemetry.instrumentation.fastapi.version import __version__ # noqa
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.util.http import get_excluded_urls
_excluded_urls = Configuration()._excluded_urls("fastapi")
_excluded_urls = get_excluded_urls("FASTAPI")
class FastAPIInstrumentor(BaseInstrumentor):

View File

@ -19,8 +19,8 @@ import fastapi
from fastapi.testclient import TestClient
import opentelemetry.instrumentation.fastapi as otel_fastapi
from opentelemetry.configuration import Configuration
from opentelemetry.test.test_base import TestBase
from opentelemetry.util.http import get_excluded_urls
class TestFastAPIManualInstrumentation(TestBase):
@ -31,7 +31,6 @@ class TestFastAPIManualInstrumentation(TestBase):
def setUp(self):
super().setUp()
Configuration()._reset()
self.env_patch = patch.dict(
"os.environ",
{"OTEL_PYTHON_FASTAPI_EXCLUDED_URLS": "/exclude/123,healthzz"},
@ -39,7 +38,7 @@ class TestFastAPIManualInstrumentation(TestBase):
self.env_patch.start()
self.exclude_patch = patch(
"opentelemetry.instrumentation.fastapi._excluded_urls",
Configuration()._excluded_urls("fastapi"),
get_excluded_urls("FASTAPI"),
)
self.exclude_patch.start()
self._instrumentor = otel_fastapi.FastAPIInstrumentor()

View File

@ -40,8 +40,9 @@ package_dir=
packages=find_namespace:
install_requires =
flask ~= 1.0
opentelemetry-instrumentation-wsgi == 0.18.dev0
opentelemetry-util-http == 0.18.dev0
opentelemetry-instrumentation == 0.18.dev0
opentelemetry-instrumentation-wsgi == 0.18.dev0
opentelemetry-api == 0.18.dev0
[options.extras_require]

View File

@ -17,8 +17,8 @@
"""
This library builds on the OpenTelemetry WSGI middleware to track web requests
in Flask applications. In addition to opentelemetry-instrumentation-wsgi, it supports
flask-specific features such as:
in Flask applications. In addition to opentelemetry-util-http, it
supports Flask-specific features such as:
* The Flask url rule pattern is used as the Span name.
* The ``http.route`` Span attribute is set so that one can see which URL rule
@ -52,10 +52,11 @@ from logging import getLogger
import flask
import opentelemetry.instrumentation.wsgi as otel_wsgi
from opentelemetry import configuration, context, propagators, trace
from opentelemetry import context, propagators, trace
from opentelemetry.instrumentation.flask.version import __version__
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.util import time_ns
from opentelemetry.util.http import get_excluded_urls
_logger = getLogger(__name__)
@ -65,7 +66,7 @@ _ENVIRON_ACTIVATION_KEY = "opentelemetry-flask.activation_key"
_ENVIRON_TOKEN = "opentelemetry-flask.token"
_excluded_urls = configuration.Configuration()._excluded_urls("flask")
_excluded_urls = get_excluded_urls("FLASK")
def get_default_span_name():
@ -78,12 +79,12 @@ def get_default_span_name():
def _rewrapped_app(wsgi_app):
def _wrapped_app(environ, start_response):
def _wrapped_app(wrapped_app_environ, start_response):
# We want to measure the time for route matching, etc.
# In theory, we could start the span here and use
# update_name later but that API is "highly discouraged" so
# we better avoid it.
environ[_ENVIRON_STARTTIME_KEY] = time_ns()
wrapped_app_environ[_ENVIRON_STARTTIME_KEY] = time_ns()
def _start_response(status, response_headers, *args, **kwargs):
if not _excluded_urls.url_disabled(flask.request.url):
@ -102,7 +103,7 @@ def _rewrapped_app(wsgi_app):
return start_response(status, response_headers, *args, **kwargs)
return wsgi_app(environ, _start_response)
return wsgi_app(wrapped_app_environ, _start_response)
return _wrapped_app
@ -112,10 +113,12 @@ def _wrapped_before_request(name_callback):
if _excluded_urls.url_disabled(flask.request.url):
return
environ = flask.request.environ
flask_request_environ = flask.request.environ
span_name = name_callback()
token = context.attach(
propagators.extract(otel_wsgi.carrier_getter, environ)
propagators.extract(
otel_wsgi.carrier_getter, flask_request_environ
)
)
tracer = trace.get_tracer(__name__, __version__)
@ -123,10 +126,12 @@ def _wrapped_before_request(name_callback):
span = tracer.start_span(
span_name,
kind=trace.SpanKind.SERVER,
start_time=environ.get(_ENVIRON_STARTTIME_KEY),
start_time=flask_request_environ.get(_ENVIRON_STARTTIME_KEY),
)
if span.is_recording():
attributes = otel_wsgi.collect_request_attributes(environ)
attributes = otel_wsgi.collect_request_attributes(
flask_request_environ
)
if flask.request.url_rule:
# For 404 that result from no route found, etc, we
# don't have a url_rule.
@ -136,9 +141,9 @@ def _wrapped_before_request(name_callback):
activation = tracer.use_span(span, end_on_exit=True)
activation.__enter__()
environ[_ENVIRON_ACTIVATION_KEY] = activation
environ[_ENVIRON_SPAN_KEY] = span
environ[_ENVIRON_TOKEN] = token
flask_request_environ[_ENVIRON_ACTIVATION_KEY] = activation
flask_request_environ[_ENVIRON_SPAN_KEY] = span
flask_request_environ[_ENVIRON_TOKEN] = token
return _before_request

View File

@ -15,14 +15,8 @@
from werkzeug.test import Client
from werkzeug.wrappers import BaseResponse
from opentelemetry.configuration import Configuration
class InstrumentationTest:
def setUp(self): # pylint: disable=invalid-name
super().setUp() # pylint: disable=no-member
Configuration._reset() # pylint: disable=protected-access
@staticmethod
def _hello_endpoint(helloid):
if helloid == 500:

View File

@ -17,10 +17,10 @@ from unittest.mock import Mock, patch
from flask import Flask, request
from opentelemetry import trace
from opentelemetry.configuration import Configuration
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.test.test_base import TestBase
from opentelemetry.test.wsgitestutil import WsgiTestBase
from opentelemetry.util.http import get_excluded_urls
# pylint: disable=import-error
from .base_test import InstrumentationTest
@ -62,7 +62,7 @@ class TestProgrammatic(InstrumentationTest, TestBase, WsgiTestBase):
self.env_patch.start()
self.exclude_patch = patch(
"opentelemetry.instrumentation.flask._excluded_urls",
Configuration()._excluded_urls("flask"),
get_excluded_urls("FLASK"),
)
self.exclude_patch.start()

View File

@ -22,6 +22,9 @@ SERVER_ID = 1
class TestServer(test_server_pb2_grpc.GRPCTestServerServicer):
# pylint: disable=invalid-name
# pylint: disable=no-self-use
def SimpleMethod(self, request, context):
if request.request_data == "error":
context.set_code(grpc.StatusCode.INVALID_ARGUMENT)

View File

@ -13,7 +13,9 @@
# limitations under the License.
import grpc
from tests.protobuf import test_server_pb2_grpc
from tests.protobuf import ( # pylint: disable=no-name-in-module
test_server_pb2_grpc,
)
import opentelemetry.instrumentation.grpc
from opentelemetry import trace

View File

@ -43,6 +43,7 @@ install_requires =
opentelemetry-instrumentation == 0.18.dev0
opentelemetry-api == 0.18.dev0
opentelemetry-instrumentation-wsgi == 0.18.dev0
opentelemetry-util-http == 0.18.dev0
wrapt >= 1.0.0, < 2.0.0
[options.extras_require]

View File

@ -6,9 +6,10 @@ from pyramid.settings import asbool
from pyramid.tweens import EXCVIEW
import opentelemetry.instrumentation.wsgi as otel_wsgi
from opentelemetry import configuration, context, propagators, trace
from opentelemetry import context, propagators, trace
from opentelemetry.instrumentation.pyramid.version import __version__
from opentelemetry.util import time_ns
from opentelemetry.util.http import get_excluded_urls
TWEEN_NAME = "opentelemetry.instrumentation.pyramid.trace_tween_factory"
SETTING_TRACE_ENABLED = "opentelemetry-pyramid.trace_enabled"
@ -22,7 +23,7 @@ _ENVIRON_TOKEN = "opentelemetry-pyramid.token"
_logger = getLogger(__name__)
_excluded_urls = configuration.Configuration()._excluded_urls("pyramid")
_excluded_urls = get_excluded_urls("PYRAMID")
def includeme(config):
@ -44,10 +45,10 @@ def _insert_tween(config):
def _before_traversal(event):
request = event.request
environ = request.environ
span_name = otel_wsgi.get_default_span_name(environ)
request_environ = request.environ
span_name = otel_wsgi.get_default_span_name(request_environ)
enabled = environ.get(_ENVIRON_ENABLED_KEY)
enabled = request_environ.get(_ENVIRON_ENABLED_KEY)
if enabled is None:
_logger.warning(
"Opentelemetry pyramid tween 'opentelemetry.instrumentation.pyramid.trace_tween_factory'"
@ -60,24 +61,24 @@ def _before_traversal(event):
# Tracing not enabled, return
return
start_time = environ.get(_ENVIRON_STARTTIME_KEY)
start_time = request_environ.get(_ENVIRON_STARTTIME_KEY)
token = context.attach(
propagators.extract(otel_wsgi.carrier_getter, environ)
propagators.extract(otel_wsgi.carrier_getter, request_environ)
)
tracer = trace.get_tracer(__name__, __version__)
if request.matched_route:
span_name = request.matched_route.pattern
else:
span_name = otel_wsgi.get_default_span_name(environ)
span_name = otel_wsgi.get_default_span_name(request_environ)
span = tracer.start_span(
span_name, kind=trace.SpanKind.SERVER, start_time=start_time,
)
if span.is_recording():
attributes = otel_wsgi.collect_request_attributes(environ)
attributes = otel_wsgi.collect_request_attributes(request_environ)
if request.matched_route:
attributes["http.route"] = request.matched_route.pattern
for key, value in attributes.items():
@ -85,9 +86,9 @@ def _before_traversal(event):
activation = tracer.use_span(span, end_on_exit=True)
activation.__enter__()
environ[_ENVIRON_ACTIVATION_KEY] = activation
environ[_ENVIRON_SPAN_KEY] = span
environ[_ENVIRON_TOKEN] = token
request_environ[_ENVIRON_ACTIVATION_KEY] = activation
request_environ[_ENVIRON_SPAN_KEY] = span
request_environ[_ENVIRON_TOKEN] = token
def trace_tween_factory(handler, registry):

View File

@ -17,14 +17,8 @@ from pyramid.response import Response
from werkzeug.test import Client
from werkzeug.wrappers import BaseResponse
from opentelemetry.configuration import Configuration
class InstrumentationTest:
def setUp(self): # pylint: disable=invalid-name
super().setUp() # pylint: disable=no-member
Configuration._reset() # pylint: disable=protected-access
@staticmethod
def _hello_endpoint(request):
helloid = int(request.matchdict["helloid"])

View File

@ -17,10 +17,10 @@ from unittest.mock import Mock, patch
from pyramid.config import Configurator
from opentelemetry import trace
from opentelemetry.configuration import Configuration
from opentelemetry.instrumentation.pyramid import PyramidInstrumentor
from opentelemetry.test.test_base import TestBase
from opentelemetry.test.wsgitestutil import WsgiTestBase
from opentelemetry.util.http import get_excluded_urls
# pylint: disable=import-error
from .pyramid_base_test import InstrumentationTest
@ -62,7 +62,7 @@ class TestProgrammatic(InstrumentationTest, TestBase, WsgiTestBase):
self.env_patch.start()
self.exclude_patch = patch(
"opentelemetry.instrumentation.pyramid.callbacks._excluded_urls",
Configuration()._excluded_urls("pyramid"),
get_excluded_urls("PYRAMID"),
)
self.exclude_patch.start()

View File

@ -40,6 +40,7 @@ packages=find_namespace:
install_requires =
opentelemetry-api == 0.18.dev0
opentelemetry-instrumentation-asgi == 0.18.dev0
opentelemetry-util-http == 0.18.dev0
[options.entry_points]
opentelemetry_instrumentor =

View File

@ -11,17 +11,15 @@
# 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.
from typing import Optional
from starlette import applications
from starlette.routing import Match
from opentelemetry.configuration import Configuration
from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.starlette.version import __version__ # noqa
from opentelemetry.util.http import get_excluded_urls
_excluded_urls = Configuration()._excluded_urls("starlette")
_excluded_urls = get_excluded_urls("STARLETTE")
class StarletteInstrumentor(BaseInstrumentor):

View File

@ -21,8 +21,8 @@ from starlette.routing import Route
from starlette.testclient import TestClient
import opentelemetry.instrumentation.starlette as otel_starlette
from opentelemetry.configuration import Configuration
from opentelemetry.test.test_base import TestBase
from opentelemetry.util.http import get_excluded_urls
class TestStarletteManualInstrumentation(TestBase):
@ -33,7 +33,6 @@ class TestStarletteManualInstrumentation(TestBase):
def setUp(self):
super().setUp()
Configuration()._reset()
self.env_patch = patch.dict(
"os.environ",
{"OTEL_PYTHON_STARLETTE_EXCLUDED_URLS": "/exclude/123,healthzz"},
@ -41,7 +40,7 @@ class TestStarletteManualInstrumentation(TestBase):
self.env_patch.start()
self.exclude_patch = patch(
"opentelemetry.instrumentation.starlette._excluded_urls",
Configuration()._excluded_urls("starlette"),
get_excluded_urls("STARLETTE"),
)
self.exclude_patch.start()
self._instrumentor = otel_starlette.StarletteInstrumentor()

View File

@ -41,6 +41,7 @@ install_requires =
tornado >= 6.0
opentelemetry-instrumentation == 0.18.dev0
opentelemetry-api == 0.18.dev0
opentelemetry-util-http == 0.18.dev0
[options.extras_require]
test =

View File

@ -35,18 +35,15 @@ Usage
tornado.ioloop.IOLoop.current().start()
"""
import inspect
import typing
from collections import namedtuple
from functools import partial, wraps
from functools import partial
from logging import getLogger
import tornado.web
import wrapt
from tornado.routing import Rule
from wrapt import wrap_function_wrapper
from opentelemetry import configuration, context, propagators, trace
from opentelemetry import context, propagators, trace
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.tornado.version import __version__
from opentelemetry.instrumentation.utils import (
@ -57,6 +54,7 @@ from opentelemetry.instrumentation.utils import (
from opentelemetry.trace.propagation.textmap import DictGetter
from opentelemetry.trace.status import Status
from opentelemetry.util import time_ns
from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs
from .client import fetch_async # pylint: disable=E0401
@ -65,10 +63,9 @@ _TraceContext = namedtuple("TraceContext", ["activation", "span", "token"])
_HANDLER_CONTEXT_KEY = "_otel_trace_context_key"
_OTEL_PATCHED_KEY = "_otel_patched_key"
cfg = configuration.Configuration()
_excluded_urls = cfg._excluded_urls("tornado")
_traced_attrs = cfg._traced_request_attrs("tornado")
_excluded_urls = get_excluded_urls("TORNADO")
_traced_request_attrs = get_traced_request_attrs("TORNADO")
carrier_getter = DictGetter()
@ -186,7 +183,9 @@ def _get_attributes_from_request(request):
if request.remote_ip:
attrs["net.peer.ip"] = request.remote_ip
return extract_attributes_from_object(request, _traced_attrs, attrs)
return extract_attributes_from_object(
request, _traced_request_attrs, attrs
)
def _get_operation_name(handler, request):

View File

@ -18,7 +18,6 @@ from unittest.mock import Mock, patch
from tornado.testing import AsyncHTTPTestCase
from opentelemetry import trace
from opentelemetry.configuration import Configuration
from opentelemetry.instrumentation.tornado import (
TornadoInstrumentor,
patch_handler_class,
@ -26,6 +25,7 @@ from opentelemetry.instrumentation.tornado import (
)
from opentelemetry.test.test_base import TestBase
from opentelemetry.trace import SpanKind
from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs
from .tornado_test_app import (
AsyncHandler,
@ -45,7 +45,6 @@ class TornadoTest(AsyncHTTPTestCase, TestBase):
TornadoInstrumentor().instrument()
super().setUp()
# pylint: disable=protected-access
Configuration()._reset()
self.env_patch = patch.dict(
"os.environ",
{
@ -56,11 +55,11 @@ class TornadoTest(AsyncHTTPTestCase, TestBase):
self.env_patch.start()
self.exclude_patch = patch(
"opentelemetry.instrumentation.tornado._excluded_urls",
Configuration()._excluded_urls("tornado"),
get_excluded_urls("TORNADO"),
)
self.traced_patch = patch(
"opentelemetry.instrumentation.tornado._traced_attrs",
Configuration()._traced_request_attrs("tornado"),
"opentelemetry.instrumentation.tornado._traced_request_attrs",
get_traced_request_attrs("TORNADO"),
)
self.exclude_patch.start()
self.traced_patch.start()

16
tox.ini
View File

@ -138,6 +138,10 @@ envlist =
py3{5,6,7,8}-test-instrumentation-tornado
pypy3-test-instrumentation-tornado
; opentelemetry-util-http
py3{5,6,7,8}-test-util-http
pypy3-test-util-http
lint
docker-tests
docs
@ -193,6 +197,7 @@ changedir =
test-instrumentation-system-metrics: instrumentation/opentelemetry-instrumentation-system-metrics/tests
test-instrumentation-tornado: instrumentation/opentelemetry-instrumentation-tornado/tests
test-instrumentation-wsgi: instrumentation/opentelemetry-instrumentation-wsgi/tests
test-util-http: util/opentelemetry-util-http/tests
test-sdkextension-aws: sdk-extension/opentelemetry-sdk-extension-aws/tests
test-exporter-datadog: exporter/opentelemetry-exporter-datadog/tests
@ -211,6 +216,7 @@ commands_pre =
grpc: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-grpc[test]
falcon,flask,django,pyramid,tornado,starlette,fastapi: pip install {toxinidir}/util/opentelemetry-util-http
wsgi,falcon,flask,django,pyramid: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi
asgi,starlette,fastapi: pip install {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi
@ -274,7 +280,8 @@ commands_pre =
aws: pip install requests {toxinidir}/sdk-extension/opentelemetry-sdk-extension-aws
; In order to get a healthy coverage report,
http: pip install {toxinidir}/util/opentelemetry-util-http
; In order to get a health coverage report,
; we have to install packages in editable mode.
coverage: python {toxinidir}/scripts/eachdist.py install --editable
@ -288,6 +295,12 @@ deps =
-r {toxinidir}/docs-requirements.txt
pytest
commands_pre =
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-api
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-sdk
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-instrumentation
python -m pip install {toxinidir}/util/opentelemetry-util-http
changedir = docs
commands =
@ -314,6 +327,7 @@ commands_pre =
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-instrumentation
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-sdk
python -m pip install {toxinidir}/opentelemetry-python-core/tests/util
python -m pip install {toxinidir}/util/opentelemetry-util-http
python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-wsgi[test]
python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-dbapi[test]
python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-asgi[test]

View File

@ -0,0 +1,72 @@
OpenTelemetry Util HTTP
=======================
|pypi|
.. |pypi| image:: https://badge.fury.io/py/opentelemetry-util-http.svg
:target: https://pypi.org/project/opentelemetry-util-http/
This library provides ASGI, WSGI middleware and other HTTP-related
functionality that is common to instrumented web frameworks (such as Django,
Starlette, FastAPI, etc.) to track requests timing through OpenTelemetry.
Installation
------------
::
pip install opentelemetry-util-http
Usage (Quart)
-------------
.. code-block:: python
from quart import Quart
from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
app = Quart(__name__)
app.asgi_app = OpenTelemetryMiddleware(app.asgi_app)
@app.route("/")
async def hello():
return "Hello!"
if __name__ == "__main__":
app.run(debug=True)
Usage (Django 3.0)
------------------
Modify the application's ``asgi.py`` file as shown below.
.. code-block:: python
import os
from django.core.asgi import get_asgi_application
from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'asgi_example.settings')
application = get_asgi_application()
application = OpenTelemetryMiddleware(application)
Usage (Raw ASGI)
----------------
.. code-block:: python
from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
app = ... # An ASGI application.
app = OpenTelemetryMiddleware(app)
References
----------
* `OpenTelemetry Project <https://opentelemetry.io/>`_

View File

@ -0,0 +1,51 @@
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
#
[metadata]
name = opentelemetry-util-http
description = Web util for OpenTelemetry
long_description = file: README.rst
long_description_content_type = text/x-rst
author = OpenTelemetry Authors
author_email = cncf-opentelemetry-contributors@lists.cncf.io
url = https://github.com/open-telemetry/opentelemetry-python-contrib/util/opentelemetry-util-http
platforms = any
license = Apache-2.0
classifiers =
Development Status :: 4 - Beta
Intended Audience :: Developers
License :: OSI Approved :: Apache Software License
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
[options]
python_requires = >=3.5
package_dir=
=src
packages=find_namespace:
install_requires =
opentelemetry-api == 0.18.dev0
opentelemetry-instrumentation == 0.18.dev0
asgiref ~= 3.0
[options.extras_require]
test =
opentelemetry-test == 0.18.dev0
[options.packages.find]
where = src

View File

@ -0,0 +1,26 @@
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
import os
import setuptools
BASE_DIR = os.path.dirname(__file__)
VERSION_FILENAME = os.path.join(
BASE_DIR, "src", "opentelemetry", "util", "http", "version.py"
)
PACKAGE_INFO = {}
with open(VERSION_FILENAME) as f:
exec(f.read(), PACKAGE_INFO)
setuptools.setup(version=PACKAGE_INFO["__version__"])

View File

@ -0,0 +1,59 @@
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
from os import environ
from re import compile as re_compile
from re import search
class ExcludeList:
"""Class to exclude certain paths (given as a list of regexes) from tracing requests"""
def __init__(self, excluded_urls):
self._excluded_urls = excluded_urls
if self._excluded_urls:
self._regex = re_compile("|".join(excluded_urls))
def url_disabled(self, url: str) -> bool:
return bool(self._excluded_urls and search(self._regex, url))
_root = r"OTEL_PYTHON_{}"
def get_traced_request_attrs(instrumentation):
traced_request_attrs = environ.get(
_root.format("{}_TRACED_REQUEST_ATTRS".format(instrumentation)), []
)
if traced_request_attrs:
traced_request_attrs = [
traced_request_attr.strip()
for traced_request_attr in traced_request_attrs.split(",")
]
return traced_request_attrs
def get_excluded_urls(instrumentation):
excluded_urls = environ.get(
_root.format("{}_EXCLUDED_URLS".format(instrumentation)), []
)
if excluded_urls:
excluded_urls = [
excluded_url.strip() for excluded_url in excluded_urls.split(",")
]
return ExcludeList(excluded_urls)

View File

@ -0,0 +1,15 @@
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
__version__ = "0.18.dev0"