From 3a0a966b11e3588ecdc34c7d3586d10060ef9f59 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Mon, 9 Mar 2020 18:50:50 -0600 Subject: [PATCH 01/28] Add configuration manager --- docs/api/api.rst | 1 - docs/api/util.loader.rst | 4 - docs/examples/basic_tracer/tracer.py | 7 +- docs/examples/http/server.py | 8 +- docs/examples/http/tests/test_http.py | 10 +- docs/examples/http/tracer_client.py | 6 +- docs/examples/metrics/observer_example.py | 3 +- docs/examples/metrics/prometheus.py | 3 +- docs/examples/metrics/record.py | 5 +- docs/examples/metrics/simple_example.py | 3 +- .../flask_example.py | 9 +- docs/examples/opentracing/main.py | 5 +- examples/basic_tracer/tests/conftest.py | 25 +++ examples/http/tests/conftest.py | 25 +++ .../tests/conftest.py | 25 +++ ext/opentelemetry-ext-dbapi/README.rst | 1 - ext/opentelemetry-ext-flask/tests/conftest.py | 25 +++ ext/opentelemetry-ext-jaeger/README.rst | 2 - .../examples/jaeger_exporter_example.py | 4 +- .../ext/opentracing_shim/__init__.py | 4 - .../tests/conftest.py | 25 +++ .../tests/test_shim.py | 11 +- ext/opentelemetry-ext-prometheus/README.rst | 3 +- .../tests/conftest.py | 25 +++ .../tests/test_prometheus_exporter.py | 8 +- ext/opentelemetry-ext-psycopg2/README.rst | 2 - .../ext/testutil/wsgitestutil.py | 7 +- ext/opentelemetry-ext-wsgi/tests/conftest.py | 25 +++ ext/opentelemetry-ext-zipkin/README.rst | 2 - opentelemetry-api/setup.py | 44 ++++- .../opentelemetry/configuration/__init__.py | 78 ++++++++ .../configuration/opentelemetry_python.json | 4 + .../src/opentelemetry/configuration/py.typed | 0 .../src/opentelemetry/metrics/__init__.py | 77 +++----- .../src/opentelemetry/trace/__init__.py | 83 +++----- .../src/opentelemetry/util/loader.py | 182 ------------------ .../tests/configuration/__init__.py | 0 .../tests/configuration/test_configuration.py | 85 ++++++++ opentelemetry-api/tests/mypysmoke.py | 2 +- opentelemetry-api/tests/test_loader.py | 112 ----------- opentelemetry-api/tests/trace/test_globals.py | 36 +--- opentelemetry-sdk/setup.py | 8 + tests/w3c_tracecontext_validation_server.py | 9 +- 43 files changed, 477 insertions(+), 526 deletions(-) delete mode 100644 docs/api/util.loader.rst create mode 100644 examples/basic_tracer/tests/conftest.py create mode 100644 examples/http/tests/conftest.py create mode 100644 examples/opentelemetry-example-app/tests/conftest.py create mode 100644 ext/opentelemetry-ext-flask/tests/conftest.py create mode 100644 ext/opentelemetry-ext-opentracing-shim/tests/conftest.py create mode 100644 ext/opentelemetry-ext-prometheus/tests/conftest.py create mode 100644 ext/opentelemetry-ext-wsgi/tests/conftest.py create mode 100644 opentelemetry-api/src/opentelemetry/configuration/__init__.py create mode 100644 opentelemetry-api/src/opentelemetry/configuration/opentelemetry_python.json create mode 100644 opentelemetry-api/src/opentelemetry/configuration/py.typed delete mode 100644 opentelemetry-api/src/opentelemetry/util/loader.py create mode 100644 opentelemetry-api/tests/configuration/__init__.py create mode 100644 opentelemetry-api/tests/configuration/test_configuration.py delete mode 100644 opentelemetry-api/tests/test_loader.py diff --git a/docs/api/api.rst b/docs/api/api.rst index 3b15cd0d36b..6ae631147a2 100644 --- a/docs/api/api.rst +++ b/docs/api/api.rst @@ -9,4 +9,3 @@ OpenTelemetry Python API context metrics trace - util.loader \ No newline at end of file diff --git a/docs/api/util.loader.rst b/docs/api/util.loader.rst deleted file mode 100644 index 079d2e4a38d..00000000000 --- a/docs/api/util.loader.rst +++ /dev/null @@ -1,4 +0,0 @@ -opentelemetry.util.loader module -================================ - -.. automodule:: opentelemetry.util.loader diff --git a/docs/examples/basic_tracer/tracer.py b/docs/examples/basic_tracer/tracer.py index a454eab7a96..a8ba537cc9c 100755 --- a/docs/examples/basic_tracer/tracer.py +++ b/docs/examples/basic_tracer/tracer.py @@ -17,7 +17,6 @@ import os from opentelemetry import trace -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( BatchExportSpanProcessor, ConsoleSpanExporter, @@ -45,10 +44,6 @@ print("Using ConsoleSpanExporter") exporter = ConsoleSpanExporter() -# The preferred tracer implementation must be set, as the opentelemetry-api -# defines the interface with a no-op implementation. -trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) - # We tell OpenTelemetry who it is that is creating spans. In this case, we have # no real name (no setup.py), so we make one up. If we had a version, we would # also specify it here. @@ -57,7 +52,7 @@ # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) -trace.tracer_provider().add_span_processor(span_processor) +trace.get_tracer_provider().add_span_processor(span_processor) with tracer.start_as_current_span("foo"): with tracer.start_as_current_span("bar"): with tracer.start_as_current_span("baz"): diff --git a/docs/examples/http/server.py b/docs/examples/http/server.py index 50bc566b77c..d706a269606 100755 --- a/docs/examples/http/server.py +++ b/docs/examples/http/server.py @@ -22,7 +22,6 @@ from opentelemetry import trace from opentelemetry.ext import http_requests from opentelemetry.ext.wsgi import OpenTelemetryMiddleware -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( BatchExportSpanProcessor, ConsoleSpanExporter, @@ -39,19 +38,16 @@ else: exporter = ConsoleSpanExporter() -# The preferred tracer implementation must be set, as the opentelemetry-api -# defines the interface with a no-op implementation. -trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) tracer = trace.get_tracer(__name__) # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) -trace.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(trace.tracer_provider()) +http_requests.enable(trace.get_tracer_provider()) app = flask.Flask(__name__) app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app) diff --git a/docs/examples/http/tests/test_http.py b/docs/examples/http/tests/test_http.py index 0ae81fe7de7..0444e8d67d6 100644 --- a/docs/examples/http/tests/test_http.py +++ b/docs/examples/http/tests/test_http.py @@ -19,11 +19,10 @@ class TestHttpExample(unittest.TestCase): - @classmethod - def setup_class(cls): + def setUp(self): dirpath = os.path.dirname(os.path.realpath(__file__)) server_script = "{}/../server.py".format(dirpath) - cls.server = subprocess.Popen([sys.executable, server_script]) + self.server = subprocess.Popen([sys.executable, server_script]) sleep(1) def test_http(self): @@ -34,6 +33,5 @@ def test_http(self): ).decode() self.assertIn('name="/"', output) - @classmethod - def teardown_class(cls): - cls.server.terminate() + def tearDown(self): + self.server.terminate() diff --git a/docs/examples/http/tracer_client.py b/docs/examples/http/tracer_client.py index 6fd0a726a42..3ae6dc9ffed 100755 --- a/docs/examples/http/tracer_client.py +++ b/docs/examples/http/tracer_client.py @@ -20,7 +20,6 @@ from opentelemetry import trace from opentelemetry.ext import http_requests -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( BatchExportSpanProcessor, ConsoleSpanExporter, @@ -37,10 +36,7 @@ else: exporter = ConsoleSpanExporter() -# The preferred tracer implementation must be set, as the opentelemetry-api -# defines the interface with a no-op implementation. -trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) -tracer_provider = trace.tracer_provider() +tracer_provider = trace.get_tracer_provider() # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) diff --git a/docs/examples/metrics/observer_example.py b/docs/examples/metrics/observer_example.py index aff25ee476c..7f5614d058e 100644 --- a/docs/examples/metrics/observer_example.py +++ b/docs/examples/metrics/observer_example.py @@ -19,7 +19,7 @@ import psutil from opentelemetry import metrics -from opentelemetry.sdk.metrics import LabelSet, MeterProvider +from opentelemetry.sdk.metrics import LabelSet from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter from opentelemetry.sdk.metrics.export.batcher import UngroupedBatcher from opentelemetry.sdk.metrics.export.controller import PushController @@ -27,7 +27,6 @@ # Configure a stateful batcher batcher = UngroupedBatcher(stateful=True) -metrics.set_preferred_meter_provider_implementation(lambda _: MeterProvider()) meter = metrics.get_meter(__name__) # Exporter to export metrics to the console diff --git a/docs/examples/metrics/prometheus.py b/docs/examples/metrics/prometheus.py index 4d30f8abcca..3c9a33f32a3 100644 --- a/docs/examples/metrics/prometheus.py +++ b/docs/examples/metrics/prometheus.py @@ -21,14 +21,13 @@ from opentelemetry import metrics from opentelemetry.ext.prometheus import PrometheusMetricsExporter -from opentelemetry.sdk.metrics import Counter, MeterProvider +from opentelemetry.sdk.metrics import Counter from opentelemetry.sdk.metrics.export.controller import PushController # Start Prometheus client start_http_server(port=8000, addr="localhost") # Meter is responsible for creating and recording metrics -metrics.set_preferred_meter_provider_implementation(lambda _: MeterProvider()) meter = metrics.get_meter(__name__) # exporter to export metrics to Prometheus prefix = "MyAppPrefix" diff --git a/docs/examples/metrics/record.py b/docs/examples/metrics/record.py index d4c3d03d824..948fdf10913 100644 --- a/docs/examples/metrics/record.py +++ b/docs/examples/metrics/record.py @@ -19,13 +19,10 @@ import time from opentelemetry import metrics -from opentelemetry.sdk.metrics import Counter, MeterProvider +from opentelemetry.sdk.metrics import Counter from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter from opentelemetry.sdk.metrics.export.controller import PushController -# The preferred tracer implementation must be set, as the opentelemetry-api -# defines the interface with a no-op implementation. -metrics.set_preferred_meter_provider_implementation(lambda _: MeterProvider()) # Meter is responsible for creating and recording metrics meter = metrics.get_meter(__name__) # exporter to export metrics to the console diff --git a/docs/examples/metrics/simple_example.py b/docs/examples/metrics/simple_example.py index 2b8f5cfac8b..0108d1620b8 100644 --- a/docs/examples/metrics/simple_example.py +++ b/docs/examples/metrics/simple_example.py @@ -23,7 +23,7 @@ import time from opentelemetry import metrics -from opentelemetry.sdk.metrics import Counter, Measure, MeterProvider +from opentelemetry.sdk.metrics import Counter, Measure from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter from opentelemetry.sdk.metrics.export.controller import PushController @@ -44,7 +44,6 @@ def usage(argv): sys.exit(1) # Meter is responsible for creating and recording metrics -metrics.set_preferred_meter_provider_implementation(lambda _: MeterProvider()) # Meter's namespace corresponds to the string passed as the first argument Pass # in True/False to indicate whether the batcher is stateful. True indicates the 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 a33b3b58f4c..12d3eed204a 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 @@ -23,7 +23,6 @@ import opentelemetry.ext.http_requests from opentelemetry import trace from opentelemetry.ext.flask import instrument_app -from opentelemetry.sdk.trace import TracerProvider def configure_opentelemetry(flask_app: flask.Flask): @@ -42,12 +41,6 @@ def configure_opentelemetry(flask_app: flask.Flask): """ # Start by configuring all objects required to ensure # a complete end to end workflow. - # The preferred implementation of these objects must be set, - # as the opentelemetry-api defines the interface with a no-op - # implementation. - trace.set_preferred_tracer_provider_implementation( - lambda _: TracerProvider() - ) # Next, we need to configure how the values that are used by # traces and metrics are propagated (such as what specific headers @@ -55,7 +48,7 @@ def configure_opentelemetry(flask_app: flask.Flask): # 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. - opentelemetry.ext.http_requests.enable(trace.tracer_provider()) + opentelemetry.ext.http_requests.enable(trace.get_tracer_provider()) instrument_app(flask_app) diff --git a/docs/examples/opentracing/main.py b/docs/examples/opentracing/main.py index 665099aeeef..0c331ddee35 100755 --- a/docs/examples/opentracing/main.py +++ b/docs/examples/opentracing/main.py @@ -3,13 +3,10 @@ from opentelemetry import trace from opentelemetry.ext import opentracing_shim from opentelemetry.ext.jaeger import JaegerSpanExporter -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleExportSpanProcessor from rediscache import RedisCache -# Configure the tracer using the default implementation -trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) -tracer_provider = trace.tracer_provider() +tracer_provider = trace.get_tracer_provider() # Configure the tracer to export traces to Jaeger jaeger_exporter = JaegerSpanExporter( diff --git a/examples/basic_tracer/tests/conftest.py b/examples/basic_tracer/tests/conftest.py new file mode 100644 index 00000000000..ff9e5ea43bb --- /dev/null +++ b/examples/basic_tracer/tests/conftest.py @@ -0,0 +1,25 @@ +# Copyright 2020, 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 + + +def pytest_sessionstart(session): # pylint: disable=unused-argument + environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" + environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" + + +def pytest_sessionfinish(session): # pylint: disable=unused-argument + environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") + environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/examples/http/tests/conftest.py b/examples/http/tests/conftest.py new file mode 100644 index 00000000000..ff9e5ea43bb --- /dev/null +++ b/examples/http/tests/conftest.py @@ -0,0 +1,25 @@ +# Copyright 2020, 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 + + +def pytest_sessionstart(session): # pylint: disable=unused-argument + environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" + environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" + + +def pytest_sessionfinish(session): # pylint: disable=unused-argument + environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") + environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/examples/opentelemetry-example-app/tests/conftest.py b/examples/opentelemetry-example-app/tests/conftest.py new file mode 100644 index 00000000000..ff9e5ea43bb --- /dev/null +++ b/examples/opentelemetry-example-app/tests/conftest.py @@ -0,0 +1,25 @@ +# Copyright 2020, 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 + + +def pytest_sessionstart(session): # pylint: disable=unused-argument + environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" + environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" + + +def pytest_sessionfinish(session): # pylint: disable=unused-argument + environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") + environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/ext/opentelemetry-ext-dbapi/README.rst b/ext/opentelemetry-ext-dbapi/README.rst index 33ec8de6f6e..24d4577306f 100644 --- a/ext/opentelemetry-ext-dbapi/README.rst +++ b/ext/opentelemetry-ext-dbapi/README.rst @@ -15,7 +15,6 @@ Usage from opentelemetry.trace import tracer_provider from opentelemetry.ext.dbapi import trace_integration - trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) tracer = trace.get_tracer(__name__) # Ex: mysql.connector trace_integration(tracer_provider(), mysql.connector, "connect", "mysql", "sql") diff --git a/ext/opentelemetry-ext-flask/tests/conftest.py b/ext/opentelemetry-ext-flask/tests/conftest.py new file mode 100644 index 00000000000..ff9e5ea43bb --- /dev/null +++ b/ext/opentelemetry-ext-flask/tests/conftest.py @@ -0,0 +1,25 @@ +# Copyright 2020, 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 + + +def pytest_sessionstart(session): # pylint: disable=unused-argument + environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" + environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" + + +def pytest_sessionfinish(session): # pylint: disable=unused-argument + environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") + environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/ext/opentelemetry-ext-jaeger/README.rst b/ext/opentelemetry-ext-jaeger/README.rst index 6813fbdeee8..47549992dba 100644 --- a/ext/opentelemetry-ext-jaeger/README.rst +++ b/ext/opentelemetry-ext-jaeger/README.rst @@ -32,10 +32,8 @@ gRPC is still not supported by this implementation. from opentelemetry import trace from opentelemetry.ext import jaeger - from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchExportSpanProcessor - trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) tracer = trace.get_tracer(__name__) # create a JaegerSpanExporter diff --git a/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py b/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py index 81815da935c..1f0c303e065 100644 --- a/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py +++ b/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py @@ -2,10 +2,8 @@ from opentelemetry import trace from opentelemetry.ext import jaeger -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchExportSpanProcessor -trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) tracer = trace.get_tracer(__name__) # create a JaegerSpanExporter @@ -26,7 +24,7 @@ span_processor = BatchExportSpanProcessor(jaeger_exporter) # add to the tracer factory -trace.tracer_provider().add_span_processor(span_processor) +trace.get_tracer_provider().add_span_processor(span_processor) # create some spans for testing with tracer.start_as_current_span("foo") as foo: diff --git a/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py b/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py index bd9d22678ed..331ed10baf1 100644 --- a/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py +++ b/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py @@ -29,12 +29,8 @@ import time from opentelemetry import trace - from opentelemetry.sdk.trace import TracerProvider from opentelemetry.ext.opentracing_shim import create_tracer - # Tell OpenTelemetry which Tracer implementation to use. - trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) - # Create an OpenTelemetry Tracer. otel_tracer = trace.get_tracer(__name__) diff --git a/ext/opentelemetry-ext-opentracing-shim/tests/conftest.py b/ext/opentelemetry-ext-opentracing-shim/tests/conftest.py new file mode 100644 index 00000000000..ff9e5ea43bb --- /dev/null +++ b/ext/opentelemetry-ext-opentracing-shim/tests/conftest.py @@ -0,0 +1,25 @@ +# Copyright 2020, 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 + + +def pytest_sessionstart(session): # pylint: disable=unused-argument + environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" + environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" + + +def pytest_sessionfinish(session): # pylint: disable=unused-argument + environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") + environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py b/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py index 2a3fe819c9b..8a025be0368 100644 --- a/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py +++ b/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py @@ -25,7 +25,6 @@ from opentelemetry import propagators, trace from opentelemetry.context import Context from opentelemetry.ext.opentracing_shim import util -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.trace.propagation import ( get_span_from_context, set_span_in_context, @@ -44,18 +43,10 @@ class TestShim(TestCase): def setUp(self): """Create an OpenTelemetry tracer and a shim before every test case.""" - self.shim = opentracingshim.create_tracer(trace.tracer_provider()) + self.shim = opentracingshim.create_tracer(trace.get_tracer_provider()) @classmethod def setUpClass(cls): - """Set preferred tracer implementation only once rather than before - every test method. - """ - - trace.set_preferred_tracer_provider_implementation( - lambda T: TracerProvider() - ) - # Save current propagator to be restored on teardown. cls._previous_propagator = propagators.get_global_httptextformat() diff --git a/ext/opentelemetry-ext-prometheus/README.rst b/ext/opentelemetry-ext-prometheus/README.rst index e70332556e2..f7049194a2e 100644 --- a/ext/opentelemetry-ext-prometheus/README.rst +++ b/ext/opentelemetry-ext-prometheus/README.rst @@ -29,7 +29,7 @@ The **OpenTelemetry Prometheus Exporter** allows to export `OpenTelemetry`_ metr from opentelemetry import metrics from opentelemetry.ext.prometheus import PrometheusMetricsExporter - from opentelemetry.sdk.metrics import Counter, Meter + from opentelemetry.sdk.metrics import Counter from opentelemetry.sdk.metrics.export.controller import PushController from prometheus_client import start_http_server @@ -37,7 +37,6 @@ The **OpenTelemetry Prometheus Exporter** allows to export `OpenTelemetry`_ metr start_http_server(port=8000, addr="localhost") # Meter is responsible for creating and recording metrics - metrics.set_preferred_meter_implementation(lambda _: Meter()) meter = metrics.meter() # exporter to export metrics to Prometheus prefix = "MyAppPrefix" diff --git a/ext/opentelemetry-ext-prometheus/tests/conftest.py b/ext/opentelemetry-ext-prometheus/tests/conftest.py new file mode 100644 index 00000000000..ff9e5ea43bb --- /dev/null +++ b/ext/opentelemetry-ext-prometheus/tests/conftest.py @@ -0,0 +1,25 @@ +# Copyright 2020, 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 + + +def pytest_sessionstart(session): # pylint: disable=unused-argument + environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" + environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" + + +def pytest_sessionfinish(session): # pylint: disable=unused-argument + environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") + environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py b/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py index f6883475386..a0079b1fee1 100644 --- a/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py +++ b/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py @@ -21,6 +21,7 @@ CustomCollector, PrometheusMetricsExporter, ) +from opentelemetry.metrics import get_meter_provider from opentelemetry.sdk import metrics from opentelemetry.sdk.metrics.export import MetricRecord, MetricsExportResult from opentelemetry.sdk.metrics.export.aggregate import CounterAggregator @@ -28,7 +29,7 @@ class TestPrometheusMetricExporter(unittest.TestCase): def setUp(self): - self._meter = metrics.MeterProvider().get_meter(__name__) + self._meter = get_meter_provider().get_meter(__name__) self._test_metric = self._meter.create_metric( "testname", "testdesc", @@ -74,7 +75,7 @@ def test_export(self): self.assertIs(result, MetricsExportResult.SUCCESS) def test_counter_to_prometheus(self): - meter = metrics.MeterProvider().get_meter(__name__) + meter = get_meter_provider().get_meter(__name__) metric = meter.create_metric( "test@name", "testdesc", @@ -110,8 +111,7 @@ def test_counter_to_prometheus(self): # TODO: Add unit test once Measure Aggregators are available def test_invalid_metric(self): - - meter = metrics.MeterProvider().get_meter(__name__) + meter = get_meter_provider().get_meter(__name__) metric = meter.create_metric( "tesname", "testdesc", "unit", int, TestMetric ) diff --git a/ext/opentelemetry-ext-psycopg2/README.rst b/ext/opentelemetry-ext-psycopg2/README.rst index 127b74f0c79..3cf4cf110b3 100644 --- a/ext/opentelemetry-ext-psycopg2/README.rst +++ b/ext/opentelemetry-ext-psycopg2/README.rst @@ -13,10 +13,8 @@ Usage import psycopg2 from opentelemetry import trace - from opentelemetry.sdk.trace import TracerProvider from opentelemetry.trace.ext.psycopg2 import trace_integration - trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) tracer = trace.get_tracer(__name__) trace_integration(tracer) cnx = psycopg2.connect(database='Database') diff --git a/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py b/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py index 18b64364db9..39c2be27f9e 100644 --- a/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py +++ b/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py @@ -4,7 +4,7 @@ from importlib import reload from opentelemetry import trace as trace_api -from opentelemetry.sdk.trace import TracerProvider, export +from opentelemetry.sdk.trace import export from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( InMemorySpanExporter, ) @@ -16,10 +16,7 @@ class WsgiTestBase(unittest.TestCase): @classmethod def setUpClass(cls): global _MEMORY_EXPORTER # pylint:disable=global-statement - trace_api.set_preferred_tracer_provider_implementation( - lambda T: TracerProvider() - ) - tracer_provider = trace_api.tracer_provider() + tracer_provider = trace_api.get_tracer_provider() _MEMORY_EXPORTER = InMemorySpanExporter() span_processor = export.SimpleExportSpanProcessor(_MEMORY_EXPORTER) tracer_provider.add_span_processor(span_processor) diff --git a/ext/opentelemetry-ext-wsgi/tests/conftest.py b/ext/opentelemetry-ext-wsgi/tests/conftest.py new file mode 100644 index 00000000000..ff9e5ea43bb --- /dev/null +++ b/ext/opentelemetry-ext-wsgi/tests/conftest.py @@ -0,0 +1,25 @@ +# Copyright 2020, 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 + + +def pytest_sessionstart(session): # pylint: disable=unused-argument + environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" + environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" + + +def pytest_sessionfinish(session): # pylint: disable=unused-argument + environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") + environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/ext/opentelemetry-ext-zipkin/README.rst b/ext/opentelemetry-ext-zipkin/README.rst index f933ba4a685..9c88e450603 100644 --- a/ext/opentelemetry-ext-zipkin/README.rst +++ b/ext/opentelemetry-ext-zipkin/README.rst @@ -30,10 +30,8 @@ This exporter always send traces to the configured Zipkin collector using HTTP. from opentelemetry import trace from opentelemetry.ext import zipkin - from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchExportSpanProcessor - trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) tracer = trace.get_tracer(__name__) # create a ZipkinSpanExporter diff --git a/opentelemetry-api/setup.py b/opentelemetry-api/setup.py index 20e7f581435..eb10d24b94f 100644 --- a/opentelemetry-api/setup.py +++ b/opentelemetry-api/setup.py @@ -12,18 +12,40 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os +from os.path import dirname, exists, join +from pathlib import Path import setuptools -BASE_DIR = os.path.dirname(__file__) -VERSION_FILENAME = os.path.join( - BASE_DIR, "src", "opentelemetry", "util", "version.py" -) +BASE_DIR = dirname(__file__) +VERSION_FILENAME = join(BASE_DIR, "src", "opentelemetry", "util", "version.py") PACKAGE_INFO = {} with open(VERSION_FILENAME) as f: exec(f.read(), PACKAGE_INFO) +# FIXME Make this script install the configuration file in +# ~/.config/opentelemetry_python.json +configuration_file_path = join( + Path.home(), ".config", "opentelemetry_python.json" +) + +data_files = [] + +if not exists(configuration_file_path): + data_files.append( + ( + dirname(configuration_file_path), + [ + join( + "src", + "opentelemetry", + "configuration", + "opentelemetry_python.json", + ) + ], + ) + ) + setuptools.setup( name="opentelemetry-api", version=PACKAGE_INFO["__version__"], @@ -61,12 +83,22 @@ zip_safe=False, entry_points={ "opentelemetry_context": [ + "default_context = opentelemetry.context:DefaultContext", "contextvars_context = " "opentelemetry.context.contextvars_context:" "ContextVarsRuntimeContext", "threadlocal_context = " "opentelemetry.context.threadlocal_context:" "ThreadLocalRuntimeContext", - ] + ], + "opentelemetry_meter_provider": [ + "default_meter_provider = " + "opentelemetry.metrics:DefaultMeterProvider" + ], + "opentelemetry_tracer_provider": [ + "default_tracer_provider = " + "opentelemetry.trace:DefaultTracerProvider" + ], }, + data_files=data_files, ) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py new file mode 100644 index 00000000000..3e89f5f7d3a --- /dev/null +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -0,0 +1,78 @@ +# Copyright 2020, 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. + +""" +Simple configuration manager + +This configuration manager reads configuration values from a JSON file, the +values read there can be overriden by environment variables. + +It would probably be better to replace this configuration manager with a more +powerful one, Dynaconf, for example. +""" + +from json import load +from os import environ +from os.path import exists, join +from pathlib import Path + + +class Configuration: + _instance = None + + __slots__ = ["tracer_provider", "meter_provider"] + + def __new__(cls): + if Configuration._instance is None: + + configuration = { + key: "default_{}".format(key) for key in cls.__slots__ + } + + configuration_file_path = join( + Path.home(), ".config", "opentelemetry_python.json" + ) + + if exists(configuration_file_path): + + with open(configuration_file_path) as configuration_file: + file_configuration = load(configuration_file) + + for key, value in configuration.items(): + configuration[key] = file_configuration.get(key, value) + + for key, value in configuration.items(): + configuration[key] = environ.get( + "OPENTELEMETRY_PYTHON_{}".format(key.upper()), value + ) + + for key, value in configuration.items(): + underscored_key = "_{}".format(key) + + setattr(Configuration, underscored_key, value) + setattr( + Configuration, + key, + property( + ( + lambda underscored_key: lambda self: getattr( + self, underscored_key + ) + )(underscored_key) + ), + ) + + Configuration._instance = object.__new__(cls) + + return cls._instance diff --git a/opentelemetry-api/src/opentelemetry/configuration/opentelemetry_python.json b/opentelemetry-api/src/opentelemetry/configuration/opentelemetry_python.json new file mode 100644 index 00000000000..c0ac3f4ff93 --- /dev/null +++ b/opentelemetry-api/src/opentelemetry/configuration/opentelemetry_python.json @@ -0,0 +1,4 @@ +{ + "tracer_provider": "default_tracer_provider", + "meter_provider": "default_meter_provider" +} diff --git a/opentelemetry-api/src/opentelemetry/configuration/py.typed b/opentelemetry-api/src/opentelemetry/configuration/py.typed new file mode 100644 index 00000000000..e69de29bb2d diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py index e521b2654c3..911fab1b79d 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py @@ -27,13 +27,14 @@ """ import abc -import logging -from typing import Callable, Dict, Optional, Sequence, Tuple, Type, TypeVar +from logging import getLogger +from typing import Callable, Dict, Sequence, Tuple, Type, TypeVar -from opentelemetry.util import loader +from pkg_resources import iter_entry_points -logger = logging.getLogger(__name__) +from opentelemetry.configuration import Configuration +_LOGGER = getLogger(__name__) ValueT = TypeVar("ValueT", int, float) @@ -398,15 +399,7 @@ def get_label_set(self, labels: Dict[str, str]) -> "LabelSet": return DefaultLabelSet() -# Once https://github.com/python/mypy/issues/7092 is resolved, -# the following type definition should be replaced with -# from opentelemetry.util.loader import ImplementationFactory -ImplementationFactory = Callable[ - [Type[MeterProvider]], Optional[MeterProvider] -] - _METER_PROVIDER = None -_METER_PROVIDER_FACTORY = None def get_meter( @@ -418,52 +411,34 @@ def get_meter( This function is a convenience wrapper for opentelemetry.metrics.meter_provider().get_meter """ - return meter_provider().get_meter( + return get_meter_provider().get_meter( instrumenting_module_name, stateful, instrumenting_library_version ) -def meter_provider() -> MeterProvider: - """Gets the current global :class:`~.MeterProvider` object. - - If there isn't one set yet, a default will be loaded. - """ - global _METER_PROVIDER, _METER_PROVIDER_FACTORY # pylint:disable=global-statement +def get_meter_provider() -> MeterProvider: + """Gets the current global :class:`~.MeterProvider` object.""" + global _METER_PROVIDER # pylint: disable=global-statement if _METER_PROVIDER is None: - # pylint:disable=protected-access + configured_meter_provider = ( + Configuration().meter_provider # pylint: disable=no-member + ) + try: - _METER_PROVIDER = loader._load_impl( - MeterProvider, _METER_PROVIDER_FACTORY # type: ignore + _METER_PROVIDER = next( + iter_entry_points( + "opentelemetry_meter_provider", configured_meter_provider + ) + ).load()() + except Exception: # pylint: disable=broad-except + # FIXME Decide on how to handle this. Should an exception be + # raised here, or only a message should be logged and should + # we fall back to the default meter provider? + _LOGGER.error( + "Failed to load configured meter provider %s", + configured_meter_provider, ) - except TypeError: - # if we raised an exception trying to instantiate an - # abstract class, default to no-op meter impl - logger.warning( - "Unable to instantiate MeterProvider from meter provider factory.", - exc_info=True, - ) - _METER_PROVIDER = DefaultMeterProvider() - _METER_PROVIDER_FACTORY = None + raise return _METER_PROVIDER - - -def set_preferred_meter_provider_implementation( - factory: ImplementationFactory, -) -> None: - """Set the factory to be used to create the meter provider. - - See :mod:`opentelemetry.util.loader` for details. - - This function may not be called after a meter is already loaded. - - Args: - factory: Callback that should create a new :class:`MeterProvider` instance. - """ - global _METER_PROVIDER_FACTORY # pylint:disable=global-statement - - if _METER_PROVIDER: - raise RuntimeError("MeterProvider already loaded.") - - _METER_PROVIDER_FACTORY = factory diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index a6633e434a0..05c6b962237 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -63,20 +63,23 @@ .. versionadded:: 0.1.0 .. versionchanged:: 0.3.0 `TracerProvider` was introduced and the global ``tracer`` getter was replaced - by `tracer_provider`. + by `get_tracer_provider`. """ import abc import enum -import logging import types as python_types import typing from contextlib import contextmanager +from logging import getLogger +from pkg_resources import iter_entry_points + +from opentelemetry.configuration import Configuration from opentelemetry.trace.status import Status -from opentelemetry.util import loader, types +from opentelemetry.util import types -logger = logging.getLogger(__name__) +_LOGGER = getLogger(__name__) # TODO: quarantine ParentSpan = typing.Optional[typing.Union["Span", "SpanContext"]] @@ -639,15 +642,7 @@ def use_span( yield -# Once https://github.com/python/mypy/issues/7092 is resolved, -# the following type definition should be replaced with -# from opentelemetry.util.loader import ImplementationFactory -ImplementationFactory = typing.Callable[ - [typing.Type[TracerProvider]], typing.Optional[TracerProvider] -] - -_TRACER_PROVIDER = None # type: typing.Optional[TracerProvider] -_TRACER_PROVIDER_FACTORY = None # type: typing.Optional[ImplementationFactory] +_TRACER_PROVIDER = None def get_tracer( @@ -658,53 +653,35 @@ def get_tracer( This function is a convenience wrapper for opentelemetry.trace.tracer_provider().get_tracer """ - return tracer_provider().get_tracer( + return get_tracer_provider().get_tracer( instrumenting_module_name, instrumenting_library_version ) -def tracer_provider() -> TracerProvider: - """Gets the current global :class:`~.TracerProvider` object. - - If there isn't one set yet, a default will be loaded. - """ - global _TRACER_PROVIDER, _TRACER_PROVIDER_FACTORY # pylint:disable=global-statement +def get_tracer_provider() -> TracerProvider: + """Gets the current global :class:`~.TracerProvider` object.""" + global _TRACER_PROVIDER # pylint: disable=global-statement if _TRACER_PROVIDER is None: - # pylint:disable=protected-access + configured_tracer_provider = ( + Configuration().tracer_provider # pylint: disable=no-member + ) + try: - _TRACER_PROVIDER = loader._load_impl( - TracerProvider, _TRACER_PROVIDER_FACTORY # type: ignore + _TRACER_PROVIDER = next( + iter_entry_points( + "opentelemetry_tracer_provider", + name=configured_tracer_provider, + ) + ).load()() + except Exception: # pylint: disable=broad-except + # FIXME Decide on how to handle this. Should an exception be + # raised here, or only a message should be logged and should + # we fall back to the default tracer provider? + _LOGGER.error( + "Failed to load tracer implementation: %s", + configured_tracer_provider, ) - except TypeError: - # if we raised an exception trying to instantiate an - # abstract class, default to no-op tracer impl - logger.warning( - "Unable to instantiate TracerProvider from factory.", - exc_info=True, - ) - _TRACER_PROVIDER = DefaultTracerProvider() - del _TRACER_PROVIDER_FACTORY + raise return _TRACER_PROVIDER - - -def set_preferred_tracer_provider_implementation( - factory: ImplementationFactory, -) -> None: - """Set the factory to be used to create the global TracerProvider. - - See :mod:`opentelemetry.util.loader` for details. - - This function may not be called after a tracer is already loaded. - - Args: - factory: Callback that should create a new :class:`TracerProvider` - instance. - """ - global _TRACER_PROVIDER_FACTORY # pylint:disable=global-statement - - if _TRACER_PROVIDER: - raise RuntimeError("TracerProvider already loaded.") - - _TRACER_PROVIDER_FACTORY = factory diff --git a/opentelemetry-api/src/opentelemetry/util/loader.py b/opentelemetry-api/src/opentelemetry/util/loader.py deleted file mode 100644 index eeda2b3e7f7..00000000000 --- a/opentelemetry-api/src/opentelemetry/util/loader.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2019, 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. - - -""" -The OpenTelemetry loader module is mainly used internally to load the -implementation for global objects like -:func:`opentelemetry.trace.tracer_provider`. - -.. _loader-factory: - -An instance of a global object of type ``T`` is always created with a factory -function with the following signature:: - - def my_factory_for_t(api_type: typing.Type[T]) -> typing.Optional[T]: - # ... - -That function is called with e.g., the type of the global object it should -create as an argument (e.g. the type object -:class:`opentelemetry.trace.TracerProvider`) and should return an instance of that type -(such that ``instanceof(my_factory_for_t(T), T)`` is true). Alternatively, it -may return ``None`` to indicate that the no-op default should be used. - -When loading an implementation, the following algorithm is used to find a -factory function or other means to create the global object: - - 1. If the environment variable - :samp:`OPENTELEMETRY_PYTHON_IMPLEMENTATION_{getter-name}` (e.g., - ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_TRACERPROVIDER``) is set to an - nonempty value, an attempt is made to import a module with that name and - use a factory function named ``get_opentelemetry_implementation`` in it. - 2. Otherwise, the same is tried with the environment variable - ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_DEFAULT``. - 3. Otherwise, if a :samp:`set_preferred_{}_implementation` was - called (e.g. - :func:`opentelemetry.trace.set_preferred_tracer_provider_implementation`), - the callback set there is used (that is, the environment variables - override the callback set in code). - 4. Otherwise, if :func:`set_preferred_default_implementation` was called, - the callback set there is used. - 5. Otherwise, an attempt is made to import and use the OpenTelemetry SDK. - 6. Otherwise the default implementation that ships with the API - distribution (a fast no-op implementation) is used. - -If any of the above steps fails (e.g., a module is loaded but does not define -the required function or a module name is set but the module fails to load), -the search immediatelly skips to the last step. - -Note that the first two steps (those that query environment variables) are -skipped if :data:`sys.flags` has ``ignore_environment`` set (which usually -means that the Python interpreter was invoked with the ``-E`` or ``-I`` flag). -""" - -import importlib -import os -import sys -from typing import Callable, Optional, Type, TypeVar - -_T = TypeVar("_T") - -# "Untrusted" because this is usually user-provided and we don't trust the user -# to really return a _T: by using object, mypy forces us to check/cast -# explicitly. -_UntrustedImplFactory = Callable[[Type[_T]], Optional[object]] - - -# This would be the normal ImplementationFactory which would be used to -# annotate setters, were it not for https://github.com/python/mypy/issues/7092 -# Once that bug is resolved, setters should use this instead of duplicating the -# code. -# ImplementationFactory = Callable[[Type[_T]], Optional[_T]] - -_DEFAULT_FACTORY = None # type: Optional[_UntrustedImplFactory[object]] - - -def _try_load_impl_from_modname( - implementation_modname: str, api_type: Type[_T] -) -> Optional[_T]: - try: - implementation_mod = importlib.import_module(implementation_modname) - except (ImportError, SyntaxError): - # TODO Log/warn - return None - - return _try_load_impl_from_mod(implementation_mod, api_type) - - -def _try_load_impl_from_mod( - implementation_mod: object, api_type: Type[_T] -) -> Optional[_T]: - - try: - # Note: We use such a long name to avoid calling a function that is not - # intended for this API. - - implementation_fn = getattr( - implementation_mod, "get_opentelemetry_implementation" - ) # type: _UntrustedImplFactory[_T] - except AttributeError: - # TODO Log/warn - return None - - return _try_load_impl_from_callback(implementation_fn, api_type) - - -def _try_load_impl_from_callback( - implementation_fn: _UntrustedImplFactory[_T], api_type: Type[_T] -) -> Optional[_T]: - result = implementation_fn(api_type) - if result is None: - return None - if not isinstance(result, api_type): - # TODO Warn if wrong type is returned - return None - - # TODO: Warn if implementation_fn returns api_type(): It should return None - # to indicate using the default. - - return result - - -def _try_load_configured_impl( - api_type: Type[_T], factory: Optional[_UntrustedImplFactory[_T]] -) -> Optional[_T]: - """Attempts to find any specially configured implementation. If none is - configured, or a load error occurs, returns `None` - """ - implementation_modname = None - if not sys.flags.ignore_environment: - implementation_modname = os.getenv( - "OPENTELEMETRY_PYTHON_IMPLEMENTATION_" + api_type.__name__.upper() - ) - if implementation_modname: - return _try_load_impl_from_modname( - implementation_modname, api_type - ) - implementation_modname = os.getenv( - "OPENTELEMETRY_PYTHON_IMPLEMENTATION_DEFAULT" - ) - if implementation_modname: - return _try_load_impl_from_modname( - implementation_modname, api_type - ) - if factory is not None: - return _try_load_impl_from_callback(factory, api_type) - if _DEFAULT_FACTORY is not None: - return _try_load_impl_from_callback(_DEFAULT_FACTORY, api_type) - return None - - -# Public to other opentelemetry-api modules -def _load_impl( - api_type: Type[_T], factory: Optional[Callable[[Type[_T]], Optional[_T]]] -) -> _T: - """Tries to load a configured implementation, if unsuccessful, returns a - fast no-op implemenation that is always available. - """ - - result = _try_load_configured_impl(api_type, factory) - if result is None: - return api_type() - return result - - -def set_preferred_default_implementation( - implementation_factory: _UntrustedImplFactory[_T], -) -> None: - """Sets a factory function that may be called for any implementation - object. See the :ref:`module docs ` for more details.""" - global _DEFAULT_FACTORY # pylint:disable=global-statement - _DEFAULT_FACTORY = implementation_factory diff --git a/opentelemetry-api/tests/configuration/__init__.py b/opentelemetry-api/tests/configuration/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/opentelemetry-api/tests/configuration/test_configuration.py b/opentelemetry-api/tests/configuration/test_configuration.py new file mode 100644 index 00000000000..cd3b9aa3e0a --- /dev/null +++ b/opentelemetry-api/tests/configuration/test_configuration.py @@ -0,0 +1,85 @@ +# Copyright 2020, 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 json import dumps +from os import getcwd +from unittest import TestCase +from unittest.mock import patch + +from opentelemetry.configuration import Configuration +from pytest import fixture # pylint: disable=import-error + + +class TestConfiguration(TestCase): + @fixture(autouse=True) + def configdir(self, tmpdir): # pylint: disable=no-self-use + tmpdir.chdir() + tmpdir.mkdir(".config").join("opentelemetry_python.json").write( + dumps({"tracer_provider": "default_tracer_provider"}) + ) + + def setUp(self): + Configuration._instance = None # pylint: disable=protected-access + + def tearDown(self): + Configuration._instance = None # pylint: disable=protected-access + + def test_singleton(self): + self.assertIs(Configuration(), Configuration()) + + @patch("pathlib.Path.home") + def test_configuration_file(self, mock_home_path): + mock_home_path.return_value = getcwd() + + self.assertEqual( + Configuration().tracer_provider, "default_tracer_provider" + ) # pylint: disable=no-member + self.assertEqual( + Configuration().meter_provider, "default_meter_provider" + ) # pylint: disable=no-member + + @patch.dict( + "os.environ", + {"OPENTELEMETRY_PYTHON_METER_PROVIDER": "overridden_meter_provider"}, + ) + def test_environment_variables(self): + self.assertEqual( + Configuration().tracer_provider, "default_tracer_provider" + ) # pylint: disable=no-member + self.assertEqual( + Configuration().meter_provider, "overridden_meter_provider" + ) # pylint: disable=no-member + + @patch("pathlib.Path.home") + @patch.dict( + "os.environ", + {"OPENTELEMETRY_PYTHON_METER_PROVIDER": "reoverridden_meter_provider"}, + ) + def test_configuration_file_environment_variables(self, mock_home_path): + mock_home_path.return_value = getcwd() + + self.assertEqual( + Configuration().tracer_provider, "default_tracer_provider" + ) + self.assertEqual( + Configuration().meter_provider, "reoverridden_meter_provider" + ) + + def test_property(self): + with self.assertRaises(AttributeError): + Configuration().tracer_provider = "new_tracer_provider" + + def test_slots(self): + with self.assertRaises(AttributeError): + Configuration().xyz = "xyz" # pylint: disable=assigning-non-slot diff --git a/opentelemetry-api/tests/mypysmoke.py b/opentelemetry-api/tests/mypysmoke.py index bbbda93ef29..2891f3ee624 100644 --- a/opentelemetry-api/tests/mypysmoke.py +++ b/opentelemetry-api/tests/mypysmoke.py @@ -16,4 +16,4 @@ def dummy_check_mypy_returntype() -> opentelemetry.trace.TracerProvider: - return opentelemetry.trace.tracer_provider() + return opentelemetry.trace.get_tracer_provider() diff --git a/opentelemetry-api/tests/test_loader.py b/opentelemetry-api/tests/test_loader.py deleted file mode 100644 index 76575df705a..00000000000 --- a/opentelemetry-api/tests/test_loader.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2019, 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 sys -import unittest -from importlib import reload -from typing import Any, Callable - -from opentelemetry import trace -from opentelemetry.util import loader - -DUMMY_TRACER_PROVIDER = None - - -class DummyTracerProvider(trace.TracerProvider): - def get_tracer( - self, - instrumenting_module_name: str, - instrumenting_library_version: str = "", - ) -> "trace.Tracer": - return trace.DefaultTracer() - - -def get_opentelemetry_implementation(type_): - global DUMMY_TRACER_PROVIDER # pylint:disable=global-statement - assert type_ is trace.TracerProvider - DUMMY_TRACER_PROVIDER = DummyTracerProvider() - return DUMMY_TRACER_PROVIDER - - -# pylint:disable=redefined-outer-name,protected-access,unidiomatic-typecheck - - -class TestLoader(unittest.TestCase): - def setUp(self): - reload(loader) - reload(trace) - - # Need to reload self, otherwise DummyTracerProvider will have the wrong - # base class after reloading `trace`. - reload(sys.modules[__name__]) - - def test_get_default(self): - tracer_provider = trace.tracer_provider() - self.assertIs(type(tracer_provider), trace.DefaultTracerProvider) - - def test_preferred_impl(self): - trace.set_preferred_tracer_provider_implementation( - get_opentelemetry_implementation - ) - tracer_provider = trace.tracer_provider() - self.assertIs(tracer_provider, DUMMY_TRACER_PROVIDER) - - # NOTE: We use do_* + *_ methods because subtest wouldn't run setUp, - # which we require here. - def do_test_preferred_impl(self, setter: Callable[[Any], Any]) -> None: - setter(get_opentelemetry_implementation) - tracer_provider = trace.tracer_provider() - self.assertIs(tracer_provider, DUMMY_TRACER_PROVIDER) - - def test_preferred_impl_with_tracer(self): - self.do_test_preferred_impl( - trace.set_preferred_tracer_provider_implementation - ) - - def test_preferred_impl_with_default(self): - self.do_test_preferred_impl( - loader.set_preferred_default_implementation - ) - - def test_try_set_again(self): - self.assertTrue(trace.tracer_provider()) - # Try setting after the tracer_provider has already been created: - with self.assertRaises(RuntimeError) as einfo: - trace.set_preferred_tracer_provider_implementation( - get_opentelemetry_implementation - ) - self.assertIn("already loaded", str(einfo.exception)) - - def do_test_get_envvar(self, envvar_suffix: str) -> None: - global DUMMY_TRACER_PROVIDER # pylint:disable=global-statement - - # Test is not runnable with this! - self.assertFalse(sys.flags.ignore_environment) - - envname = "OPENTELEMETRY_PYTHON_IMPLEMENTATION_" + envvar_suffix - os.environ[envname] = __name__ - try: - tracer_provider = trace.tracer_provider() - self.assertIs(tracer_provider, DUMMY_TRACER_PROVIDER) - finally: - DUMMY_TRACER_PROVIDER = None - del os.environ[envname] - self.assertIs(type(tracer_provider), DummyTracerProvider) - - def test_get_envvar_tracer(self): - return self.do_test_get_envvar("TRACERPROVIDER") - - def test_get_envvar_default(self): - return self.do_test_get_envvar("DEFAULT") diff --git a/opentelemetry-api/tests/trace/test_globals.py b/opentelemetry-api/tests/trace/test_globals.py index 7c4d8e3549b..2e0339b99dd 100644 --- a/opentelemetry-api/tests/trace/test_globals.py +++ b/opentelemetry-api/tests/trace/test_globals.py @@ -1,40 +1,18 @@ -import importlib import unittest +from unittest.mock import patch from opentelemetry import trace class TestGlobals(unittest.TestCase): def setUp(self): - importlib.reload(trace) + self._patcher = patch("opentelemetry.trace._TRACER_PROVIDER") + self._mock_tracer_provider = self._patcher.start() - # This class has to be declared after the importlib reload, or else it - # will inherit from an old TracerProvider, rather than the new - # TracerProvider ABC created from reload. - - static_tracer = trace.DefaultTracer() - - class DummyTracerProvider(trace.TracerProvider): - """TracerProvider used for testing""" - - def get_tracer( - self, - instrumenting_module_name: str, - instrumenting_library_version: str = "", - ) -> trace.Tracer: - # pylint:disable=no-self-use,unused-argument - return static_tracer - - trace.set_preferred_tracer_provider_implementation( - lambda _: DummyTracerProvider() - ) - - @staticmethod - def tearDown() -> None: - importlib.reload(trace) + def tearDown(self) -> None: + self._patcher.stop() def test_get_tracer(self): """trace.get_tracer should proxy to the global tracer provider.""" - from_global_api = trace.get_tracer("foo") - from_tracer_api = trace.tracer_provider().get_tracer("foo") - self.assertIs(from_global_api, from_tracer_api) + trace.get_tracer("foo", "var") + self._mock_tracer_provider.get_tracer.assert_called_with("foo", "var") diff --git a/opentelemetry-sdk/setup.py b/opentelemetry-sdk/setup.py index 50fe925605c..c471ff02311 100644 --- a/opentelemetry-sdk/setup.py +++ b/opentelemetry-sdk/setup.py @@ -56,4 +56,12 @@ "/tree/master/opentelemetry-sdk" ), zip_safe=False, + entry_points={ + "opentelemetry_meter_provider": [ + "sdk_meter_provider = opentelemetry.sdk.metrics:MeterProvider" + ], + "opentelemetry_tracer_provider": [ + "sdk_tracer_provider = opentelemetry.sdk.trace:TracerProvider" + ], + }, ) diff --git a/tests/w3c_tracecontext_validation_server.py b/tests/w3c_tracecontext_validation_server.py index 4ec179c3545..40ac247f542 100644 --- a/tests/w3c_tracecontext_validation_server.py +++ b/tests/w3c_tracecontext_validation_server.py @@ -26,24 +26,19 @@ from opentelemetry import trace from opentelemetry.ext import http_requests from opentelemetry.ext.wsgi import OpenTelemetryMiddleware -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( ConsoleSpanExporter, SimpleExportSpanProcessor, ) -# The preferred tracer implementation must be set, as the opentelemetry-api -# defines the interface with a no-op implementation. -trace.set_preferred_tracer_provider_implementation(lambda T: TracerProvider()) - # 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.tracer_provider()) +http_requests.enable(trace.get_tracer_provider()) # SpanExporter receives the spans and send them to the target location. span_processor = SimpleExportSpanProcessor(ConsoleSpanExporter()) -trace.tracer_provider().add_span_processor(span_processor) +trace.get_tracer_provider().add_span_processor(span_processor) app = flask.Flask(__name__) app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app) From fd6f4e55953c7ef8379c44353ab14f9b8f32361d Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Tue, 10 Mar 2020 13:20:02 -0600 Subject: [PATCH 02/28] Revert to logger --- opentelemetry-api/src/opentelemetry/metrics/__init__.py | 4 ++-- opentelemetry-api/src/opentelemetry/trace/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py index 911fab1b79d..7cc1d9bb96c 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py @@ -34,7 +34,7 @@ from opentelemetry.configuration import Configuration -_LOGGER = getLogger(__name__) +logger = getLogger(__name__) ValueT = TypeVar("ValueT", int, float) @@ -435,7 +435,7 @@ def get_meter_provider() -> MeterProvider: # FIXME Decide on how to handle this. Should an exception be # raised here, or only a message should be logged and should # we fall back to the default meter provider? - _LOGGER.error( + logger.error( "Failed to load configured meter provider %s", configured_meter_provider, ) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index 05c6b962237..7c0165afb95 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -79,7 +79,7 @@ from opentelemetry.trace.status import Status from opentelemetry.util import types -_LOGGER = getLogger(__name__) +logger = getLogger(__name__) # TODO: quarantine ParentSpan = typing.Optional[typing.Union["Span", "SpanContext"]] @@ -678,7 +678,7 @@ def get_tracer_provider() -> TracerProvider: # FIXME Decide on how to handle this. Should an exception be # raised here, or only a message should be logged and should # we fall back to the default tracer provider? - _LOGGER.error( + logger.error( "Failed to load tracer implementation: %s", configured_tracer_provider, ) From 7009e686d075cf52821dec46077ce33a8238bf11 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Tue, 10 Mar 2020 23:51:43 -0600 Subject: [PATCH 03/28] Add missing conftest.py --- .../examples}/basic_tracer/tests/conftest.py | 0 .../examples}/http/tests/conftest.py | 0 .../tests/conftest.py | 25 ------------------- 3 files changed, 25 deletions(-) rename {examples => docs/examples}/basic_tracer/tests/conftest.py (100%) rename {examples => docs/examples}/http/tests/conftest.py (100%) delete mode 100644 examples/opentelemetry-example-app/tests/conftest.py diff --git a/examples/basic_tracer/tests/conftest.py b/docs/examples/basic_tracer/tests/conftest.py similarity index 100% rename from examples/basic_tracer/tests/conftest.py rename to docs/examples/basic_tracer/tests/conftest.py diff --git a/examples/http/tests/conftest.py b/docs/examples/http/tests/conftest.py similarity index 100% rename from examples/http/tests/conftest.py rename to docs/examples/http/tests/conftest.py diff --git a/examples/opentelemetry-example-app/tests/conftest.py b/examples/opentelemetry-example-app/tests/conftest.py deleted file mode 100644 index ff9e5ea43bb..00000000000 --- a/examples/opentelemetry-example-app/tests/conftest.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020, 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 - - -def pytest_sessionstart(session): # pylint: disable=unused-argument - environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" - environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" - - -def pytest_sessionfinish(session): # pylint: disable=unused-argument - environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") - environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") From 10f04fb57c62dcad34f232ea0ab889d7f117ebdc Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 12:29:26 -0600 Subject: [PATCH 04/28] Work around mypy issues --- .../src/opentelemetry/configuration/__init__.py | 5 ++++- .../src/opentelemetry/metrics/__init__.py | 12 ++++++------ .../src/opentelemetry/trace/__init__.py | 12 ++++++------ .../tests/configuration/test_configuration.py | 12 ++++++------ 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index 3e89f5f7d3a..fcf7dc15e12 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -12,6 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# FIXME find a better way to avoid all those "Expression has type "Any"" errors +# type: ignore + """ Simple configuration manager @@ -33,7 +36,7 @@ class Configuration: __slots__ = ["tracer_provider", "meter_provider"] - def __new__(cls): + def __new__(cls) -> "Configuration": if Configuration._instance is None: configuration = { diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py index 7cc1d9bb96c..e1f28089664 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py @@ -32,7 +32,7 @@ from pkg_resources import iter_entry_points -from opentelemetry.configuration import Configuration +from opentelemetry.configuration import Configuration # type: ignore logger = getLogger(__name__) ValueT = TypeVar("ValueT", int, float) @@ -422,13 +422,13 @@ def get_meter_provider() -> MeterProvider: if _METER_PROVIDER is None: configured_meter_provider = ( - Configuration().meter_provider # pylint: disable=no-member + Configuration().meter_provider # type: ignore # pylint: disable=no-member ) try: - _METER_PROVIDER = next( + _METER_PROVIDER = next( # type: ignore iter_entry_points( - "opentelemetry_meter_provider", configured_meter_provider + "opentelemetry_meter_provider", configured_meter_provider # type: ignore ) ).load()() except Exception: # pylint: disable=broad-except @@ -437,8 +437,8 @@ def get_meter_provider() -> MeterProvider: # we fall back to the default meter provider? logger.error( "Failed to load configured meter provider %s", - configured_meter_provider, + configured_meter_provider, # type: ignore ) raise - return _METER_PROVIDER + return _METER_PROVIDER # type: ignore diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index 7c0165afb95..f1309ae7a34 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -75,7 +75,7 @@ from pkg_resources import iter_entry_points -from opentelemetry.configuration import Configuration +from opentelemetry.configuration import Configuration # type: ignore from opentelemetry.trace.status import Status from opentelemetry.util import types @@ -664,14 +664,14 @@ def get_tracer_provider() -> TracerProvider: if _TRACER_PROVIDER is None: configured_tracer_provider = ( - Configuration().tracer_provider # pylint: disable=no-member + Configuration().tracer_provider # type: ignore # pylint: disable=no-member ) try: - _TRACER_PROVIDER = next( + _TRACER_PROVIDER = next( # type: ignore iter_entry_points( "opentelemetry_tracer_provider", - name=configured_tracer_provider, + name=configured_tracer_provider, # type: ignore ) ).load()() except Exception: # pylint: disable=broad-except @@ -680,8 +680,8 @@ def get_tracer_provider() -> TracerProvider: # we fall back to the default tracer provider? logger.error( "Failed to load tracer implementation: %s", - configured_tracer_provider, + configured_tracer_provider, # type: ignore ) raise - return _TRACER_PROVIDER + return _TRACER_PROVIDER # type: ignore diff --git a/opentelemetry-api/tests/configuration/test_configuration.py b/opentelemetry-api/tests/configuration/test_configuration.py index cd3b9aa3e0a..bb71a1de246 100644 --- a/opentelemetry-api/tests/configuration/test_configuration.py +++ b/opentelemetry-api/tests/configuration/test_configuration.py @@ -17,13 +17,13 @@ from unittest import TestCase from unittest.mock import patch -from opentelemetry.configuration import Configuration -from pytest import fixture # pylint: disable=import-error +from opentelemetry.configuration import Configuration # type: ignore +from pytest import fixture # type: ignore # pylint: disable=import-error class TestConfiguration(TestCase): @fixture(autouse=True) - def configdir(self, tmpdir): # pylint: disable=no-self-use + def configdir(self, tmpdir): # type: ignore # pylint: disable=no-self-use tmpdir.chdir() tmpdir.mkdir(".config").join("opentelemetry_python.json").write( dumps({"tracer_provider": "default_tracer_provider"}) @@ -39,7 +39,7 @@ def test_singleton(self): self.assertIs(Configuration(), Configuration()) @patch("pathlib.Path.home") - def test_configuration_file(self, mock_home_path): + def test_configuration_file(self, mock_home_path): # type: ignore mock_home_path.return_value = getcwd() self.assertEqual( @@ -53,7 +53,7 @@ def test_configuration_file(self, mock_home_path): "os.environ", {"OPENTELEMETRY_PYTHON_METER_PROVIDER": "overridden_meter_provider"}, ) - def test_environment_variables(self): + def test_environment_variables(self): # type: ignore self.assertEqual( Configuration().tracer_provider, "default_tracer_provider" ) # pylint: disable=no-member @@ -66,7 +66,7 @@ def test_environment_variables(self): "os.environ", {"OPENTELEMETRY_PYTHON_METER_PROVIDER": "reoverridden_meter_provider"}, ) - def test_configuration_file_environment_variables(self, mock_home_path): + def test_configuration_file_environment_variables(self, mock_home_path): # type: ignore mock_home_path.return_value = getcwd() self.assertEqual( From 32bb9d2edc8cbb8dd53199e8b449a9d64be278f3 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 13:06:58 -0600 Subject: [PATCH 05/28] Add workaround for tracecontext --- tests/w3c_tracecontext_validation_server.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/w3c_tracecontext_validation_server.py b/tests/w3c_tracecontext_validation_server.py index 40ac247f542..d5169d46e8b 100644 --- a/tests/w3c_tracecontext_validation_server.py +++ b/tests/w3c_tracecontext_validation_server.py @@ -23,6 +23,14 @@ import flask import requests +from os import environ + +# FIXME This could likely be avoided by integrating this script into the +# standard test running mechanisms. + +environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" +environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] ="sdk_meter_provider" + from opentelemetry import trace from opentelemetry.ext import http_requests from opentelemetry.ext.wsgi import OpenTelemetryMiddleware From 7dd05bd480167424bc4d553d679f99948234bd8e Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 13:48:58 -0600 Subject: [PATCH 06/28] Fix lint --- tests/w3c_tracecontext_validation_server.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/w3c_tracecontext_validation_server.py b/tests/w3c_tracecontext_validation_server.py index d5169d46e8b..ddbbbd383f0 100644 --- a/tests/w3c_tracecontext_validation_server.py +++ b/tests/w3c_tracecontext_validation_server.py @@ -19,22 +19,25 @@ """ import json +from os import environ import flask import requests -from os import environ - # FIXME This could likely be avoided by integrating this script into the # standard test running mechanisms. -environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" -environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] ="sdk_meter_provider" +environ[ + "OPENTELEMETRY_PYTHON_TRACER_PROVIDER" +] = "sdk_tracer_provider" # isort:skip +environ[ + "OPENTELEMETRY_PYTHON_METER_PROVIDER" +] = "sdk_meter_provider" # isort:skip -from opentelemetry import trace -from opentelemetry.ext import http_requests -from opentelemetry.ext.wsgi import OpenTelemetryMiddleware -from opentelemetry.sdk.trace.export import ( +from opentelemetry import trace # noqa # isort:skip +from opentelemetry.ext import http_requests # noqa # isort:skip" +from opentelemetry.ext.wsgi import OpenTelemetryMiddleware # noqa # isort:skip +from opentelemetry.sdk.trace.export import ( # noqa # isort:skip ConsoleSpanExporter, SimpleExportSpanProcessor, ) From b05eaa66d504d8d3e8e2ae4fec29649bcc64f689 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 14:04:47 -0600 Subject: [PATCH 07/28] Remove configuration file writing --- opentelemetry-api/setup.py | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/opentelemetry-api/setup.py b/opentelemetry-api/setup.py index eb10d24b94f..b2266dd23b4 100644 --- a/opentelemetry-api/setup.py +++ b/opentelemetry-api/setup.py @@ -12,8 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from os.path import dirname, exists, join -from pathlib import Path +from os.path import dirname, join import setuptools @@ -23,29 +22,6 @@ with open(VERSION_FILENAME) as f: exec(f.read(), PACKAGE_INFO) -# FIXME Make this script install the configuration file in -# ~/.config/opentelemetry_python.json -configuration_file_path = join( - Path.home(), ".config", "opentelemetry_python.json" -) - -data_files = [] - -if not exists(configuration_file_path): - data_files.append( - ( - dirname(configuration_file_path), - [ - join( - "src", - "opentelemetry", - "configuration", - "opentelemetry_python.json", - ) - ], - ) - ) - setuptools.setup( name="opentelemetry-api", version=PACKAGE_INFO["__version__"], @@ -100,5 +76,4 @@ "opentelemetry.trace:DefaultTracerProvider" ], }, - data_files=data_files, ) From 41c21eb1294ad15506d6570116c786f1fffadf70 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 15:27:58 -0600 Subject: [PATCH 08/28] Use expanduser --- .../src/opentelemetry/configuration/__init__.py | 5 ++--- .../tests/configuration/test_configuration.py | 12 ++++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index fcf7dc15e12..237a98eb41e 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -27,8 +27,7 @@ from json import load from os import environ -from os.path import exists, join -from pathlib import Path +from os.path import exists, join, expanduser class Configuration: @@ -44,7 +43,7 @@ def __new__(cls) -> "Configuration": } configuration_file_path = join( - Path.home(), ".config", "opentelemetry_python.json" + expanduser("~"), ".config", "opentelemetry_python.json" ) if exists(configuration_file_path): diff --git a/opentelemetry-api/tests/configuration/test_configuration.py b/opentelemetry-api/tests/configuration/test_configuration.py index bb71a1de246..0c78a0123a2 100644 --- a/opentelemetry-api/tests/configuration/test_configuration.py +++ b/opentelemetry-api/tests/configuration/test_configuration.py @@ -38,9 +38,9 @@ def tearDown(self): def test_singleton(self): self.assertIs(Configuration(), Configuration()) - @patch("pathlib.Path.home") - def test_configuration_file(self, mock_home_path): # type: ignore - mock_home_path.return_value = getcwd() + @patch("os.path.expanduser") + def test_configuration_file(self, mock_expanduser): # type: ignore + mock_expanduser.return_value = getcwd() self.assertEqual( Configuration().tracer_provider, "default_tracer_provider" @@ -61,13 +61,13 @@ def test_environment_variables(self): # type: ignore Configuration().meter_provider, "overridden_meter_provider" ) # pylint: disable=no-member - @patch("pathlib.Path.home") + @patch("os.path.expanduser") @patch.dict( "os.environ", {"OPENTELEMETRY_PYTHON_METER_PROVIDER": "reoverridden_meter_provider"}, ) - def test_configuration_file_environment_variables(self, mock_home_path): # type: ignore - mock_home_path.return_value = getcwd() + def test_configuration_file_environment_variables(self, mock_expanduser): # type: ignore + mock_expanduser.return_value = getcwd() self.assertEqual( Configuration().tracer_provider, "default_tracer_provider" From e685cb714b93f37f20f49cdef723a63111fcab0c Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 15:54:26 -0600 Subject: [PATCH 09/28] Fix lint --- opentelemetry-api/src/opentelemetry/configuration/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index 237a98eb41e..026e060323d 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -27,7 +27,7 @@ from json import load from os import environ -from os.path import exists, join, expanduser +from os.path import exists, expanduser, join class Configuration: From 00cfd7e491e2c26e1d2442fc4f8310d11865a81d Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 17:09:18 -0600 Subject: [PATCH 10/28] Update otcollector --- .../tests/conftest.py | 25 +++++++++++++++++++ .../test_otcollector_metrics_exporter.py | 15 +++-------- 2 files changed, 28 insertions(+), 12 deletions(-) create mode 100644 ext/opentelemetry-ext-otcollector/tests/conftest.py diff --git a/ext/opentelemetry-ext-otcollector/tests/conftest.py b/ext/opentelemetry-ext-otcollector/tests/conftest.py new file mode 100644 index 00000000000..ff9e5ea43bb --- /dev/null +++ b/ext/opentelemetry-ext-otcollector/tests/conftest.py @@ -0,0 +1,25 @@ +# Copyright 2020, 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 + + +def pytest_sessionstart(session): # pylint: disable=unused-argument + environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" + environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" + + +def pytest_sessionfinish(session): # pylint: disable=unused-argument + environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") + environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py b/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py index f58f9768d60..04b3ef0c42e 100644 --- a/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py +++ b/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py @@ -21,7 +21,7 @@ from opentelemetry import metrics from opentelemetry.ext.otcollector import metrics_exporter -from opentelemetry.sdk.metrics import Counter, Measure, MeterProvider +from opentelemetry.sdk.metrics import Counter, Measure from opentelemetry.sdk.metrics.export import ( MetricRecord, MetricsExportResult, @@ -34,13 +34,7 @@ class TestCollectorMetricsExporter(unittest.TestCase): @classmethod def setUpClass(cls): # pylint: disable=protected-access - cls._meter_defaults = ( - metrics._METER_PROVIDER, - metrics._METER_PROVIDER_FACTORY, - ) - metrics.set_preferred_meter_provider_implementation( - lambda _: MeterProvider() - ) + cls._meter_defaults = metrics._METER_PROVIDER cls._meter = metrics.get_meter(__name__) kvp = {"environment": "staging"} cls._test_label_set = cls._meter.get_label_set(kvp) @@ -48,10 +42,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): # pylint: disable=protected-access - ( - metrics._METER_PROVIDER, - metrics._METER_PROVIDER_FACTORY, - ) = cls._meter_defaults + metrics._METER_PROVIDER = cls._meter_defaults def test_constructor(self): mock_get_node = mock.Mock() From a684297d3ddd5b9deb14fb831535a19064fd4c5e Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 17:27:58 -0600 Subject: [PATCH 11/28] Fix lint --- examples/metrics/collector.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/metrics/collector.py b/examples/metrics/collector.py index 230b2963934..25bc4ef9152 100644 --- a/examples/metrics/collector.py +++ b/examples/metrics/collector.py @@ -21,11 +21,10 @@ from opentelemetry.ext.otcollector.metrics_exporter import ( CollectorMetricsExporter, ) -from opentelemetry.sdk.metrics import Counter, MeterProvider +from opentelemetry.sdk.metrics import Counter from opentelemetry.sdk.metrics.export.controller import PushController # Meter is responsible for creating and recording metrics -metrics.set_preferred_meter_provider_implementation(lambda _: MeterProvider()) meter = metrics.get_meter(__name__) # exporter to export metrics to OT Collector exporter = CollectorMetricsExporter( From e2e0bcc822e7b2be42699af92a055cfda2c253fd Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 17:29:11 -0600 Subject: [PATCH 12/28] Update opentelemetry-api/src/opentelemetry/configuration/__init__.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Mauricio Vásquez --- opentelemetry-api/src/opentelemetry/configuration/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index 026e060323d..34fa2afa8fe 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -33,7 +33,7 @@ class Configuration: _instance = None - __slots__ = ["tracer_provider", "meter_provider"] + __slots__ = ("tracer_provider", "meter_provider") def __new__(cls) -> "Configuration": if Configuration._instance is None: From f54234bd2815a7ae7869ee5fd369f7f76308ad7f Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 17:29:25 -0600 Subject: [PATCH 13/28] Update opentelemetry-api/src/opentelemetry/configuration/__init__.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Mauricio Vásquez --- .../src/opentelemetry/configuration/__init__.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index 34fa2afa8fe..b010dec29d1 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -60,19 +60,10 @@ def __new__(cls) -> "Configuration": ) for key, value in configuration.items(): - underscored_key = "_{}".format(key) - - setattr(Configuration, underscored_key, value) setattr( Configuration, key, - property( - ( - lambda underscored_key: lambda self: getattr( - self, underscored_key - ) - )(underscored_key) - ), + property(lambda self, local_value=value: local_value), ) Configuration._instance = object.__new__(cls) From 342278adb1c50e351be33a64e8b0040d0b71e8f9 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 17:54:58 -0600 Subject: [PATCH 14/28] Fix lint --- .../tests/configuration/test_configuration.py | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/opentelemetry-api/tests/configuration/test_configuration.py b/opentelemetry-api/tests/configuration/test_configuration.py index 0c78a0123a2..7cefa060294 100644 --- a/opentelemetry-api/tests/configuration/test_configuration.py +++ b/opentelemetry-api/tests/configuration/test_configuration.py @@ -26,7 +26,7 @@ class TestConfiguration(TestCase): def configdir(self, tmpdir): # type: ignore # pylint: disable=no-self-use tmpdir.chdir() tmpdir.mkdir(".config").join("opentelemetry_python.json").write( - dumps({"tracer_provider": "default_tracer_provider"}) + dumps({"tracer_provider": "overridden_tracer_provider"}) ) def setUp(self): @@ -38,12 +38,20 @@ def tearDown(self): def test_singleton(self): self.assertIs(Configuration(), Configuration()) - @patch("os.path.expanduser") + def test_default_values(self): + self.assertEqual( + Configuration().tracer_provider, "default_tracer_provider" + ) # pylint: disable=no-member + self.assertEqual( + Configuration().meter_provider, "default_meter_provider" + ) # pylint: disable=no-member + + @patch("opentelemetry.configuration.expanduser") def test_configuration_file(self, mock_expanduser): # type: ignore mock_expanduser.return_value = getcwd() self.assertEqual( - Configuration().tracer_provider, "default_tracer_provider" + Configuration().tracer_provider, "overridden_tracer_provider" ) # pylint: disable=no-member self.assertEqual( Configuration().meter_provider, "default_meter_provider" @@ -61,19 +69,23 @@ def test_environment_variables(self): # type: ignore Configuration().meter_provider, "overridden_meter_provider" ) # pylint: disable=no-member - @patch("os.path.expanduser") + @patch("opentelemetry.configuration.expanduser") @patch.dict( "os.environ", - {"OPENTELEMETRY_PYTHON_METER_PROVIDER": "reoverridden_meter_provider"}, + { + "OPENTELEMETRY_PYTHON_TRACER_PROVIDER": ( + "reoverridden_tracer_provider" + ) + }, ) def test_configuration_file_environment_variables(self, mock_expanduser): # type: ignore mock_expanduser.return_value = getcwd() self.assertEqual( - Configuration().tracer_provider, "default_tracer_provider" + Configuration().tracer_provider, "reoverridden_tracer_provider" ) self.assertEqual( - Configuration().meter_provider, "reoverridden_meter_provider" + Configuration().meter_provider, "default_meter_provider" ) def test_property(self): From f5df21ac532aff7000cd6d31674831234fbe6de6 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 18:18:06 -0600 Subject: [PATCH 15/28] Revert changes that should not be in this PR --- docs/examples/http/tests/test_http.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/examples/http/tests/test_http.py b/docs/examples/http/tests/test_http.py index 0444e8d67d6..0ae81fe7de7 100644 --- a/docs/examples/http/tests/test_http.py +++ b/docs/examples/http/tests/test_http.py @@ -19,10 +19,11 @@ class TestHttpExample(unittest.TestCase): - def setUp(self): + @classmethod + def setup_class(cls): dirpath = os.path.dirname(os.path.realpath(__file__)) server_script = "{}/../server.py".format(dirpath) - self.server = subprocess.Popen([sys.executable, server_script]) + cls.server = subprocess.Popen([sys.executable, server_script]) sleep(1) def test_http(self): @@ -33,5 +34,6 @@ def test_http(self): ).decode() self.assertIn('name="/"', output) - def tearDown(self): - self.server.terminate() + @classmethod + def teardown_class(cls): + cls.server.terminate() From cbc1a03e27c9f44be3db64723b063e45c35741e1 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Wed, 11 Mar 2020 18:23:19 -0600 Subject: [PATCH 16/28] Fix lint --- opentelemetry-api/src/opentelemetry/metrics/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py index e1f28089664..4d13874fd34 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py @@ -428,7 +428,8 @@ def get_meter_provider() -> MeterProvider: try: _METER_PROVIDER = next( # type: ignore iter_entry_points( - "opentelemetry_meter_provider", configured_meter_provider # type: ignore + "opentelemetry_meter_provider", + name=configured_meter_provider, # type: ignore ) ).load()() except Exception: # pylint: disable=broad-except From cfcc34c8a17235e3d3d48d58b478fe09bf9ced6a Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 12 Mar 2020 18:03:53 -0600 Subject: [PATCH 17/28] Move iter_entry_points into the configuration manager --- .../opentelemetry/configuration/__init__.py | 40 ++++++++++++- .../src/opentelemetry/metrics/__init__.py | 28 +++------ .../src/opentelemetry/trace/__init__.py | 29 +++------- .../tests/configuration/test_configuration.py | 58 +++++++++++++++++-- 4 files changed, 107 insertions(+), 48 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index b010dec29d1..79a67f7268b 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -28,6 +28,10 @@ from json import load from os import environ from os.path import exists, expanduser, join +from pkg_resources import iter_entry_points +from logging import getLogger + +logger = getLogger(__name__) class Configuration: @@ -60,12 +64,46 @@ def __new__(cls) -> "Configuration": ) for key, value in configuration.items(): + underscored_key = "_{}".format(key) + + setattr(Configuration, underscored_key, None) setattr( Configuration, key, - property(lambda self, local_value=value: local_value), + property( + fget=lambda cls, local_key=key, local_value=value: + cls._load(key=local_key, value=local_value) + ), ) Configuration._instance = object.__new__(cls) return cls._instance + + @classmethod + def _load(cls, key=None, value=None): + underscored_key = "_{}".format(key) + + if getattr(cls, underscored_key) is None: + try: + setattr( + cls, + underscored_key, + next( # type: ignore + iter_entry_points( + "opentelemetry_{}".format(key), + name=value, # type: ignore + ) + ).load()() + ) + except Exception: # pylint: disable=broad-except + # FIXME Decide on how to handle this. Should an exception be + # raised here, or only a message should be logged and should + # we fall back to the default meter provider? + logger.error( + "Failed to load configured provider %s", + value, # type: ignore + ) + raise + + return getattr(cls, underscored_key) diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py index 4d13874fd34..3d471f1c540 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py @@ -30,7 +30,6 @@ from logging import getLogger from typing import Callable, Dict, Sequence, Tuple, Type, TypeVar -from pkg_resources import iter_entry_points from opentelemetry.configuration import Configuration # type: ignore @@ -416,30 +415,17 @@ def get_meter( ) +def set_meter_provider(meter_provider: MeterProvider) -> None: + """Sets the current global :class:`~.MeterProvider` object.""" + global _METER_PROVIDER + _METER_PROVIDER = meter_provider + + def get_meter_provider() -> MeterProvider: """Gets the current global :class:`~.MeterProvider` object.""" global _METER_PROVIDER # pylint: disable=global-statement if _METER_PROVIDER is None: - configured_meter_provider = ( - Configuration().meter_provider # type: ignore # pylint: disable=no-member - ) - - try: - _METER_PROVIDER = next( # type: ignore - iter_entry_points( - "opentelemetry_meter_provider", - name=configured_meter_provider, # type: ignore - ) - ).load()() - except Exception: # pylint: disable=broad-except - # FIXME Decide on how to handle this. Should an exception be - # raised here, or only a message should be logged and should - # we fall back to the default meter provider? - logger.error( - "Failed to load configured meter provider %s", - configured_meter_provider, # type: ignore - ) - raise + _METER_PROVIDER = Configuration().meter_provider return _METER_PROVIDER # type: ignore diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index f1309ae7a34..fac88ba9f09 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -73,8 +73,6 @@ from contextlib import contextmanager from logging import getLogger -from pkg_resources import iter_entry_points - from opentelemetry.configuration import Configuration # type: ignore from opentelemetry.trace.status import Status from opentelemetry.util import types @@ -658,30 +656,17 @@ def get_tracer( ) +def set_tracer_provider(tracer_provider: TracerProvider) -> None: + """Sets the current global :class:`~.TracerProvider` object.""" + global _TRACER_PROVIDER + _TRACER_PROVIDER = tracer_provider + + def get_tracer_provider() -> TracerProvider: """Gets the current global :class:`~.TracerProvider` object.""" global _TRACER_PROVIDER # pylint: disable=global-statement if _TRACER_PROVIDER is None: - configured_tracer_provider = ( - Configuration().tracer_provider # type: ignore # pylint: disable=no-member - ) - - try: - _TRACER_PROVIDER = next( # type: ignore - iter_entry_points( - "opentelemetry_tracer_provider", - name=configured_tracer_provider, # type: ignore - ) - ).load()() - except Exception: # pylint: disable=broad-except - # FIXME Decide on how to handle this. Should an exception be - # raised here, or only a message should be logged and should - # we fall back to the default tracer provider? - logger.error( - "Failed to load tracer implementation: %s", - configured_tracer_provider, # type: ignore - ) - raise + _TRACER_PROVIDER = Configuration().tracer_provider return _TRACER_PROVIDER # type: ignore diff --git a/opentelemetry-api/tests/configuration/test_configuration.py b/opentelemetry-api/tests/configuration/test_configuration.py index 7cefa060294..bcdf3ce8172 100644 --- a/opentelemetry-api/tests/configuration/test_configuration.py +++ b/opentelemetry-api/tests/configuration/test_configuration.py @@ -22,6 +22,19 @@ class TestConfiguration(TestCase): + class IterEntryPointsMock: + def __init__(self, argument, name=None): + self._name = name + + def __next__(self): + return self + + def __call__(self): + return self._name + + def load(self): + return self + @fixture(autouse=True) def configdir(self, tmpdir): # type: ignore # pylint: disable=no-self-use tmpdir.chdir() @@ -38,7 +51,26 @@ def tearDown(self): def test_singleton(self): self.assertIs(Configuration(), Configuration()) - def test_default_values(self): + @patch( + "opentelemetry.configuration.iter_entry_points", + **{"side_effect": IterEntryPointsMock} + ) + def test_lazy(self, mock_iter_entry_points): + configuration = Configuration() + + self.assertIsNone(configuration._tracer_provider) + + configuration.tracer_provider + + self.assertEqual( + configuration._tracer_provider, "default_tracer_provider" + ) + + @patch( + "opentelemetry.configuration.iter_entry_points", + **{"side_effect": IterEntryPointsMock} + ) + def test_default_values(self, mock_iter_entry_points): self.assertEqual( Configuration().tracer_provider, "default_tracer_provider" ) # pylint: disable=no-member @@ -46,8 +78,14 @@ def test_default_values(self): Configuration().meter_provider, "default_meter_provider" ) # pylint: disable=no-member + @patch( + "opentelemetry.configuration.iter_entry_points", + **{"side_effect": IterEntryPointsMock} + ) @patch("opentelemetry.configuration.expanduser") - def test_configuration_file(self, mock_expanduser): # type: ignore + def test_configuration_file( + self, mock_expanduser, mock_iter_entry_points + ): # type: ignore mock_expanduser.return_value = getcwd() self.assertEqual( @@ -57,11 +95,17 @@ def test_configuration_file(self, mock_expanduser): # type: ignore Configuration().meter_provider, "default_meter_provider" ) # pylint: disable=no-member + @patch( + "opentelemetry.configuration.iter_entry_points", + **{"side_effect": IterEntryPointsMock} + ) @patch.dict( "os.environ", {"OPENTELEMETRY_PYTHON_METER_PROVIDER": "overridden_meter_provider"}, ) - def test_environment_variables(self): # type: ignore + def test_environment_variables( + self, mock_iter_entry_points + ): # type: ignore self.assertEqual( Configuration().tracer_provider, "default_tracer_provider" ) # pylint: disable=no-member @@ -69,6 +113,10 @@ def test_environment_variables(self): # type: ignore Configuration().meter_provider, "overridden_meter_provider" ) # pylint: disable=no-member + @patch( + "opentelemetry.configuration.iter_entry_points", + **{"side_effect": IterEntryPointsMock} + ) @patch("opentelemetry.configuration.expanduser") @patch.dict( "os.environ", @@ -78,7 +126,9 @@ def test_environment_variables(self): # type: ignore ) }, ) - def test_configuration_file_environment_variables(self, mock_expanduser): # type: ignore + def test_configuration_file_environment_variables( + self, mock_expanduser, mock_iter_entry_points + ): # type: ignore mock_expanduser.return_value = getcwd() self.assertEqual( From 5adb183098f4771a69013fed3f27b2d5b0b94912 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 12 Mar 2020 18:40:26 -0600 Subject: [PATCH 18/28] Fix test cases for exts --- ext/opentelemetry-ext-flask/tests/conftest.py | 25 ------------------- .../tests/conftest.py | 25 ------------------- .../tests/test_shim.py | 3 ++- .../tests/conftest.py | 25 ------------------- .../test_otcollector_metrics_exporter.py | 8 ++---- .../tests/conftest.py | 25 ------------------- .../tests/test_prometheus_exporter.py | 3 ++- .../ext/testutil/wsgitestutil.py | 3 ++- ext/opentelemetry-ext-wsgi/tests/conftest.py | 25 ------------------- 9 files changed, 8 insertions(+), 134 deletions(-) delete mode 100644 ext/opentelemetry-ext-flask/tests/conftest.py delete mode 100644 ext/opentelemetry-ext-opentracing-shim/tests/conftest.py delete mode 100644 ext/opentelemetry-ext-otcollector/tests/conftest.py delete mode 100644 ext/opentelemetry-ext-prometheus/tests/conftest.py delete mode 100644 ext/opentelemetry-ext-wsgi/tests/conftest.py diff --git a/ext/opentelemetry-ext-flask/tests/conftest.py b/ext/opentelemetry-ext-flask/tests/conftest.py deleted file mode 100644 index ff9e5ea43bb..00000000000 --- a/ext/opentelemetry-ext-flask/tests/conftest.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020, 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 - - -def pytest_sessionstart(session): # pylint: disable=unused-argument - environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" - environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" - - -def pytest_sessionfinish(session): # pylint: disable=unused-argument - environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") - environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/ext/opentelemetry-ext-opentracing-shim/tests/conftest.py b/ext/opentelemetry-ext-opentracing-shim/tests/conftest.py deleted file mode 100644 index ff9e5ea43bb..00000000000 --- a/ext/opentelemetry-ext-opentracing-shim/tests/conftest.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020, 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 - - -def pytest_sessionstart(session): # pylint: disable=unused-argument - environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" - environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" - - -def pytest_sessionfinish(session): # pylint: disable=unused-argument - environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") - environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py b/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py index 8a025be0368..9c8b57ebbc6 100644 --- a/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py +++ b/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py @@ -24,6 +24,7 @@ import opentelemetry.ext.opentracing_shim as opentracingshim from opentelemetry import propagators, trace from opentelemetry.context import Context +from opentelemetry.sdk.trace import TracerProvider from opentelemetry.ext.opentracing_shim import util from opentelemetry.trace.propagation import ( get_span_from_context, @@ -42,7 +43,7 @@ class TestShim(TestCase): def setUp(self): """Create an OpenTelemetry tracer and a shim before every test case.""" - + trace.set_tracer_provider(TracerProvider()) self.shim = opentracingshim.create_tracer(trace.get_tracer_provider()) @classmethod diff --git a/ext/opentelemetry-ext-otcollector/tests/conftest.py b/ext/opentelemetry-ext-otcollector/tests/conftest.py deleted file mode 100644 index ff9e5ea43bb..00000000000 --- a/ext/opentelemetry-ext-otcollector/tests/conftest.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020, 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 - - -def pytest_sessionstart(session): # pylint: disable=unused-argument - environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" - environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" - - -def pytest_sessionfinish(session): # pylint: disable=unused-argument - environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") - environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py b/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py index 04b3ef0c42e..5bb22e983ab 100644 --- a/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py +++ b/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py @@ -20,6 +20,7 @@ from opencensus.proto.metrics.v1 import metrics_pb2 from opentelemetry import metrics +from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.ext.otcollector import metrics_exporter from opentelemetry.sdk.metrics import Counter, Measure from opentelemetry.sdk.metrics.export import ( @@ -34,16 +35,11 @@ class TestCollectorMetricsExporter(unittest.TestCase): @classmethod def setUpClass(cls): # pylint: disable=protected-access - cls._meter_defaults = metrics._METER_PROVIDER + metrics.set_meter_provider(MeterProvider()) cls._meter = metrics.get_meter(__name__) kvp = {"environment": "staging"} cls._test_label_set = cls._meter.get_label_set(kvp) - @classmethod - def tearDownClass(cls): - # pylint: disable=protected-access - metrics._METER_PROVIDER = cls._meter_defaults - def test_constructor(self): mock_get_node = mock.Mock() patch = mock.patch( diff --git a/ext/opentelemetry-ext-prometheus/tests/conftest.py b/ext/opentelemetry-ext-prometheus/tests/conftest.py deleted file mode 100644 index ff9e5ea43bb..00000000000 --- a/ext/opentelemetry-ext-prometheus/tests/conftest.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020, 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 - - -def pytest_sessionstart(session): # pylint: disable=unused-argument - environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" - environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" - - -def pytest_sessionfinish(session): # pylint: disable=unused-argument - environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") - environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py b/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py index a0079b1fee1..0e01030e416 100644 --- a/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py +++ b/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py @@ -21,7 +21,7 @@ CustomCollector, PrometheusMetricsExporter, ) -from opentelemetry.metrics import get_meter_provider +from opentelemetry.metrics import set_meter_provider, get_meter_provider from opentelemetry.sdk import metrics from opentelemetry.sdk.metrics.export import MetricRecord, MetricsExportResult from opentelemetry.sdk.metrics.export.aggregate import CounterAggregator @@ -29,6 +29,7 @@ class TestPrometheusMetricExporter(unittest.TestCase): def setUp(self): + set_meter_provider(metrics.MeterProvider()) self._meter = get_meter_provider().get_meter(__name__) self._test_metric = self._meter.create_metric( "testname", diff --git a/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py b/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py index 39c2be27f9e..6ebcd55ff09 100644 --- a/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py +++ b/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py @@ -4,7 +4,7 @@ from importlib import reload from opentelemetry import trace as trace_api -from opentelemetry.sdk.trace import export +from opentelemetry.sdk.trace import export, TracerProvider from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( InMemorySpanExporter, ) @@ -16,6 +16,7 @@ class WsgiTestBase(unittest.TestCase): @classmethod def setUpClass(cls): global _MEMORY_EXPORTER # pylint:disable=global-statement + trace_api.set_tracer_provider(TracerProvider()) tracer_provider = trace_api.get_tracer_provider() _MEMORY_EXPORTER = InMemorySpanExporter() span_processor = export.SimpleExportSpanProcessor(_MEMORY_EXPORTER) diff --git a/ext/opentelemetry-ext-wsgi/tests/conftest.py b/ext/opentelemetry-ext-wsgi/tests/conftest.py deleted file mode 100644 index ff9e5ea43bb..00000000000 --- a/ext/opentelemetry-ext-wsgi/tests/conftest.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020, 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 - - -def pytest_sessionstart(session): # pylint: disable=unused-argument - environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" - environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" - - -def pytest_sessionfinish(session): # pylint: disable=unused-argument - environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") - environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") From cfc1a09377d7c18b3f57fb5dff259e6d11333fb1 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 12 Mar 2020 18:44:53 -0600 Subject: [PATCH 19/28] Remove remaining conftest.py files --- docs/examples/basic_tracer/tests/conftest.py | 25 -------------------- docs/examples/basic_tracer/tracer.py | 2 ++ docs/examples/http/server.py | 2 ++ docs/examples/http/tests/conftest.py | 25 -------------------- docs/examples/http/tracer_client.py | 2 ++ 5 files changed, 6 insertions(+), 50 deletions(-) delete mode 100644 docs/examples/basic_tracer/tests/conftest.py delete mode 100644 docs/examples/http/tests/conftest.py diff --git a/docs/examples/basic_tracer/tests/conftest.py b/docs/examples/basic_tracer/tests/conftest.py deleted file mode 100644 index ff9e5ea43bb..00000000000 --- a/docs/examples/basic_tracer/tests/conftest.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020, 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 - - -def pytest_sessionstart(session): # pylint: disable=unused-argument - environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" - environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" - - -def pytest_sessionfinish(session): # pylint: disable=unused-argument - environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") - environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/docs/examples/basic_tracer/tracer.py b/docs/examples/basic_tracer/tracer.py index a8ba537cc9c..92f96be89fd 100755 --- a/docs/examples/basic_tracer/tracer.py +++ b/docs/examples/basic_tracer/tracer.py @@ -17,6 +17,7 @@ import os from opentelemetry import trace +from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( BatchExportSpanProcessor, ConsoleSpanExporter, @@ -52,6 +53,7 @@ # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) +trace.set_tracer_provider(TracerProvider()) trace.get_tracer_provider().add_span_processor(span_processor) with tracer.start_as_current_span("foo"): with tracer.start_as_current_span("bar"): diff --git a/docs/examples/http/server.py b/docs/examples/http/server.py index d706a269606..34c501a0759 100755 --- a/docs/examples/http/server.py +++ b/docs/examples/http/server.py @@ -20,6 +20,7 @@ import requests from opentelemetry import trace +from opentelemetry.sdk.trace import TracerProvider from opentelemetry.ext import http_requests from opentelemetry.ext.wsgi import OpenTelemetryMiddleware from opentelemetry.sdk.trace.export import ( @@ -42,6 +43,7 @@ # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) +trace.set_tracer_provider(TracerProvider()) trace.get_tracer_provider().add_span_processor(span_processor) # Integrations are the glue that binds the OpenTelemetry API and the diff --git a/docs/examples/http/tests/conftest.py b/docs/examples/http/tests/conftest.py deleted file mode 100644 index ff9e5ea43bb..00000000000 --- a/docs/examples/http/tests/conftest.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020, 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 - - -def pytest_sessionstart(session): # pylint: disable=unused-argument - environ["OPENTELEMETRY_PYTHON_TRACER_PROVIDER"] = "sdk_tracer_provider" - environ["OPENTELEMETRY_PYTHON_METER_PROVIDER"] = "sdk_meter_provider" - - -def pytest_sessionfinish(session): # pylint: disable=unused-argument - environ.pop("OPENTELEMETRY_PYTHON_TRACER_PROVIDER") - environ.pop("OPENTELEMETRY_PYTHON_METER_PROVIDER") diff --git a/docs/examples/http/tracer_client.py b/docs/examples/http/tracer_client.py index 3ae6dc9ffed..593596df430 100755 --- a/docs/examples/http/tracer_client.py +++ b/docs/examples/http/tracer_client.py @@ -19,6 +19,7 @@ import requests from opentelemetry import trace +from opentelemetry.sdk.trace import TracerProvider from opentelemetry.ext import http_requests from opentelemetry.sdk.trace.export import ( BatchExportSpanProcessor, @@ -36,6 +37,7 @@ else: exporter = ConsoleSpanExporter() +trace.set_tracer_provider(TracerProvider()) tracer_provider = trace.get_tracer_provider() # SpanExporter receives the spans and send them to the target location. From aed33989b94d6619c0918d3a66bd28d728be4fa1 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 12 Mar 2020 19:03:30 -0600 Subject: [PATCH 20/28] Fixing lint WIP --- docs/examples/http/server.py | 2 +- docs/examples/http/tracer_client.py | 2 +- .../tests/test_shim.py | 2 +- .../tests/test_otcollector_metrics_exporter.py | 3 +-- .../tests/test_prometheus_exporter.py | 2 +- .../src/opentelemetry/ext/testutil/wsgitestutil.py | 2 +- .../src/opentelemetry/configuration/__init__.py | 10 ++++++---- .../src/opentelemetry/metrics/__init__.py | 1 - 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/examples/http/server.py b/docs/examples/http/server.py index 34c501a0759..a665abdd49d 100755 --- a/docs/examples/http/server.py +++ b/docs/examples/http/server.py @@ -20,9 +20,9 @@ import requests from opentelemetry import trace -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.ext import http_requests from opentelemetry.ext.wsgi import OpenTelemetryMiddleware +from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( BatchExportSpanProcessor, ConsoleSpanExporter, diff --git a/docs/examples/http/tracer_client.py b/docs/examples/http/tracer_client.py index 593596df430..0e83c5c53ff 100755 --- a/docs/examples/http/tracer_client.py +++ b/docs/examples/http/tracer_client.py @@ -19,8 +19,8 @@ import requests from opentelemetry import trace -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.ext import http_requests +from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( BatchExportSpanProcessor, ConsoleSpanExporter, diff --git a/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py b/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py index 9c8b57ebbc6..1d619ab2770 100644 --- a/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py +++ b/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py @@ -24,8 +24,8 @@ import opentelemetry.ext.opentracing_shim as opentracingshim from opentelemetry import propagators, trace from opentelemetry.context import Context -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.ext.opentracing_shim import util +from opentelemetry.sdk.trace import TracerProvider from opentelemetry.trace.propagation import ( get_span_from_context, set_span_in_context, diff --git a/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py b/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py index 5bb22e983ab..ab6f4c8ccd5 100644 --- a/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py +++ b/ext/opentelemetry-ext-otcollector/tests/test_otcollector_metrics_exporter.py @@ -20,9 +20,8 @@ from opencensus.proto.metrics.v1 import metrics_pb2 from opentelemetry import metrics -from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.ext.otcollector import metrics_exporter -from opentelemetry.sdk.metrics import Counter, Measure +from opentelemetry.sdk.metrics import Counter, Measure, MeterProvider from opentelemetry.sdk.metrics.export import ( MetricRecord, MetricsExportResult, diff --git a/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py b/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py index 0e01030e416..512a3170adb 100644 --- a/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py +++ b/ext/opentelemetry-ext-prometheus/tests/test_prometheus_exporter.py @@ -21,7 +21,7 @@ CustomCollector, PrometheusMetricsExporter, ) -from opentelemetry.metrics import set_meter_provider, get_meter_provider +from opentelemetry.metrics import get_meter_provider, set_meter_provider from opentelemetry.sdk import metrics from opentelemetry.sdk.metrics.export import MetricRecord, MetricsExportResult from opentelemetry.sdk.metrics.export.aggregate import CounterAggregator diff --git a/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py b/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py index 6ebcd55ff09..cdce28b9078 100644 --- a/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py +++ b/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py @@ -4,7 +4,7 @@ from importlib import reload from opentelemetry import trace as trace_api -from opentelemetry.sdk.trace import export, TracerProvider +from opentelemetry.sdk.trace import TracerProvider, export from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( InMemorySpanExporter, ) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index 79a67f7268b..8ecd32ee36f 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -26,10 +26,11 @@ """ from json import load +from logging import getLogger from os import environ from os.path import exists, expanduser, join + from pkg_resources import iter_entry_points -from logging import getLogger logger = getLogger(__name__) @@ -71,8 +72,9 @@ def __new__(cls) -> "Configuration": Configuration, key, property( - fget=lambda cls, local_key=key, local_value=value: - cls._load(key=local_key, value=local_value) + fget=lambda cls, local_key=key, local_value=value: cls._load( + key=local_key, value=local_value + ) ), ) @@ -94,7 +96,7 @@ def _load(cls, key=None, value=None): "opentelemetry_{}".format(key), name=value, # type: ignore ) - ).load()() + ).load()(), ) except Exception: # pylint: disable=broad-except # FIXME Decide on how to handle this. Should an exception be diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py index 3d471f1c540..b7aa102f639 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py @@ -30,7 +30,6 @@ from logging import getLogger from typing import Callable, Dict, Sequence, Tuple, Type, TypeVar - from opentelemetry.configuration import Configuration # type: ignore logger = getLogger(__name__) From 7703cdddaadef2058786a24e4735264d64dee25b Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 13 Mar 2020 11:19:14 -0600 Subject: [PATCH 21/28] Fix lint --- .../src/opentelemetry/metrics/__init__.py | 6 ++-- .../src/opentelemetry/trace/__init__.py | 6 ++-- .../tests/configuration/test_configuration.py | 31 +++++++++++++------ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py index b7aa102f639..fccaa04fc1d 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py @@ -416,7 +416,7 @@ def get_meter( def set_meter_provider(meter_provider: MeterProvider) -> None: """Sets the current global :class:`~.MeterProvider` object.""" - global _METER_PROVIDER + global _METER_PROVIDER # pylint: disable=global-statement _METER_PROVIDER = meter_provider @@ -425,6 +425,8 @@ def get_meter_provider() -> MeterProvider: global _METER_PROVIDER # pylint: disable=global-statement if _METER_PROVIDER is None: - _METER_PROVIDER = Configuration().meter_provider + _METER_PROVIDER = ( + Configuration().meter_provider # pylint: disable=no-member + ) return _METER_PROVIDER # type: ignore diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index fac88ba9f09..aae94f58b84 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -658,7 +658,7 @@ def get_tracer( def set_tracer_provider(tracer_provider: TracerProvider) -> None: """Sets the current global :class:`~.TracerProvider` object.""" - global _TRACER_PROVIDER + global _TRACER_PROVIDER # pylint: disable=global-statement _TRACER_PROVIDER = tracer_provider @@ -667,6 +667,8 @@ def get_tracer_provider() -> TracerProvider: global _TRACER_PROVIDER # pylint: disable=global-statement if _TRACER_PROVIDER is None: - _TRACER_PROVIDER = Configuration().tracer_provider + _TRACER_PROVIDER = ( + Configuration().tracer_provider # pylint: disable=no-member + ) return _TRACER_PROVIDER # type: ignore diff --git a/opentelemetry-api/tests/configuration/test_configuration.py b/opentelemetry-api/tests/configuration/test_configuration.py index bcdf3ce8172..c8a6fdbfca3 100644 --- a/opentelemetry-api/tests/configuration/test_configuration.py +++ b/opentelemetry-api/tests/configuration/test_configuration.py @@ -23,7 +23,9 @@ class TestConfiguration(TestCase): class IterEntryPointsMock: - def __init__(self, argument, name=None): + def __init__( + self, argument, name=None + ): # pylint: disable=unused-argument self._name = name def __next__(self): @@ -55,22 +57,29 @@ def test_singleton(self): "opentelemetry.configuration.iter_entry_points", **{"side_effect": IterEntryPointsMock} ) - def test_lazy(self, mock_iter_entry_points): + def test_lazy( + self, mock_iter_entry_points, # pylint: disable=unused-argument + ): configuration = Configuration() - self.assertIsNone(configuration._tracer_provider) + self.assertIsNone( + configuration._tracer_provider # pylint: disable=no-member,protected-access + ) - configuration.tracer_provider + configuration.tracer_provider # pylint: disable=pointless-statement self.assertEqual( - configuration._tracer_provider, "default_tracer_provider" + configuration._tracer_provider, # pylint: disable=no-member,protected-access + "default_tracer_provider", ) @patch( "opentelemetry.configuration.iter_entry_points", **{"side_effect": IterEntryPointsMock} ) - def test_default_values(self, mock_iter_entry_points): + def test_default_values( + self, mock_iter_entry_points # pylint: disable=unused-argument + ): self.assertEqual( Configuration().tracer_provider, "default_tracer_provider" ) # pylint: disable=no-member @@ -84,7 +93,9 @@ def test_default_values(self, mock_iter_entry_points): ) @patch("opentelemetry.configuration.expanduser") def test_configuration_file( - self, mock_expanduser, mock_iter_entry_points + self, + mock_expanduser, + mock_iter_entry_points, # pylint: disable=unused-argument ): # type: ignore mock_expanduser.return_value = getcwd() @@ -104,7 +115,7 @@ def test_configuration_file( {"OPENTELEMETRY_PYTHON_METER_PROVIDER": "overridden_meter_provider"}, ) def test_environment_variables( - self, mock_iter_entry_points + self, mock_iter_entry_points # pylint: disable=unused-argument ): # type: ignore self.assertEqual( Configuration().tracer_provider, "default_tracer_provider" @@ -127,7 +138,9 @@ def test_environment_variables( }, ) def test_configuration_file_environment_variables( - self, mock_expanduser, mock_iter_entry_points + self, + mock_expanduser, + mock_iter_entry_points, # pylint: disable=unused-argument ): # type: ignore mock_expanduser.return_value = getcwd() From 33c7e1f90eaae4cd17504562ee2baa6a99148d71 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 13 Mar 2020 11:37:40 -0600 Subject: [PATCH 22/28] More and more fixing --- .../opentelemetry/configuration/__init__.py | 8 +++----- .../src/opentelemetry/metrics/__init__.py | 2 +- .../src/opentelemetry/trace/__init__.py | 2 +- .../tests/configuration/test_configuration.py | 20 +++++++++---------- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index 8ecd32ee36f..447e265b00d 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -91,10 +91,9 @@ def _load(cls, key=None, value=None): setattr( cls, underscored_key, - next( # type: ignore + next( iter_entry_points( - "opentelemetry_{}".format(key), - name=value, # type: ignore + "opentelemetry_{}".format(key), name=value, ) ).load()(), ) @@ -103,8 +102,7 @@ def _load(cls, key=None, value=None): # raised here, or only a message should be logged and should # we fall back to the default meter provider? logger.error( - "Failed to load configured provider %s", - value, # type: ignore + "Failed to load configured provider %s", value, ) raise diff --git a/opentelemetry-api/src/opentelemetry/metrics/__init__.py b/opentelemetry-api/src/opentelemetry/metrics/__init__.py index fccaa04fc1d..c37119529b6 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/metrics/__init__.py @@ -426,7 +426,7 @@ def get_meter_provider() -> MeterProvider: if _METER_PROVIDER is None: _METER_PROVIDER = ( - Configuration().meter_provider # pylint: disable=no-member + Configuration().meter_provider # type: ignore # pylint: disable=no-member ) return _METER_PROVIDER # type: ignore diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index aae94f58b84..e23404f707b 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -668,7 +668,7 @@ def get_tracer_provider() -> TracerProvider: if _TRACER_PROVIDER is None: _TRACER_PROVIDER = ( - Configuration().tracer_provider # pylint: disable=no-member + Configuration().tracer_provider # type: ignore # pylint: disable=no-member ) return _TRACER_PROVIDER # type: ignore diff --git a/opentelemetry-api/tests/configuration/test_configuration.py b/opentelemetry-api/tests/configuration/test_configuration.py index c8a6fdbfca3..8d536c27be9 100644 --- a/opentelemetry-api/tests/configuration/test_configuration.py +++ b/opentelemetry-api/tests/configuration/test_configuration.py @@ -55,9 +55,9 @@ def test_singleton(self): @patch( "opentelemetry.configuration.iter_entry_points", - **{"side_effect": IterEntryPointsMock} + **{"side_effect": IterEntryPointsMock} # type: ignore ) - def test_lazy( + def test_lazy( # type: ignore self, mock_iter_entry_points, # pylint: disable=unused-argument ): configuration = Configuration() @@ -75,9 +75,9 @@ def test_lazy( @patch( "opentelemetry.configuration.iter_entry_points", - **{"side_effect": IterEntryPointsMock} + **{"side_effect": IterEntryPointsMock} # type: ignore ) - def test_default_values( + def test_default_values( # type: ignore self, mock_iter_entry_points # pylint: disable=unused-argument ): self.assertEqual( @@ -89,10 +89,10 @@ def test_default_values( @patch( "opentelemetry.configuration.iter_entry_points", - **{"side_effect": IterEntryPointsMock} + **{"side_effect": IterEntryPointsMock} # type: ignore ) @patch("opentelemetry.configuration.expanduser") - def test_configuration_file( + def test_configuration_file( # type: ignore self, mock_expanduser, mock_iter_entry_points, # pylint: disable=unused-argument @@ -108,13 +108,13 @@ def test_configuration_file( @patch( "opentelemetry.configuration.iter_entry_points", - **{"side_effect": IterEntryPointsMock} + **{"side_effect": IterEntryPointsMock} # type: ignore ) @patch.dict( "os.environ", {"OPENTELEMETRY_PYTHON_METER_PROVIDER": "overridden_meter_provider"}, ) - def test_environment_variables( + def test_environment_variables( # type: ignore self, mock_iter_entry_points # pylint: disable=unused-argument ): # type: ignore self.assertEqual( @@ -126,7 +126,7 @@ def test_environment_variables( @patch( "opentelemetry.configuration.iter_entry_points", - **{"side_effect": IterEntryPointsMock} + **{"side_effect": IterEntryPointsMock} # type: ignore ) @patch("opentelemetry.configuration.expanduser") @patch.dict( @@ -137,7 +137,7 @@ def test_environment_variables( ) }, ) - def test_configuration_file_environment_variables( + def test_configuration_file_environment_variables( # type: ignore self, mock_expanduser, mock_iter_entry_points, # pylint: disable=unused-argument From 0ea8bd5cd5c51d67e782359e40b0cb19fcfa5978 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 13 Mar 2020 14:52:25 -0600 Subject: [PATCH 23/28] Update opentelemetry-api/setup.py Co-Authored-By: Chris Kleinknecht --- opentelemetry-api/setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/opentelemetry-api/setup.py b/opentelemetry-api/setup.py index b2266dd23b4..5eb91d1f1b6 100644 --- a/opentelemetry-api/setup.py +++ b/opentelemetry-api/setup.py @@ -59,7 +59,6 @@ zip_safe=False, entry_points={ "opentelemetry_context": [ - "default_context = opentelemetry.context:DefaultContext", "contextvars_context = " "opentelemetry.context.contextvars_context:" "ContextVarsRuntimeContext", From 05944d8b0bd204588723225b7727754f28ab0817 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 13 Mar 2020 16:33:45 -0600 Subject: [PATCH 24/28] Remove configuration file from manager --- .../opentelemetry/configuration/__init__.py | 14 ------ .../configuration/opentelemetry_python.json | 4 -- .../tests/configuration/test_configuration.py | 47 ------------------- tests/w3c_tracecontext_validation_server.py | 10 +--- 4 files changed, 2 insertions(+), 73 deletions(-) delete mode 100644 opentelemetry-api/src/opentelemetry/configuration/opentelemetry_python.json diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index 447e265b00d..41261ae61cf 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -25,10 +25,8 @@ powerful one, Dynaconf, for example. """ -from json import load from logging import getLogger from os import environ -from os.path import exists, expanduser, join from pkg_resources import iter_entry_points @@ -47,18 +45,6 @@ def __new__(cls) -> "Configuration": key: "default_{}".format(key) for key in cls.__slots__ } - configuration_file_path = join( - expanduser("~"), ".config", "opentelemetry_python.json" - ) - - if exists(configuration_file_path): - - with open(configuration_file_path) as configuration_file: - file_configuration = load(configuration_file) - - for key, value in configuration.items(): - configuration[key] = file_configuration.get(key, value) - for key, value in configuration.items(): configuration[key] = environ.get( "OPENTELEMETRY_PYTHON_{}".format(key.upper()), value diff --git a/opentelemetry-api/src/opentelemetry/configuration/opentelemetry_python.json b/opentelemetry-api/src/opentelemetry/configuration/opentelemetry_python.json deleted file mode 100644 index c0ac3f4ff93..00000000000 --- a/opentelemetry-api/src/opentelemetry/configuration/opentelemetry_python.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "tracer_provider": "default_tracer_provider", - "meter_provider": "default_meter_provider" -} diff --git a/opentelemetry-api/tests/configuration/test_configuration.py b/opentelemetry-api/tests/configuration/test_configuration.py index 8d536c27be9..754f9c48942 100644 --- a/opentelemetry-api/tests/configuration/test_configuration.py +++ b/opentelemetry-api/tests/configuration/test_configuration.py @@ -13,7 +13,6 @@ # limitations under the License. from json import dumps -from os import getcwd from unittest import TestCase from unittest.mock import patch @@ -87,25 +86,6 @@ def test_default_values( # type: ignore Configuration().meter_provider, "default_meter_provider" ) # pylint: disable=no-member - @patch( - "opentelemetry.configuration.iter_entry_points", - **{"side_effect": IterEntryPointsMock} # type: ignore - ) - @patch("opentelemetry.configuration.expanduser") - def test_configuration_file( # type: ignore - self, - mock_expanduser, - mock_iter_entry_points, # pylint: disable=unused-argument - ): # type: ignore - mock_expanduser.return_value = getcwd() - - self.assertEqual( - Configuration().tracer_provider, "overridden_tracer_provider" - ) # pylint: disable=no-member - self.assertEqual( - Configuration().meter_provider, "default_meter_provider" - ) # pylint: disable=no-member - @patch( "opentelemetry.configuration.iter_entry_points", **{"side_effect": IterEntryPointsMock} # type: ignore @@ -124,33 +104,6 @@ def test_environment_variables( # type: ignore Configuration().meter_provider, "overridden_meter_provider" ) # pylint: disable=no-member - @patch( - "opentelemetry.configuration.iter_entry_points", - **{"side_effect": IterEntryPointsMock} # type: ignore - ) - @patch("opentelemetry.configuration.expanduser") - @patch.dict( - "os.environ", - { - "OPENTELEMETRY_PYTHON_TRACER_PROVIDER": ( - "reoverridden_tracer_provider" - ) - }, - ) - def test_configuration_file_environment_variables( # type: ignore - self, - mock_expanduser, - mock_iter_entry_points, # pylint: disable=unused-argument - ): # type: ignore - mock_expanduser.return_value = getcwd() - - self.assertEqual( - Configuration().tracer_provider, "reoverridden_tracer_provider" - ) - self.assertEqual( - Configuration().meter_provider, "default_meter_provider" - ) - def test_property(self): with self.assertRaises(AttributeError): Configuration().tracer_provider = "new_tracer_provider" diff --git a/tests/w3c_tracecontext_validation_server.py b/tests/w3c_tracecontext_validation_server.py index ddbbbd383f0..41a0f4bcfbd 100644 --- a/tests/w3c_tracecontext_validation_server.py +++ b/tests/w3c_tracecontext_validation_server.py @@ -19,7 +19,6 @@ """ import json -from os import environ import flask import requests @@ -27,14 +26,8 @@ # FIXME This could likely be avoided by integrating this script into the # standard test running mechanisms. -environ[ - "OPENTELEMETRY_PYTHON_TRACER_PROVIDER" -] = "sdk_tracer_provider" # isort:skip -environ[ - "OPENTELEMETRY_PYTHON_METER_PROVIDER" -] = "sdk_meter_provider" # isort:skip - from opentelemetry import trace # noqa # isort:skip +from opentelemetry.sdk.trace import TracerProvider from opentelemetry.ext import http_requests # noqa # isort:skip" from opentelemetry.ext.wsgi import OpenTelemetryMiddleware # noqa # isort:skip from opentelemetry.sdk.trace.export import ( # noqa # isort:skip @@ -45,6 +38,7 @@ # 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. +trace.set_tracer_provider(TracerProvider()) http_requests.enable(trace.get_tracer_provider()) # SpanExporter receives the spans and send them to the target location. From e376833f88707cd97d39ebee5b9a6c25ef9bffd7 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 13 Mar 2020 16:39:24 -0600 Subject: [PATCH 25/28] More fixing --- tests/w3c_tracecontext_validation_server.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/w3c_tracecontext_validation_server.py b/tests/w3c_tracecontext_validation_server.py index 41a0f4bcfbd..c2119f95873 100644 --- a/tests/w3c_tracecontext_validation_server.py +++ b/tests/w3c_tracecontext_validation_server.py @@ -23,11 +23,12 @@ import flask import requests +from opentelemetry.sdk.trace import TracerProvider + # FIXME This could likely be avoided by integrating this script into the # standard test running mechanisms. from opentelemetry import trace # noqa # isort:skip -from opentelemetry.sdk.trace import TracerProvider from opentelemetry.ext import http_requests # noqa # isort:skip" from opentelemetry.ext.wsgi import OpenTelemetryMiddleware # noqa # isort:skip from opentelemetry.sdk.trace.export import ( # noqa # isort:skip From 76bb1252def4ee206479e0bce8200ce783eb8c9e Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 13 Mar 2020 17:20:01 -0600 Subject: [PATCH 26/28] Fix last test case --- docs/examples/basic_tracer/tracer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/examples/basic_tracer/tracer.py b/docs/examples/basic_tracer/tracer.py index 92f96be89fd..8982e5cd7b1 100755 --- a/docs/examples/basic_tracer/tracer.py +++ b/docs/examples/basic_tracer/tracer.py @@ -45,6 +45,7 @@ print("Using ConsoleSpanExporter") exporter = ConsoleSpanExporter() +trace.set_tracer_provider(TracerProvider()) # We tell OpenTelemetry who it is that is creating spans. In this case, we have # no real name (no setup.py), so we make one up. If we had a version, we would # also specify it here. @@ -52,9 +53,8 @@ # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) - -trace.set_tracer_provider(TracerProvider()) trace.get_tracer_provider().add_span_processor(span_processor) + with tracer.start_as_current_span("foo"): with tracer.start_as_current_span("bar"): with tracer.start_as_current_span("baz"): From d7ed20ea5a195e24808e92c9f40c536434d8fe92 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Fri, 13 Mar 2020 17:54:55 -0600 Subject: [PATCH 27/28] Documenting the configuration manager --- .../opentelemetry/configuration/__init__.py | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index 41261ae61cf..312696293ff 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -18,11 +18,45 @@ """ Simple configuration manager -This configuration manager reads configuration values from a JSON file, the -values read there can be overriden by environment variables. - -It would probably be better to replace this configuration manager with a more -powerful one, Dynaconf, for example. +This is a configuration manager for the Tracer and Meter providers. It reads +configuration from environment variables prefixed with OPENTELEMETRY_PYHTON_: + +1. OPENTELEMETRY_PYTHON_TRACER_PROVIDER +2. OPENTELEMETRY_PYTHON_METER_PROVIDER + +The value of these environment variables should be the name of the entry point +that points to the class that implements either provider. This OpenTelemetry +API package provides one entry point for each, which can be found in the +setup.py file: + +entry_points={ + ... + "opentelemetry_meter_provider": [ + "default_meter_provider = " + "opentelemetry.metrics:DefaultMeterProvider" + ], + "opentelemetry_tracer_provider": [ + "default_tracer_provider = " + "opentelemetry.trace:DefaultTracerProvider" + ], +} + +To use the meter provider above, then the +OPENTELEMETRY_PYTHON_METER_PROVIDER should be set to +"default_meter_provider" (this is not actually necessary since the +OpenTelemetry API provided providers are the default ones used if no +configuration is found in the environment variables). + +Once this is done, the configuration manager can be used by simply importing +it from opentelemetry.configuration.Configuration. This is a class that can +be instantiated as many times as needed without concern because it will +always produce the same instance. Its attributes are lazy loaded and they +hold an instance of their corresponding provider. So, for example, to get +the configured meter provider: + +from opentelemetry.configuration import Configuration + +tracer_provider = Configuration().tracer_provider """ from logging import getLogger From 726c8193e3aac4e54797f68c85806354dc362fa9 Mon Sep 17 00:00:00 2001 From: Chris Kleinknecht Date: Sat, 14 Mar 2020 11:56:15 -0700 Subject: [PATCH 28/28] Add config module docs, fix docstring --- docs/api/api.rst | 1 + docs/api/configuration.rst | 10 +++++ .../opentelemetry/configuration/__init__.py | 42 ++++++++++--------- 3 files changed, 33 insertions(+), 20 deletions(-) create mode 100644 docs/api/configuration.rst diff --git a/docs/api/api.rst b/docs/api/api.rst index 6ae631147a2..8af950652f2 100644 --- a/docs/api/api.rst +++ b/docs/api/api.rst @@ -6,6 +6,7 @@ OpenTelemetry Python API .. toctree:: :maxdepth: 1 + configuration context metrics trace diff --git a/docs/api/configuration.rst b/docs/api/configuration.rst new file mode 100644 index 00000000000..06ae4332776 --- /dev/null +++ b/docs/api/configuration.rst @@ -0,0 +1,10 @@ +opentelemetry.configuration module +================================== + +Module contents +--------------- + +.. automodule:: opentelemetry.configuration + :members: + :undoc-members: + :show-inheritance: diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py index 312696293ff..f038e570168 100644 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ b/opentelemetry-api/src/opentelemetry/configuration/__init__.py @@ -19,30 +19,31 @@ Simple configuration manager This is a configuration manager for the Tracer and Meter providers. It reads -configuration from environment variables prefixed with OPENTELEMETRY_PYHTON_: +configuration from environment variables prefixed with +``OPENTELEMETRY_PYTHON_``: -1. OPENTELEMETRY_PYTHON_TRACER_PROVIDER -2. OPENTELEMETRY_PYTHON_METER_PROVIDER +1. ``OPENTELEMETRY_PYTHON_TRACER_PROVIDER`` +2. ``OPENTELEMETRY_PYTHON_METER_PROVIDER`` The value of these environment variables should be the name of the entry point that points to the class that implements either provider. This OpenTelemetry API package provides one entry point for each, which can be found in the -setup.py file: - -entry_points={ - ... - "opentelemetry_meter_provider": [ - "default_meter_provider = " - "opentelemetry.metrics:DefaultMeterProvider" - ], - "opentelemetry_tracer_provider": [ - "default_tracer_provider = " - "opentelemetry.trace:DefaultTracerProvider" - ], -} +setup.py file:: + + entry_points={ + ... + "opentelemetry_meter_provider": [ + "default_meter_provider = " + "opentelemetry.metrics:DefaultMeterProvider" + ], + "opentelemetry_tracer_provider": [ + "default_tracer_provider = " + "opentelemetry.trace:DefaultTracerProvider" + ], + } To use the meter provider above, then the -OPENTELEMETRY_PYTHON_METER_PROVIDER should be set to +``OPENTELEMETRY_PYTHON_METER_PROVIDER`` should be set to "default_meter_provider" (this is not actually necessary since the OpenTelemetry API provided providers are the default ones used if no configuration is found in the environment variables). @@ -52,11 +53,12 @@ be instantiated as many times as needed without concern because it will always produce the same instance. Its attributes are lazy loaded and they hold an instance of their corresponding provider. So, for example, to get -the configured meter provider: +the configured meter provider:: -from opentelemetry.configuration import Configuration + from opentelemetry.configuration import Configuration + + tracer_provider = Configuration().tracer_provider -tracer_provider = Configuration().tracer_provider """ from logging import getLogger