Skip to content

Commit

Permalink
Remove SDK dependency from auto-instrumentation (#1420)
Browse files Browse the repository at this point in the history
  • Loading branch information
alrex authored Dec 14, 2020
1 parent 33fa7b9 commit 0011637
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 43 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#1449](https://github.com/open-telemetry/opentelemetry-python/pull/1449))
- Added support for Jaeger propagator
([#1219](https://github.com/open-telemetry/opentelemetry-python/pull/1219))
- Remove dependency on SDK from `opentelemetry-instrumentation` package. The
`opentelemetry-sdk` package now registers an entrypoint `opentelemetry_configurator`
to allow `opentelemetry-instrument` to load the configuration for the SDK
([#1420](https://github.com/open-telemetry/opentelemetry-python/pull/1420))

## [0.16b1](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v0.16b1) - 2020-11-26
### Added
Expand Down
1 change: 0 additions & 1 deletion opentelemetry-instrumentation/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ zip_safe = False
include_package_data = True
install_requires =
opentelemetry-api == 0.17.dev0
opentelemetry-sdk == 0.17.dev0
wrapt >= 1.0.0, < 2.0.0

[options.packages.find]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@

from pkg_resources import iter_entry_points

from opentelemetry.instrumentation.auto_instrumentation.components import (
initialize_components,
)

logger = getLogger(__file__)


def auto_instrument():
def _load_distros():
# will be implemented in a subsequent PR
pass


def _load_instrumentors():
for entry_point in iter_entry_points("opentelemetry_instrumentor"):
try:
entry_point.load()().instrument() # type: ignore
Expand All @@ -35,10 +36,29 @@ def auto_instrument():
raise exc


def _load_configurators():
configured = None
for entry_point in iter_entry_points("opentelemetry_configurator"):
if configured is not None:
logger.warning(
"Configuration of %s not loaded, %s already loaded",
entry_point.name,
configured,
)
continue
try:
entry_point.load()().configure() # type: ignore
configured = entry_point.name
except Exception as exc: # pylint: disable=broad-except
logger.exception("Configuration of %s failed", entry_point.name)
raise exc


def initialize():
try:
initialize_components()
auto_instrument()
_load_distros()
_load_configurators()
_load_instrumentors()
except Exception: # pylint: disable=broad-except
logger.exception("Failed to auto initialize opentelemetry")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# 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 Configurator
"""

from abc import ABC, abstractmethod
from logging import getLogger

_LOG = getLogger(__name__)


class BaseConfigurator(ABC):
"""An ABC for configurators
Configurators are used to configure
SDKs (i.e. TracerProvider, MeterProvider, Processors...)
to reduce the amount of manual configuration required.
"""

_instance = None
_is_instrumented = False

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 SDK"""

def configure(self, **kwargs):
"""Configure the SDK"""
self._configure(**kwargs)


__all__ = ["BaseConfigurator"]
3 changes: 3 additions & 0 deletions opentelemetry-sdk/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ zip_safe = False
include_package_data = True
install_requires =
opentelemetry-api == 0.17.dev0
opentelemetry-instrumentation == 0.17.dev0

[options.packages.find]
where = src
Expand All @@ -57,6 +58,8 @@ opentelemetry_propagator =
opentelemetry_exporter =
console_span = opentelemetry.sdk.trace.export:ConsoleSpanExporter
console_metrics = opentelemetry.sdk.metrics.export:ConsoleMetricsExporter
opentelemetry_configurator =
sdk_configurator = opentelemetry.sdk.configuration:Configurator

[options.extras_require]
test =
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from opentelemetry import trace
from opentelemetry.configuration import Configuration
from opentelemetry.instrumentation.configurator import BaseConfigurator
from opentelemetry.sdk.metrics.export import MetricsExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
Expand All @@ -38,15 +39,15 @@
_DEFAULT_IDS_GENERATOR = RANDOM_IDS_GENERATOR


def get_ids_generator() -> str:
def _get_ids_generator() -> str:
return Configuration().IDS_GENERATOR or _DEFAULT_IDS_GENERATOR


def get_service_name() -> str:
def _get_service_name() -> str:
return Configuration().SERVICE_NAME or ""


def get_exporter_names() -> Sequence[str]:
def _get_exporter_names() -> Sequence[str]:
exporter = Configuration().EXPORTER or _DEFAULT_EXPORTER
if exporter.lower().strip() == "none":
return []
Expand All @@ -62,10 +63,10 @@ def get_exporter_names() -> Sequence[str]:
return names


def init_tracing(
def _init_tracing(
exporters: Sequence[SpanExporter], ids_generator: trace.IdsGenerator
):
service_name = get_service_name()
service_name = _get_service_name()
provider = TracerProvider(
resource=Resource.create({"service.name": service_name}),
ids_generator=ids_generator(),
Expand All @@ -85,12 +86,12 @@ def init_tracing(
)


def init_metrics(exporters: Sequence[MetricsExporter]):
def _init_metrics(exporters: Sequence[MetricsExporter]):
if exporters:
logger.warning("automatic metric initialization is not supported yet.")


def import_tracer_provider_config_components(
def _import_tracer_provider_config_components(
selected_components, entry_point_name
) -> Sequence[Tuple[str, object]]:
component_entry_points = {
Expand All @@ -112,15 +113,15 @@ def import_tracer_provider_config_components(
return component_impls


def import_exporters(
def _import_exporters(
exporter_names: Sequence[str],
) -> Tuple[Sequence[SpanExporter], Sequence[MetricsExporter]]:
trace_exporters, metric_exporters = {}, {}

for (
exporter_name,
exporter_impl,
) in import_tracer_provider_config_components(
) in _import_tracer_provider_config_components(
exporter_names, "opentelemetry_exporter"
):
if issubclass(exporter_impl, SpanExporter):
Expand All @@ -136,11 +137,11 @@ def import_exporters(
return trace_exporters, metric_exporters


def import_ids_generator(ids_generator_name: str) -> trace.IdsGenerator:
def _import_ids_generator(ids_generator_name: str) -> trace.IdsGenerator:
# pylint: disable=unbalanced-tuple-unpacking
[
(ids_generator_name, ids_generator_impl)
] = import_tracer_provider_config_components(
] = _import_tracer_provider_config_components(
[ids_generator_name.strip()], "opentelemetry_ids_generator"
)

Expand All @@ -150,14 +151,19 @@ def import_ids_generator(ids_generator_name: str) -> trace.IdsGenerator:
raise RuntimeError("{0} is not an IdsGenerator".format(ids_generator_name))


def initialize_components():
exporter_names = get_exporter_names()
trace_exporters, metric_exporters = import_exporters(exporter_names)
ids_generator_name = get_ids_generator()
ids_generator = import_ids_generator(ids_generator_name)
init_tracing(trace_exporters, ids_generator)
def _initialize_components():
exporter_names = _get_exporter_names()
trace_exporters, metric_exporters = _import_exporters(exporter_names)
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)
_init_metrics(metric_exporters)


class Configurator(BaseConfigurator):
def _configure(self, **kwargs):
_initialize_components()
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
from unittest.mock import patch

from opentelemetry.configuration import Configuration
from opentelemetry.instrumentation.auto_instrumentation import components
from opentelemetry.sdk.configuration import (
_get_ids_generator,
_import_ids_generator,
_init_tracing,
)
from opentelemetry.sdk.resources import Resource
from opentelemetry.trace.ids_generator import RandomIdsGenerator

Expand Down Expand Up @@ -71,11 +75,10 @@ class TestTraceInit(TestCase):
def setUp(self):
super()
self.get_provider_patcher = patch(
"opentelemetry.instrumentation.auto_instrumentation.components.TracerProvider",
Provider,
"opentelemetry.sdk.configuration.TracerProvider", Provider,
)
self.get_processor_patcher = patch(
"opentelemetry.instrumentation.auto_instrumentation.components.BatchExportSpanProcessor",
"opentelemetry.sdk.configuration.BatchExportSpanProcessor",
Processor,
)
self.set_provider_patcher = patch(
Expand All @@ -96,7 +99,7 @@ def tearDown(self):
def test_trace_init_default(self):
environ["OTEL_SERVICE_NAME"] = "my-test-service"
Configuration._reset()
components.init_tracing({"zipkin": Exporter}, RandomIdsGenerator)
_init_tracing({"zipkin": Exporter}, RandomIdsGenerator)

self.assertEqual(self.set_provider_mock.call_count, 1)
provider = self.set_provider_mock.call_args[0][0]
Expand All @@ -111,7 +114,7 @@ def test_trace_init_default(self):
def test_trace_init_otlp(self):
environ["OTEL_SERVICE_NAME"] = "my-otlp-test-service"
Configuration._reset()
components.init_tracing({"otlp": OTLPExporter}, RandomIdsGenerator)
_init_tracing({"otlp": OTLPExporter}, RandomIdsGenerator)

self.assertEqual(self.set_provider_mock.call_count, 1)
provider = self.set_provider_mock.call_args[0][0]
Expand All @@ -128,21 +131,18 @@ def test_trace_init_otlp(self):

@patch.dict(environ, {"OTEL_IDS_GENERATOR": "custom_ids_generator"})
@patch(
"opentelemetry.instrumentation.auto_instrumentation.components.trace.IdsGenerator",
new=IdsGenerator,
)
@patch(
"opentelemetry.instrumentation.auto_instrumentation.components.iter_entry_points"
"opentelemetry.sdk.configuration.trace.IdsGenerator", new=IdsGenerator,
)
@patch("opentelemetry.sdk.configuration.iter_entry_points")
def test_trace_init_custom_ids_generator(self, mock_iter_entry_points):
mock_iter_entry_points.configure_mock(
return_value=[
IterEntryPoint("custom_ids_generator", CustomIdsGenerator)
]
)
Configuration._reset()
ids_generator_name = components.get_ids_generator()
ids_generator = components.import_ids_generator(ids_generator_name)
components.init_tracing({}, ids_generator)
ids_generator_name = _get_ids_generator()
ids_generator = _import_ids_generator(ids_generator_name)
_init_tracing({}, ids_generator)
provider = self.set_provider_mock.call_args[0][0]
self.assertIsInstance(provider.ids_generator, CustomIdsGenerator)
7 changes: 4 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ commands_pre =
py3{5,6,7,8,9}: python -m pip install -U pip setuptools wheel
; Install common packages for all the tests. These are not needed in all the
; cases but it saves a lot of boilerplate in this file.
test: pip install {toxinidir}/opentelemetry-api {toxinidir}/opentelemetry-sdk {toxinidir}/tests/util
test: pip install {toxinidir}/opentelemetry-api {toxinidir}/opentelemetry-instrumentation {toxinidir}/opentelemetry-sdk {toxinidir}/tests/util

test-core-proto: pip install {toxinidir}/opentelemetry-proto
instrumentation: pip install {toxinidir}/opentelemetry-instrumentation
Expand Down Expand Up @@ -141,8 +141,8 @@ deps =

commands_pre =
python -m pip install -e {toxinidir}/opentelemetry-api[test]
python -m pip install -e {toxinidir}/opentelemetry-sdk[test]
python -m pip install -e {toxinidir}/opentelemetry-instrumentation[test]
python -m pip install -e {toxinidir}/opentelemetry-sdk[test]
python -m pip install -e {toxinidir}/opentelemetry-proto[test]
python -m pip install -e {toxinidir}/tests/util[test]
python -m pip install -e {toxinidir}/instrumentation/opentelemetry-instrumentation-opentracing-shim[test]
Expand Down Expand Up @@ -176,8 +176,8 @@ deps =

commands_pre =
pip install -e {toxinidir}/opentelemetry-api \
-e {toxinidir}/opentelemetry-sdk \
-e {toxinidir}/opentelemetry-instrumentation \
-e {toxinidir}/opentelemetry-sdk \
-e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-requests \
-e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-wsgi

Expand All @@ -194,6 +194,7 @@ changedir =

commands_pre =
pip install -e {toxinidir}/opentelemetry-api \
-e {toxinidir}/opentelemetry-instrumentation \
-e {toxinidir}/opentelemetry-sdk \
-e {toxinidir}/tests/util \
-e {toxinidir}/exporter/opentelemetry-exporter-opencensus
Expand Down

0 comments on commit 0011637

Please sign in to comment.