diff --git a/CHANGELOG.md b/CHANGELOG.md index f8b1a254db..e4f19b0aa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Always setup logs sdk, OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED only controls python `logging` module handler setup + ([#4340](https://github.com/open-telemetry/opentelemetry-python/pull/4340)) + + ## Version 1.29.0/0.50b0 (2024-12-11) - Fix crash exporting a log record with None body diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 2dffd78023..a8f9826c31 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -236,6 +236,7 @@ def _init_metrics( def _init_logging( exporters: Dict[str, Type[LogExporter]], resource: Resource = None, + setup_logging_handler: bool = True, ): provider = LoggerProvider(resource=resource) set_logger_provider(provider) @@ -246,13 +247,15 @@ def _init_logging( BatchLogRecordProcessor(exporter_class(**exporter_args)) ) - handler = LoggingHandler(level=logging.NOTSET, logger_provider=provider) - - logging.getLogger().addHandler(handler) - event_logger_provider = EventLoggerProvider(logger_provider=provider) set_event_logger_provider(event_logger_provider) + if setup_logging_handler: + handler = LoggingHandler( + level=logging.NOTSET, logger_provider=provider + ) + logging.getLogger().addHandler(handler) + def _import_exporters( trace_exporter_names: Sequence[str], @@ -364,7 +367,7 @@ def _initialize_components( sampler: Optional[Sampler] = None, resource_attributes: Optional[Attributes] = None, id_generator: IdGenerator = None, - logging_enabled: Optional[bool] = None, + setup_logging_handler: Optional[bool] = None, ): if trace_exporter_names is None: trace_exporter_names = [] @@ -401,8 +404,8 @@ def _initialize_components( resource=resource, ) _init_metrics(metric_exporters, resource) - if logging_enabled is None: - logging_enabled = ( + if setup_logging_handler is None: + setup_logging_handler = ( os.getenv( _OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED, "false" ) @@ -410,8 +413,7 @@ def _initialize_components( .lower() == "true" ) - if logging_enabled: - _init_logging(log_exporters, resource) + _init_logging(log_exporters, resource, setup_logging_handler) class _BaseConfigurator(ABC): diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py index 260df81f70..f09807547c 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py @@ -669,7 +669,7 @@ .. envvar:: OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED The :envvar:`OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED` environment variable allows users to -enable/disable the logging SDK auto instrumentation. +enable/disable the auto instrumentation for the python logging module. Default: False Note: Logs SDK and its related settings are experimental. diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 034d5b8c9b..4bc969d9e3 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -17,7 +17,7 @@ from logging import WARNING, getLogger from os import environ from typing import Dict, Iterable, Optional, Sequence -from unittest import TestCase +from unittest import TestCase, mock from unittest.mock import Mock, patch from pytest import raises @@ -663,6 +663,32 @@ def test_logging_init_exporter(self): getLogger(__name__).error("hello") self.assertTrue(provider.processor.exporter.export_called) + @patch.dict( + environ, + {"OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service"}, + ) + def test_logging_init_exporter_without_handler_setup(self): + resource = Resource.create({}) + _init_logging( + {"otlp": DummyOTLPLogExporter}, + resource=resource, + setup_logging_handler=False, + ) + self.assertEqual(self.set_provider_mock.call_count, 1) + provider = self.set_provider_mock.call_args[0][0] + self.assertIsInstance(provider, DummyLoggerProvider) + self.assertIsInstance(provider.resource, Resource) + self.assertEqual( + provider.resource.attributes.get("service.name"), + "otlp-service", + ) + self.assertIsInstance(provider.processor, DummyLogRecordProcessor) + self.assertIsInstance( + provider.processor.exporter, DummyOTLPLogExporter + ) + getLogger(__name__).error("hello") + self.assertFalse(provider.processor.exporter.export_called) + @patch.dict( environ, {"OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service"}, @@ -671,8 +697,8 @@ def test_logging_init_exporter(self): @patch("opentelemetry.sdk._configuration._init_logging") def test_logging_init_disable_default(self, logging_mock, tracing_mock): _initialize_components(auto_instrumentation_version="auto-version") - self.assertEqual(logging_mock.call_count, 0) self.assertEqual(tracing_mock.call_count, 1) + logging_mock.assert_called_once_with(mock.ANY, mock.ANY, False) @patch.dict( environ, @@ -686,7 +712,7 @@ def test_logging_init_disable_default(self, logging_mock, tracing_mock): def test_logging_init_enable_env(self, logging_mock, tracing_mock): with self.assertLogs(level=WARNING): _initialize_components(auto_instrumentation_version="auto-version") - self.assertEqual(logging_mock.call_count, 1) + logging_mock.assert_called_once_with(mock.ANY, mock.ANY, True) self.assertEqual(tracing_mock.call_count, 1) @patch.dict( @@ -768,7 +794,7 @@ def test_initialize_components_kwargs( "custom.key.2": "pass-in-value-2", }, "id_generator": "TEST_GENERATOR", - "logging_enabled": True, + "setup_logging_handler": True, } _initialize_components(**kwargs) @@ -810,6 +836,7 @@ def test_initialize_components_kwargs( logging_mock.assert_called_once_with( "TEST_LOG_EXPORTERS_DICT", "TEST_RESOURCE", + True, )