diff --git a/CHANGELOG.md b/CHANGELOG.md index d0424a8b5c..21a16a8de7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `SpanContext` ([#1485](https://github.com/open-telemetry/opentelemetry-python/pull/1485)]) - `opentelemetry-sdk` Add support for OTEL_TRACE_SAMPLER and OTEL_TRACE_SAMPLER_ARG env variables ([#1496](https://github.com/open-telemetry/opentelemetry-python/pull/1496)) +- Adding `opentelemetry-distro` package to add default configuration for + span exporter to OTLP + ([#1482](https://github.com/open-telemetry/opentelemetry-python/pull/1482)) ### Changed - `opentelemetry-exporter-zipkin` Updated zipkin exporter status code and error tag diff --git a/eachdist.ini b/eachdist.ini index 9cef826d20..ded3a5d8c1 100644 --- a/eachdist.ini +++ b/eachdist.ini @@ -9,6 +9,7 @@ sortfirst= opentelemetry-sdk opentelemetry-instrumentation opentelemetry-proto + opentelemetry-distro tests/util instrumentation/* exporter/* diff --git a/opentelemetry-distro/MANIFEST.in b/opentelemetry-distro/MANIFEST.in new file mode 100644 index 0000000000..191b7d1959 --- /dev/null +++ b/opentelemetry-distro/MANIFEST.in @@ -0,0 +1,7 @@ +prune tests +graft src +global-exclude *.pyc +global-exclude *.pyo +global-exclude __pycache__/* +include MANIFEST.in +include README.rst diff --git a/opentelemetry-distro/README.rst b/opentelemetry-distro/README.rst new file mode 100644 index 0000000000..4189131fc2 --- /dev/null +++ b/opentelemetry-distro/README.rst @@ -0,0 +1,22 @@ +OpenTelemetry Distro +==================== + +|pypi| + +.. |pypi| image:: https://badge.fury.io/py/opentelemetry-distro.svg + :target: https://pypi.org/project/opentelemetry-distro/ + +Installation +------------ + +:: + + pip install opentelemetry-distro + + +This package provides entrypoints to configure OpenTelemetry + +References +---------- + +* `OpenTelemetry Project `_ diff --git a/opentelemetry-distro/setup.cfg b/opentelemetry-distro/setup.cfg new file mode 100644 index 0000000000..a9340e4608 --- /dev/null +++ b/opentelemetry-distro/setup.cfg @@ -0,0 +1,59 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +[metadata] +name = opentelemetry-distro +description = OpenTelemetry Python Distro +long_description = file: README.rst +long_description_content_type = text/x-rst +author = OpenTelemetry Authors +author_email = cncf-opentelemetry-contributors@lists.cncf.io +url = https://github.com/open-telemetry/opentelemetry-python/tree/master/opentelemetry-distro +platforms = any +license = Apache-2.0 +classifiers = + Development Status :: 4 - Beta + Intended Audience :: Developers + License :: OSI Approved :: Apache Software License + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.5 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + +[options] +python_requires = >=3.5 +package_dir= + =src +packages=find_namespace: +zip_safe = False +include_package_data = True +install_requires = + opentelemetry-api == 0.17.dev0 + opentelemetry-sdk == 0.17.dev0 + +[options.packages.find] +where = src + +[options.entry_points] +opentelemetry_distro = + distro = opentelemetry.distro:OpenTelemetryDistro +opentelemetry_configurator = + configurator = opentelemetry.distro:Configurator + +[options.extras_require] +test = +otlp = + opentelemetry-exporter-otlp == 0.17.dev0 diff --git a/opentelemetry-distro/setup.py b/opentelemetry-distro/setup.py new file mode 100644 index 0000000000..da8417d50a --- /dev/null +++ b/opentelemetry-distro/setup.py @@ -0,0 +1,27 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import setuptools + +BASE_DIR = os.path.dirname(__file__) +VERSION_FILENAME = os.path.join( + BASE_DIR, "src", "opentelemetry", "distro", "version.py" +) +PACKAGE_INFO = {} +with open(VERSION_FILENAME) as f: + exec(f.read(), PACKAGE_INFO) + +setuptools.setup(version=PACKAGE_INFO["__version__"],) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/configuration/__init__.py b/opentelemetry-distro/src/opentelemetry/distro/__init__.py similarity index 93% rename from opentelemetry-sdk/src/opentelemetry/sdk/configuration/__init__.py rename to opentelemetry-distro/src/opentelemetry/distro/__init__.py index b8a99bb62c..8a48d256c7 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/configuration/__init__.py +++ b/opentelemetry-distro/src/opentelemetry/distro/__init__.py @@ -11,7 +11,8 @@ # 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 from logging import getLogger from typing import Sequence, Tuple @@ -20,6 +21,7 @@ from opentelemetry import trace from opentelemetry.configuration import Configuration from opentelemetry.instrumentation.configurator import BaseConfigurator +from opentelemetry.instrumentation.distro import BaseDistro from opentelemetry.sdk.metrics.export import MetricsExporter from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider @@ -31,10 +33,10 @@ logger = getLogger(__file__) + EXPORTER_OTLP = "otlp" EXPORTER_OTLP_SPAN = "otlp_span" EXPORTER_OTLP_METRIC = "otlp_metric" -_DEFAULT_EXPORTER = EXPORTER_OTLP RANDOM_IDS_GENERATOR = "random" _DEFAULT_IDS_GENERATOR = RANDOM_IDS_GENERATOR @@ -49,7 +51,7 @@ def _get_service_name() -> str: def _get_exporter_names() -> Sequence[str]: - exporter = Configuration().EXPORTER or _DEFAULT_EXPORTER + exporter = Configuration().EXPORTER or EXPORTER_OTLP if exporter.lower().strip() == "none": return [] @@ -87,11 +89,6 @@ def _init_tracing( ) -def _init_metrics(exporters: Sequence[MetricsExporter]): - if exporters: - logger.warning("automatic metric initialization is not supported yet.") - - def _import_tracer_provider_config_components( selected_components, entry_point_name ) -> Sequence[Tuple[str, object]]: @@ -158,13 +155,27 @@ def _initialize_components(): ids_generator_name = _get_ids_generator() ids_generator = _import_ids_generator(ids_generator_name) _init_tracing(trace_exporters, ids_generator) - # We don't support automatic initialization for metric yet but have added # some boilerplate in order to make sure current implementation does not # lock us out of supporting metrics later without major surgery. _init_metrics(metric_exporters) +def _init_metrics(exporters: Sequence[MetricsExporter]): + if exporters: + logger.warning("automatic metric initialization is not supported yet.") + + class Configurator(BaseConfigurator): def _configure(self, **kwargs): _initialize_components() + + +class OpenTelemetryDistro(BaseDistro): + """ + The OpenTelemetry provided Distro configures a default set of + configuration out of the box. + """ + + def _configure(self, **kwargs): + os.environ.setdefault("OTEL_EXPORTER", "otlp") diff --git a/opentelemetry-distro/src/opentelemetry/distro/version.py b/opentelemetry-distro/src/opentelemetry/distro/version.py new file mode 100644 index 0000000000..86e1dbb17a --- /dev/null +++ b/opentelemetry-distro/src/opentelemetry/distro/version.py @@ -0,0 +1,15 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +__version__ = "0.17.dev0" diff --git a/opentelemetry-distro/tests/__init__.py b/opentelemetry-distro/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/opentelemetry-sdk/tests/configuration/test_configurator.py b/opentelemetry-distro/tests/test_configurator.py similarity index 94% rename from opentelemetry-sdk/tests/configuration/test_configurator.py rename to opentelemetry-distro/tests/test_configurator.py index ebd6768444..90ee7fe931 100644 --- a/opentelemetry-sdk/tests/configuration/test_configurator.py +++ b/opentelemetry-distro/tests/test_configurator.py @@ -18,7 +18,7 @@ from unittest.mock import patch from opentelemetry.configuration import Configuration -from opentelemetry.sdk.configuration import ( +from opentelemetry.distro import ( _get_ids_generator, _import_ids_generator, _init_tracing, @@ -78,11 +78,10 @@ class TestTraceInit(TestCase): def setUp(self): super() self.get_provider_patcher = patch( - "opentelemetry.sdk.configuration.TracerProvider", Provider, + "opentelemetry.distro.TracerProvider", Provider ) self.get_processor_patcher = patch( - "opentelemetry.sdk.configuration.BatchExportSpanProcessor", - Processor, + "opentelemetry.distro.BatchExportSpanProcessor", Processor ) self.set_provider_patcher = patch( "opentelemetry.trace.set_tracer_provider" @@ -133,7 +132,8 @@ def test_trace_init_otlp(self): del environ["OTEL_SERVICE_NAME"] @patch.dict(environ, {"OTEL_IDS_GENERATOR": "custom_ids_generator"}) - @patch("opentelemetry.sdk.configuration.iter_entry_points") + @patch("opentelemetry.distro.IdsGenerator", new=IdsGenerator) + @patch("opentelemetry.distro.iter_entry_points") def test_trace_init_custom_ids_generator(self, mock_iter_entry_points): mock_iter_entry_points.configure_mock( return_value=[ diff --git a/opentelemetry-distro/tests/test_distro.py b/opentelemetry-distro/tests/test_distro.py new file mode 100644 index 0000000000..62d3a7e5e3 --- /dev/null +++ b/opentelemetry-distro/tests/test_distro.py @@ -0,0 +1,35 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# type: ignore + +import os +from unittest import TestCase + +from pkg_resources import DistributionNotFound, require + +from opentelemetry.distro import OpenTelemetryDistro + + +class TestDistribution(TestCase): + def test_package_available(self): + try: + require(["opentelemetry-distro"]) + except DistributionNotFound: + self.fail("opentelemetry-distro not installed") + + def test_default_configuration(self): + distro = OpenTelemetryDistro() + self.assertIsNone(os.environ.get("OTEL_EXPORTER")) + distro.configure() + self.assertEqual("otlp", os.environ.get("OTEL_EXPORTER")) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index 3465619ea3..72be01fd18 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -24,8 +24,15 @@ def _load_distros(): - # will be implemented in a subsequent PR - pass + for entry_point in iter_entry_points("opentelemetry_distro"): + try: + entry_point.load()().configure() # type: ignore + logger.debug("Distribution %s configured", entry_point.name) + except Exception as exc: # pylint: disable=broad-except + logger.exception( + "Distribution %s configuration failed", entry_point.name + ) + raise exc def _load_instrumentors(): diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py new file mode 100644 index 0000000000..63cacf1f6d --- /dev/null +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py @@ -0,0 +1,47 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# type: ignore + +""" +OpenTelemetry Base Distribution (Distro) +""" + +from abc import ABC, abstractmethod +from logging import getLogger + +_LOG = getLogger(__name__) + + +class BaseDistro(ABC): + """An ABC for distro""" + + _instance = None + + def __new__(cls, *args, **kwargs): + + if cls._instance is None: + cls._instance = object.__new__(cls, *args, **kwargs) + + return cls._instance + + @abstractmethod + def _configure(self, **kwargs): + """Configure the distribution""" + + def configure(self, **kwargs): + """Configure the distribution""" + self._configure(**kwargs) + + +__all__ = ["BaseDistro"] diff --git a/opentelemetry-sdk/setup.cfg b/opentelemetry-sdk/setup.cfg index f7ad42ba99..b1ecb357d2 100644 --- a/opentelemetry-sdk/setup.cfg +++ b/opentelemetry-sdk/setup.cfg @@ -43,7 +43,6 @@ zip_safe = False include_package_data = True install_requires = opentelemetry-api == 0.17.dev0 - opentelemetry-instrumentation == 0.17.dev0 [options.packages.find] where = src @@ -56,8 +55,6 @@ opentelemetry_tracer_provider = opentelemetry_exporter = console_span = opentelemetry.sdk.trace.export:ConsoleSpanExporter console_metrics = opentelemetry.sdk.metrics.export:ConsoleMetricsExporter -opentelemetry_configurator = - sdk_configurator = opentelemetry.sdk.configuration:Configurator opentelemetry_ids_generator = random = opentelemetry.sdk.trace.ids_generator:RandomIdsGenerator diff --git a/scripts/build.sh b/scripts/build.sh index 853a297003..718d91ef9d 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -16,7 +16,7 @@ DISTDIR=dist mkdir -p $DISTDIR rm -rf $DISTDIR/* - for d in opentelemetry-api/ opentelemetry-sdk/ opentelemetry-instrumentation/ opentelemetry-proto/ exporter/*/ instrumentation/*/ propagator/*/; do + for d in opentelemetry-api/ opentelemetry-sdk/ opentelemetry-instrumentation/ opentelemetry-proto/ opentelemetry-distro/ exporter/*/ instrumentation/*/ propagator/*/; do ( echo "building $d" cd "$d" diff --git a/tox.ini b/tox.ini index 3ef615bb7e..6f27fa0dcb 100644 --- a/tox.ini +++ b/tox.ini @@ -24,6 +24,10 @@ envlist = py3{5,6,7,8,9}-test-core-getting-started pypy3-test-core-getting-started + ; opentelemetry-distro + py3{5,6,7,8,9}-test-core-distro + pypy3-test-core-distro + ; opentelemetry-exporter-jaeger py3{5,6,7,8,9}-test-exporter-jaeger @@ -79,6 +83,7 @@ changedir = test-core-instrumentation: opentelemetry-instrumentation/tests test-core-getting-started: docs/getting_started/tests test-core-opentracing-shim: shim/opentelemetry-opentracing-shim/tests + test-core-distro: opentelemetry-distro/tests test-exporter-jaeger: exporter/opentelemetry-exporter-jaeger/tests test-exporter-opencensus: exporter/opentelemetry-exporter-opencensus/tests @@ -97,6 +102,7 @@ commands_pre = test: pip install {toxinidir}/opentelemetry-api {toxinidir}/opentelemetry-instrumentation {toxinidir}/opentelemetry-sdk {toxinidir}/tests/util test-core-proto: pip install {toxinidir}/opentelemetry-proto + distro: pip install {toxinidir}/opentelemetry-distro {toxinidir}/opentelemetry-distro instrumentation: pip install {toxinidir}/opentelemetry-instrumentation getting-started: pip install -e {toxinidir}/opentelemetry-instrumentation -e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-requests -e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-wsgi -e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-flask @@ -167,6 +173,7 @@ commands_pre = python -m pip install -e {toxinidir}/exporter/opentelemetry-exporter-zipkin[test] python -m pip install -e {toxinidir}/propagator/opentelemetry-propagator-b3[test] python -m pip install -e {toxinidir}/propagator/opentelemetry-propagator-jaeger[test] + python -m pip install -e {toxinidir}/opentelemetry-distro[test] commands = python scripts/eachdist.py lint --check-only