Skip to content

Commit

Permalink
Merge branch 'main' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
srikanthccv authored Sep 6, 2022
2 parents 43293cb + 2d591e4 commit 71b4906
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 25 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#2863](https://github.com/open-telemetry/opentelemetry-python/pull/2863))
- Fix: Handle `backoff` dependency version 1.0 and 2.0
([#2915](https://github.com/open-telemetry/opentelemetry-python/pull/2915))
- Add support for setting OTLP export protocol with env vars, as defined in the
[specifications](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#specify-protocol)
([#2893](https://github.com/open-telemetry/opentelemetry-python/pull/2893))

## [1.12.0-0.33b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.12.0) - 2022-08-08

Expand Down
92 changes: 81 additions & 11 deletions opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from typing import Dict, Optional, Sequence, Tuple, Type

from pkg_resources import iter_entry_points
from typing_extensions import Literal

from opentelemetry.environment_variables import (
OTEL_LOGS_EXPORTER,
Expand All @@ -40,6 +41,10 @@
from opentelemetry.sdk._logs.export import BatchLogProcessor, LogExporter
from opentelemetry.sdk.environment_variables import (
_OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED,
OTEL_EXPORTER_OTLP_LOGS_PROTOCOL,
OTEL_EXPORTER_OTLP_METRICS_PROTOCOL,
OTEL_EXPORTER_OTLP_PROTOCOL,
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL,
)
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import (
Expand All @@ -55,26 +60,91 @@

_EXPORTER_OTLP = "otlp"
_EXPORTER_OTLP_PROTO_GRPC = "otlp_proto_grpc"
_EXPORTER_OTLP_PROTO_HTTP = "otlp_proto_http"

_EXPORTER_BY_OTLP_PROTOCOL = {
"grpc": _EXPORTER_OTLP_PROTO_GRPC,
"http/protobuf": _EXPORTER_OTLP_PROTO_HTTP,
}

_EXPORTER_ENV_BY_SIGNAL_TYPE = {
"traces": OTEL_TRACES_EXPORTER,
"metrics": OTEL_METRICS_EXPORTER,
"logs": OTEL_LOGS_EXPORTER,
}

_PROTOCOL_ENV_BY_SIGNAL_TYPE = {
"traces": OTEL_EXPORTER_OTLP_TRACES_PROTOCOL,
"metrics": OTEL_EXPORTER_OTLP_METRICS_PROTOCOL,
"logs": OTEL_EXPORTER_OTLP_LOGS_PROTOCOL,
}

_RANDOM_ID_GENERATOR = "random"
_DEFAULT_ID_GENERATOR = _RANDOM_ID_GENERATOR

_logger = logging.getLogger(__name__)


def _get_id_generator() -> str:
return environ.get(OTEL_PYTHON_ID_GENERATOR, _DEFAULT_ID_GENERATOR)


def _get_exporter_names(names: str) -> Sequence[str]:
exporters = set()
def _get_exporter_entry_point(
exporter_name: str, signal_type: Literal["traces", "metrics", "logs"]
):
if exporter_name not in (
_EXPORTER_OTLP,
_EXPORTER_OTLP_PROTO_GRPC,
_EXPORTER_OTLP_PROTO_HTTP,
):
return exporter_name

# Checking env vars for OTLP protocol (grpc/http).
otlp_protocol = environ.get(
_PROTOCOL_ENV_BY_SIGNAL_TYPE[signal_type]
) or environ.get(OTEL_EXPORTER_OTLP_PROTOCOL)

if not otlp_protocol:
if exporter_name == _EXPORTER_OTLP:
return _EXPORTER_OTLP_PROTO_GRPC
return exporter_name

otlp_protocol = otlp_protocol.strip()

if exporter_name == _EXPORTER_OTLP:
if otlp_protocol not in _EXPORTER_BY_OTLP_PROTOCOL:
# Invalid value was set by the env var
raise RuntimeError(
f"Unsupported OTLP protocol '{otlp_protocol}' is configured"
)

return _EXPORTER_BY_OTLP_PROTOCOL[otlp_protocol]

# grpc/http already specified by exporter_name, only add a warning in case
# of a conflict.
exporter_name_by_env = _EXPORTER_BY_OTLP_PROTOCOL.get(otlp_protocol)
if exporter_name_by_env and exporter_name != exporter_name_by_env:
_logger.warning(
"Conflicting values for %s OTLP exporter protocol, using '%s'",
signal_type,
exporter_name,
)

return exporter_name


if names and names.lower().strip() != "none":
exporters.update({_exporter.strip() for _exporter in names.split(",")})
def _get_exporter_names(
signal_type: Literal["traces", "metrics", "logs"]
) -> Sequence[str]:
names = environ.get(_EXPORTER_ENV_BY_SIGNAL_TYPE.get(signal_type, ""))

if _EXPORTER_OTLP in exporters:
exporters.remove(_EXPORTER_OTLP)
exporters.add(_EXPORTER_OTLP_PROTO_GRPC)
if not names or names.lower().strip() == "none":
return []

return list(exporters)
return [
_get_exporter_entry_point(_exporter.strip(), signal_type)
for _exporter in names.split(",")
]


def _init_tracing(
Expand Down Expand Up @@ -232,9 +302,9 @@ def _import_id_generator(id_generator_name: str) -> IdGenerator:

def _initialize_components(auto_instrumentation_version):
trace_exporters, metric_exporters, log_exporters = _import_exporters(
_get_exporter_names(environ.get(OTEL_TRACES_EXPORTER)),
_get_exporter_names(environ.get(OTEL_METRICS_EXPORTER)),
_get_exporter_names(environ.get(OTEL_LOGS_EXPORTER)),
_get_exporter_names("traces"),
_get_exporter_names("metrics"),
_get_exporter_names("logs"),
)
id_generator_name = _get_id_generator()
id_generator = _import_id_generator(id_generator_name)
Expand Down
28 changes: 21 additions & 7 deletions opentelemetry-sdk/src/opentelemetry/sdk/environment_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,27 @@
OTLP exporter.
"""

OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL"
"""
.. envvar:: OTEL_EXPORTER_OTLP_TRACES_PROTOCOL
The :envvar:`OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` represents the the transport protocol for spans.
"""

OTEL_EXPORTER_OTLP_METRICS_PROTOCOL = "OTEL_EXPORTER_OTLP_METRICS_PROTOCOL"
"""
.. envvar:: OTEL_EXPORTER_OTLP_METRICS_PROTOCOL
The :envvar:`OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` represents the the transport protocol for metrics.
"""

OTEL_EXPORTER_OTLP_LOGS_PROTOCOL = "OTEL_EXPORTER_OTLP_LOGS_PROTOCOL"
"""
.. envvar:: OTEL_EXPORTER_OTLP_LOGS_PROTOCOL
The :envvar:`OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` represents the the transport protocol for logs.
"""

OTEL_EXPORTER_OTLP_CERTIFICATE = "OTEL_EXPORTER_OTLP_CERTIFICATE"
"""
.. envvar:: OTEL_EXPORTER_OTLP_CERTIFICATE
Expand Down Expand Up @@ -314,13 +335,6 @@
A scheme of https indicates a secure connection and takes precedence over this configuration setting.
"""

OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL"
"""
.. envvar:: OTEL_EXPORTER_OTLP_TRACES_PROTOCOL
The :envvar:`OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` represents the the transport protocol for spans.
"""

OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE"
"""
.. envvar:: OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE
Expand Down
71 changes: 64 additions & 7 deletions opentelemetry-sdk/tests/test_configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from opentelemetry.sdk._configuration import (
_EXPORTER_OTLP,
_EXPORTER_OTLP_PROTO_GRPC,
_EXPORTER_OTLP_PROTO_HTTP,
_get_exporter_names,
_get_id_generator,
_import_exporters,
Expand Down Expand Up @@ -413,25 +414,81 @@ def test_metrics_init_exporter(self):


class TestExporterNames(TestCase):
def test_otlp_exporter_overwrite(self):
for exporter in [_EXPORTER_OTLP, _EXPORTER_OTLP_PROTO_GRPC]:
@patch.dict(
environ,
{
"OTEL_TRACES_EXPORTER": _EXPORTER_OTLP,
"OTEL_METRICS_EXPORTER": _EXPORTER_OTLP_PROTO_GRPC,
"OTEL_LOGS_EXPORTER": _EXPORTER_OTLP_PROTO_HTTP,
},
)
def test_otlp_exporter(self):
self.assertEqual(
_get_exporter_names("traces"), [_EXPORTER_OTLP_PROTO_GRPC]
)
self.assertEqual(
_get_exporter_names("metrics"), [_EXPORTER_OTLP_PROTO_GRPC]
)
self.assertEqual(
_get_exporter_names("logs"), [_EXPORTER_OTLP_PROTO_HTTP]
)

@patch.dict(
environ,
{
"OTEL_TRACES_EXPORTER": _EXPORTER_OTLP,
"OTEL_METRICS_EXPORTER": _EXPORTER_OTLP,
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_METRICS_PROTOCOL": "grpc",
},
)
def test_otlp_custom_exporter(self):
self.assertEqual(
_get_exporter_names("traces"), [_EXPORTER_OTLP_PROTO_HTTP]
)
self.assertEqual(
_get_exporter_names("metrics"), [_EXPORTER_OTLP_PROTO_GRPC]
)

@patch.dict(
environ,
{
"OTEL_TRACES_EXPORTER": _EXPORTER_OTLP_PROTO_HTTP,
"OTEL_METRICS_EXPORTER": _EXPORTER_OTLP_PROTO_GRPC,
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_EXPORTER_OTLP_METRICS_PROTOCOL": "http/protobuf",
},
)
def test_otlp_exporter_conflict(self):
# Verify that OTEL_*_EXPORTER is used, and a warning is logged
with self.assertLogs(level="WARNING") as logs_context:
self.assertEqual(
_get_exporter_names("traces"), [_EXPORTER_OTLP_PROTO_HTTP]
)
assert len(logs_context.output) == 1

with self.assertLogs(level="WARNING") as logs_context:
self.assertEqual(
_get_exporter_names(exporter), [_EXPORTER_OTLP_PROTO_GRPC]
_get_exporter_names("metrics"), [_EXPORTER_OTLP_PROTO_GRPC]
)
assert len(logs_context.output) == 1

@patch.dict(environ, {"OTEL_TRACES_EXPORTER": "jaeger,zipkin"})
def test_multiple_exporters(self):
self.assertEqual(
sorted(_get_exporter_names("jaeger,zipkin")), ["jaeger", "zipkin"]
sorted(_get_exporter_names("traces")), ["jaeger", "zipkin"]
)

@patch.dict(environ, {"OTEL_TRACES_EXPORTER": "none"})
def test_none_exporters(self):
self.assertEqual(sorted(_get_exporter_names("none")), [])
self.assertEqual(sorted(_get_exporter_names("traces")), [])

def test_no_exporters(self):
self.assertEqual(sorted(_get_exporter_names(None)), [])
self.assertEqual(sorted(_get_exporter_names("traces")), [])

@patch.dict(environ, {"OTEL_TRACES_EXPORTER": ""})
def test_empty_exporters(self):
self.assertEqual(sorted(_get_exporter_names("")), [])
self.assertEqual(sorted(_get_exporter_names("traces")), [])


class TestImportExporters(TestCase):
Expand Down

0 comments on commit 71b4906

Please sign in to comment.