Skip to content

Commit c6edd0f

Browse files
authored
Auto instrumentation parameters (#3864)
1 parent d73593d commit c6edd0f

File tree

3 files changed

+165
-24
lines changed

3 files changed

+165
-24
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5454
- unit annotations (enclosed in curly braces like `{requests}`) are stripped away
5555
- units with slash are converted e.g. `m/s` -> `meters_per_second`.
5656
- The exporter's API is not changed
57+
- Add parameters for Distros and configurators to configure autoinstrumentation in addition to existing environment variables.
58+
([#3864] (https://github.com/open-telemetry/opentelemetry-python/pull/3864))
5759

5860
## Version 1.24.0/0.45b0 (2024-03-28)
5961

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

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
MetricReader,
5151
PeriodicExportingMetricReader,
5252
)
53-
from opentelemetry.sdk.resources import Resource
53+
from opentelemetry.sdk.resources import Attributes, Resource
5454
from opentelemetry.sdk.trace import TracerProvider
5555
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExporter
5656
from opentelemetry.sdk.trace.id_generator import IdGenerator
@@ -354,37 +354,61 @@ def _import_id_generator(id_generator_name: str) -> IdGenerator:
354354
raise RuntimeError(f"{id_generator_name} is not an IdGenerator")
355355

356356

357-
def _initialize_components(auto_instrumentation_version):
358-
trace_exporters, metric_exporters, log_exporters = _import_exporters(
359-
_get_exporter_names("traces"),
360-
_get_exporter_names("metrics"),
361-
_get_exporter_names("logs"),
357+
def _initialize_components(
358+
auto_instrumentation_version: Optional[str] = None,
359+
trace_exporter_names: Optional[List[str]] = None,
360+
metric_exporter_names: Optional[List[str]] = None,
361+
log_exporter_names: Optional[List[str]] = None,
362+
sampler: Optional[Sampler] = None,
363+
resource_attributes: Optional[Attributes] = None,
364+
id_generator: IdGenerator = None,
365+
logging_enabled: Optional[bool] = None,
366+
):
367+
if trace_exporter_names is None:
368+
trace_exporter_names = []
369+
if metric_exporter_names is None:
370+
metric_exporter_names = []
371+
if log_exporter_names is None:
372+
log_exporter_names = []
373+
span_exporters, metric_exporters, log_exporters = _import_exporters(
374+
trace_exporter_names + _get_exporter_names("traces"),
375+
metric_exporter_names + _get_exporter_names("metrics"),
376+
log_exporter_names + _get_exporter_names("logs"),
362377
)
363-
sampler_name = _get_sampler()
364-
sampler = _import_sampler(sampler_name)
365-
id_generator_name = _get_id_generator()
366-
id_generator = _import_id_generator(id_generator_name)
367-
# if env var OTEL_RESOURCE_ATTRIBUTES is given, it will read the service_name
368-
# from the env variable else defaults to "unknown_service"
369-
auto_resource = {}
378+
if sampler is None:
379+
sampler_name = _get_sampler()
380+
sampler = _import_sampler(sampler_name)
381+
if id_generator is None:
382+
id_generator_name = _get_id_generator()
383+
id_generator = _import_id_generator(id_generator_name)
384+
if resource_attributes is None:
385+
resource_attributes = {}
370386
# populate version if using auto-instrumentation
371387
if auto_instrumentation_version:
372-
auto_resource[ResourceAttributes.TELEMETRY_AUTO_VERSION] = (
388+
resource_attributes[ResourceAttributes.TELEMETRY_AUTO_VERSION] = (
373389
auto_instrumentation_version
374390
)
375-
resource = Resource.create(auto_resource)
391+
# if env var OTEL_RESOURCE_ATTRIBUTES is given, it will read the service_name
392+
# from the env variable else defaults to "unknown_service"
393+
resource = Resource.create(resource_attributes)
376394

377395
_init_tracing(
378-
exporters=trace_exporters,
396+
exporters=span_exporters,
379397
id_generator=id_generator,
380398
sampler=sampler,
381399
resource=resource,
382400
)
383401
_init_metrics(metric_exporters, resource)
384-
logging_enabled = os.getenv(
385-
_OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED, "false"
386-
)
387-
if logging_enabled.strip().lower() == "true":
402+
if logging_enabled is None:
403+
logging_enabled = (
404+
os.getenv(
405+
_OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED, "false"
406+
)
407+
.strip()
408+
.lower()
409+
== "true"
410+
)
411+
if logging_enabled:
388412
_init_logging(log_exporters, resource)
389413

390414

@@ -428,4 +452,4 @@ class _OTelSDKConfigurator(_BaseConfigurator):
428452
"""
429453

430454
def _configure(self, **kwargs):
431-
_initialize_components(kwargs.get("auto_instrumentation_version"))
455+
_initialize_components(**kwargs)

opentelemetry-sdk/tests/test_configurator.py

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
_init_metrics,
4141
_init_tracing,
4242
_initialize_components,
43+
_OTelSDKConfigurator,
4344
)
4445
from opentelemetry.sdk._logs import LoggingHandler
4546
from opentelemetry.sdk._logs.export import ConsoleLogExporter
@@ -645,7 +646,7 @@ def test_logging_init_exporter(self):
645646
@patch("opentelemetry.sdk._configuration._init_tracing")
646647
@patch("opentelemetry.sdk._configuration._init_logging")
647648
def test_logging_init_disable_default(self, logging_mock, tracing_mock):
648-
_initialize_components("auto-version")
649+
_initialize_components(auto_instrumentation_version="auto-version")
649650
self.assertEqual(logging_mock.call_count, 0)
650651
self.assertEqual(tracing_mock.call_count, 1)
651652

@@ -660,7 +661,7 @@ def test_logging_init_disable_default(self, logging_mock, tracing_mock):
660661
@patch("opentelemetry.sdk._configuration._init_logging")
661662
def test_logging_init_enable_env(self, logging_mock, tracing_mock):
662663
with self.assertLogs(level=WARNING):
663-
_initialize_components("auto-version")
664+
_initialize_components(auto_instrumentation_version="auto-version")
664665
self.assertEqual(logging_mock.call_count, 1)
665666
self.assertEqual(tracing_mock.call_count, 1)
666667

@@ -677,7 +678,7 @@ def test_logging_init_enable_env(self, logging_mock, tracing_mock):
677678
def test_initialize_components_resource(
678679
self, metrics_mock, logging_mock, tracing_mock
679680
):
680-
_initialize_components("auto-version")
681+
_initialize_components(auto_instrumentation_version="auto-version")
681682
self.assertEqual(logging_mock.call_count, 1)
682683
self.assertEqual(tracing_mock.call_count, 1)
683684
self.assertEqual(metrics_mock.call_count, 1)
@@ -692,6 +693,101 @@ def test_initialize_components_resource(
692693
self.assertEqual(logging_resource, metrics_resource)
693694
self.assertEqual(tracing_resource, metrics_resource)
694695

696+
@patch.dict(
697+
environ,
698+
{
699+
"OTEL_TRACES_EXPORTER": _EXPORTER_OTLP,
700+
"OTEL_METRICS_EXPORTER": _EXPORTER_OTLP_PROTO_GRPC,
701+
"OTEL_LOGS_EXPORTER": _EXPORTER_OTLP_PROTO_HTTP,
702+
},
703+
)
704+
@patch.dict(
705+
environ,
706+
{
707+
"OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service, custom.key.1=env-value",
708+
"OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED": "False",
709+
},
710+
)
711+
@patch("opentelemetry.sdk._configuration.Resource")
712+
@patch("opentelemetry.sdk._configuration._import_exporters")
713+
@patch("opentelemetry.sdk._configuration._get_exporter_names")
714+
@patch("opentelemetry.sdk._configuration._init_tracing")
715+
@patch("opentelemetry.sdk._configuration._init_logging")
716+
@patch("opentelemetry.sdk._configuration._init_metrics")
717+
def test_initialize_components_kwargs(
718+
self,
719+
metrics_mock,
720+
logging_mock,
721+
tracing_mock,
722+
exporter_names_mock,
723+
import_exporters_mock,
724+
resource_mock,
725+
):
726+
exporter_names_mock.return_value = [
727+
"env_var_exporter_1",
728+
"env_var_exporter_2",
729+
]
730+
import_exporters_mock.return_value = (
731+
"TEST_SPAN_EXPORTERS_DICT",
732+
"TEST_METRICS_EXPORTERS_DICT",
733+
"TEST_LOG_EXPORTERS_DICT",
734+
)
735+
resource_mock.create.return_value = "TEST_RESOURCE"
736+
kwargs = {
737+
"auto_instrumentation_version": "auto-version",
738+
"trace_exporter_names": ["custom_span_exporter"],
739+
"metric_exporter_names": ["custom_metric_exporter"],
740+
"log_exporter_names": ["custom_log_exporter"],
741+
"sampler": "TEST_SAMPLER",
742+
"resource_attributes": {
743+
"custom.key.1": "pass-in-value-1",
744+
"custom.key.2": "pass-in-value-2",
745+
},
746+
"id_generator": "TEST_GENERATOR",
747+
"logging_enabled": True,
748+
}
749+
_initialize_components(**kwargs)
750+
751+
import_exporters_mock.assert_called_once_with(
752+
[
753+
"custom_span_exporter",
754+
"env_var_exporter_1",
755+
"env_var_exporter_2",
756+
],
757+
[
758+
"custom_metric_exporter",
759+
"env_var_exporter_1",
760+
"env_var_exporter_2",
761+
],
762+
[
763+
"custom_log_exporter",
764+
"env_var_exporter_1",
765+
"env_var_exporter_2",
766+
],
767+
)
768+
resource_mock.create.assert_called_once_with(
769+
{
770+
"telemetry.auto.version": "auto-version",
771+
"custom.key.1": "pass-in-value-1",
772+
"custom.key.2": "pass-in-value-2",
773+
}
774+
)
775+
# Resource is checked separates
776+
tracing_mock.assert_called_once_with(
777+
exporters="TEST_SPAN_EXPORTERS_DICT",
778+
id_generator="TEST_GENERATOR",
779+
sampler="TEST_SAMPLER",
780+
resource="TEST_RESOURCE",
781+
)
782+
metrics_mock.assert_called_once_with(
783+
"TEST_METRICS_EXPORTERS_DICT",
784+
"TEST_RESOURCE",
785+
)
786+
logging_mock.assert_called_once_with(
787+
"TEST_LOG_EXPORTERS_DICT",
788+
"TEST_RESOURCE",
789+
)
790+
695791

696792
class TestMetricsInit(TestCase):
697793
def setUp(self):
@@ -910,3 +1006,22 @@ def test__import_config_components_missing_component(
9101006
str(error.value),
9111007
"Requested component 'a' not found in entry point 'name'",
9121008
)
1009+
1010+
1011+
class TestConfigurator(TestCase):
1012+
class CustomConfigurator(_OTelSDKConfigurator):
1013+
def _configure(self, **kwargs):
1014+
kwargs["sampler"] = "TEST_SAMPLER"
1015+
super()._configure(**kwargs)
1016+
1017+
@patch("opentelemetry.sdk._configuration._initialize_components")
1018+
def test_custom_configurator(self, mock_init_comp):
1019+
custom_configurator = TestConfigurator.CustomConfigurator()
1020+
custom_configurator._configure(
1021+
auto_instrumentation_version="TEST_VERSION2"
1022+
)
1023+
kwargs = {
1024+
"auto_instrumentation_version": "TEST_VERSION2",
1025+
"sampler": "TEST_SAMPLER",
1026+
}
1027+
mock_init_comp.assert_called_once_with(**kwargs)

0 commit comments

Comments
 (0)