Skip to content

Commit 46f77d0

Browse files
author
Alex Boten
authored
Adding support for entrypoint loading of log exporters (#2253)
1 parent 5added0 commit 46f77d0

File tree

5 files changed

+92
-42
lines changed

5 files changed

+92
-42
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
([#2234](https://github.com/open-telemetry/opentelemetry-python/pull/2234))
1111
- Update visibility of OTEL_METRICS_EXPORTER environment variable
1212
([#2303](https://github.com/open-telemetry/opentelemetry-python/pull/2303))
13+
- Adding entrypoints for log emitter provider and console, otlp log exporters
14+
([#2253](https://github.com/open-telemetry/opentelemetry-python/pull/2253))
1315

1416
## [1.7.1-0.26b1](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.7.0-0.26b0) - 2021-11-11
1517

exporter/opentelemetry-exporter-otlp-proto-grpc/setup.cfg

+2
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,5 @@ where = src
5757
[options.entry_points]
5858
opentelemetry_traces_exporter =
5959
otlp_proto_grpc = opentelemetry.exporter.otlp.proto.grpc.trace_exporter:OTLPSpanExporter
60+
opentelemetry_logs_exporter =
61+
otlp_proto_grpc = opentelemetry.exporter.otlp.proto.grpc._log_exporter:OTLPLogExporter

opentelemetry-sdk/setup.cfg

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ opentelemetry_traces_exporter =
5656
console = opentelemetry.sdk.trace.export:ConsoleSpanExporter
5757
opentelemetry_log_emitter_provider =
5858
sdk_log_emitter_provider = opentelemetry.sdk._logs:LogEmitterProvider
59+
opentelemetry_logs_exporter =
60+
console = opentelemetry.sdk._logs.export:ConsoleExporter
5961
opentelemetry_id_generator =
6062
random = opentelemetry.sdk.trace.id_generator:RandomIdGenerator
6163
opentelemetry_environment_variables =

opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py

+58-26
Original file line numberDiff line numberDiff line change
@@ -28,39 +28,40 @@
2828
OTEL_PYTHON_ID_GENERATOR,
2929
OTEL_TRACES_EXPORTER,
3030
)
31+
from opentelemetry.sdk._logs import (
32+
LogEmitterProvider,
33+
set_log_emitter_provider,
34+
)
35+
from opentelemetry.sdk._logs.export import BatchLogProcessor, LogExporter
3136
from opentelemetry.sdk.resources import Resource
3237
from opentelemetry.sdk.trace import TracerProvider
3338
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExporter
3439
from opentelemetry.sdk.trace.id_generator import IdGenerator
3540
from opentelemetry.semconv.resource import ResourceAttributes
3641

3742
_EXPORTER_OTLP = "otlp"
38-
_EXPORTER_OTLP_SPAN = "otlp_proto_grpc"
43+
_EXPORTER_OTLP_PROTO_GRPC = "otlp_proto_grpc"
3944

4045
_RANDOM_ID_GENERATOR = "random"
4146
_DEFAULT_ID_GENERATOR = _RANDOM_ID_GENERATOR
4247

48+
# TODO: add log exporter env variable
49+
_OTEL_LOGS_EXPORTER = "OTEL_LOGS_EXPORTER"
50+
4351

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

4755

48-
def _get_exporter_names() -> Sequence[str]:
49-
trace_exporters = environ.get(OTEL_TRACES_EXPORTER)
50-
56+
def _get_exporter_names(names: str) -> Sequence[str]:
5157
exporters = set()
5258

53-
if trace_exporters and trace_exporters.lower().strip() != "none":
54-
exporters.update(
55-
{
56-
trace_exporter.strip()
57-
for trace_exporter in trace_exporters.split(",")
58-
}
59-
)
59+
if names and names.lower().strip() != "none":
60+
exporters.update({_exporter.strip() for _exporter in names.split(",")})
6061

6162
if _EXPORTER_OTLP in exporters:
6263
exporters.remove(_EXPORTER_OTLP)
63-
exporters.add(_EXPORTER_OTLP_SPAN)
64+
exporters.add(_EXPORTER_OTLP_PROTO_GRPC)
6465

6566
return list(exporters)
6667

@@ -91,7 +92,29 @@ def _init_tracing(
9192
)
9293

9394

94-
def _import_tracer_provider_config_components(
95+
def _init_logging(
96+
exporters: Dict[str, Sequence[LogExporter]],
97+
auto_instrumentation_version: Optional[str] = None,
98+
):
99+
# if env var OTEL_RESOURCE_ATTRIBUTES is given, it will read the service_name
100+
# from the env variable else defaults to "unknown_service"
101+
auto_resource = {}
102+
# populate version if using auto-instrumentation
103+
if auto_instrumentation_version:
104+
auto_resource[
105+
ResourceAttributes.TELEMETRY_AUTO_VERSION
106+
] = auto_instrumentation_version
107+
provider = LogEmitterProvider(resource=Resource.create(auto_resource))
108+
set_log_emitter_provider(provider)
109+
110+
for _, exporter_class in exporters.items():
111+
exporter_args = {}
112+
provider.add_log_processor(
113+
BatchLogProcessor(exporter_class(**exporter_args))
114+
)
115+
116+
117+
def _import_config_components(
95118
selected_components, entry_point_name
96119
) -> Sequence[Tuple[str, object]]:
97120
component_entry_points = {
@@ -112,28 +135,34 @@ def _import_tracer_provider_config_components(
112135

113136

114137
def _import_exporters(
115-
exporter_names: Sequence[str],
116-
) -> Dict[str, Type[SpanExporter]]:
138+
trace_exporter_names: Sequence[str],
139+
log_exporter_names: Sequence[str],
140+
) -> Tuple[Dict[str, Type[SpanExporter]], Dict[str, Type[LogExporter]]]:
117141
trace_exporters = {}
142+
log_exporters = {}
118143

119-
for (
120-
exporter_name,
121-
exporter_impl,
122-
) in _import_tracer_provider_config_components(
123-
exporter_names, "opentelemetry_traces_exporter"
144+
for (exporter_name, exporter_impl,) in _import_config_components(
145+
trace_exporter_names, "opentelemetry_traces_exporter"
124146
):
125147
if issubclass(exporter_impl, SpanExporter):
126148
trace_exporters[exporter_name] = exporter_impl
127149
else:
128150
raise RuntimeError(f"{exporter_name} is not a trace exporter")
129-
return trace_exporters
151+
152+
for (exporter_name, exporter_impl,) in _import_config_components(
153+
log_exporter_names, "opentelemetry_logs_exporter"
154+
):
155+
if issubclass(exporter_impl, LogExporter):
156+
log_exporters[exporter_name] = exporter_impl
157+
else:
158+
raise RuntimeError(f"{exporter_name} is not a log exporter")
159+
160+
return trace_exporters, log_exporters
130161

131162

132163
def _import_id_generator(id_generator_name: str) -> IdGenerator:
133164
# pylint: disable=unbalanced-tuple-unpacking
134-
[
135-
(id_generator_name, id_generator_impl)
136-
] = _import_tracer_provider_config_components(
165+
[(id_generator_name, id_generator_impl)] = _import_config_components(
137166
[id_generator_name.strip()], "opentelemetry_id_generator"
138167
)
139168

@@ -144,11 +173,14 @@ def _import_id_generator(id_generator_name: str) -> IdGenerator:
144173

145174

146175
def _initialize_components(auto_instrumentation_version):
147-
exporter_names = _get_exporter_names()
148-
trace_exporters = _import_exporters(exporter_names)
176+
trace_exporters, log_exporters = _import_exporters(
177+
_get_exporter_names(environ.get(OTEL_TRACES_EXPORTER)),
178+
_get_exporter_names(environ.get(_OTEL_LOGS_EXPORTER)),
179+
)
149180
id_generator_name = _get_id_generator()
150181
id_generator = _import_id_generator(id_generator_name)
151182
_init_tracing(trace_exporters, id_generator, auto_instrumentation_version)
183+
_init_logging(log_exporters, auto_instrumentation_version)
152184

153185

154186
class _BaseConfigurator(ABC):

opentelemetry-sdk/tests/test_configurator.py

+28-16
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@
1818
from unittest.mock import patch
1919

2020
from opentelemetry import trace
21-
from opentelemetry.environment_variables import (
22-
OTEL_PYTHON_ID_GENERATOR,
23-
OTEL_TRACES_EXPORTER,
24-
)
21+
from opentelemetry.environment_variables import OTEL_PYTHON_ID_GENERATOR
2522
from opentelemetry.sdk._configuration import (
2623
_EXPORTER_OTLP,
27-
_EXPORTER_OTLP_SPAN,
24+
_EXPORTER_OTLP_PROTO_GRPC,
2825
_get_exporter_names,
2926
_get_id_generator,
27+
_import_exporters,
3028
_import_id_generator,
3129
_init_tracing,
3230
)
31+
from opentelemetry.sdk._logs.export import ConsoleExporter
3332
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
33+
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
3434
from opentelemetry.sdk.trace.id_generator import IdGenerator, RandomIdGenerator
3535

3636

@@ -164,22 +164,34 @@ def test_trace_init_custom_id_generator(self, mock_iter_entry_points):
164164

165165
class TestExporterNames(TestCase):
166166
def test_otlp_exporter_overwrite(self):
167-
for exporter in [_EXPORTER_OTLP, _EXPORTER_OTLP_SPAN]:
168-
with patch.dict(environ, {OTEL_TRACES_EXPORTER: exporter}):
169-
self.assertEqual(_get_exporter_names(), [_EXPORTER_OTLP_SPAN])
167+
for exporter in [_EXPORTER_OTLP, _EXPORTER_OTLP_PROTO_GRPC]:
168+
self.assertEqual(
169+
_get_exporter_names(exporter), [_EXPORTER_OTLP_PROTO_GRPC]
170+
)
170171

171-
@patch.dict(environ, {OTEL_TRACES_EXPORTER: "jaeger,zipkin"})
172172
def test_multiple_exporters(self):
173-
self.assertEqual(sorted(_get_exporter_names()), ["jaeger", "zipkin"])
173+
self.assertEqual(
174+
sorted(_get_exporter_names("jaeger,zipkin")), ["jaeger", "zipkin"]
175+
)
174176

175-
@patch.dict(environ, {OTEL_TRACES_EXPORTER: "none"})
176177
def test_none_exporters(self):
177-
self.assertEqual(sorted(_get_exporter_names()), [])
178+
self.assertEqual(sorted(_get_exporter_names("none")), [])
178179

179-
@patch.dict(environ, {}, clear=True)
180180
def test_no_exporters(self):
181-
self.assertEqual(sorted(_get_exporter_names()), [])
181+
self.assertEqual(sorted(_get_exporter_names(None)), [])
182182

183-
@patch.dict(environ, {OTEL_TRACES_EXPORTER: ""})
184183
def test_empty_exporters(self):
185-
self.assertEqual(sorted(_get_exporter_names()), [])
184+
self.assertEqual(sorted(_get_exporter_names("")), [])
185+
186+
187+
class TestImportExporters(TestCase):
188+
def test_console_exporters(self):
189+
trace_exporters, logs_exporters = _import_exporters(
190+
["console"], ["console"]
191+
)
192+
self.assertEqual(
193+
trace_exporters["console"].__class__, ConsoleSpanExporter.__class__
194+
)
195+
self.assertEqual(
196+
logs_exporters["console"].__class__, ConsoleExporter.__class__
197+
)

0 commit comments

Comments
 (0)