From 85eaee7255d82a58463dd6ff62b143e08bb84a00 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Mon, 12 May 2025 14:56:09 -0700 Subject: [PATCH 01/11] Squash: Add Log Level and Format configuration for autoinstrumentation --- CHANGELOG.md | 2 + .../sdk/_configuration/__init__.py | 31 ++- .../sdk/environment_variables/__init__.py | 16 ++ opentelemetry-sdk/tests/test_configurator.py | 259 +++++++++++++++++- 4 files changed, 302 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bac47c6bc01..fa72e74c8cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Refactor `BatchLogRecordProcessor` to simplify code and make the control flow more clear ([#4562](https://github.com/open-telemetry/opentelemetry-python/pull/4562/) and [#4535](https://github.com/open-telemetry/opentelemetry-python/pull/4535)). +- Enable configuration of logging format and level in auto-instrumentation + ([#4203](https://github.com/open-telemetry/opentelemetry-python/pull/4203)) ## Version 1.33.0/0.54b0 (2025-05-09) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 745a83385f9..03ba423e231 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -47,6 +47,8 @@ OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG, + OTEL_PYTHON_LOG_LEVEL, + OTEL_PYTHON_LOG_FORMAT, ) from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.metrics.export import ( @@ -89,6 +91,15 @@ _OTEL_SAMPLER_ENTRY_POINT_GROUP = "opentelemetry_traces_sampler" +_OTEL_PYTHON_LOG_LEVEL_BY_NAME = { + "notset": logging.NOTSET, + "debug": logging.DEBUG, + "info": logging.INFO, + "warn": logging.WARNING, + "warning": logging.WARNING, + "error": logging.ERROR, +} + _logger = logging.getLogger(__name__) @@ -132,6 +143,9 @@ def _get_sampler() -> str | None: def _get_id_generator() -> str: return environ.get(OTEL_PYTHON_ID_GENERATOR, _DEFAULT_ID_GENERATOR) +def _get_log_level() -> int: + return _OTEL_PYTHON_LOG_LEVEL_BY_NAME.get(environ.get(OTEL_PYTHON_LOG_LEVEL, "notset").lower().strip(), logging.NOTSET) + def _get_exporter_entry_point( exporter_name: str, signal_type: Literal["traces", "metrics", "logs"] @@ -255,11 +269,19 @@ def _init_logging( if setup_logging_handler: _patch_basic_config() - # Add OTel handler + # Log Handler + root_logger = logging.getLogger() handler = LoggingHandler( - level=logging.NOTSET, logger_provider=provider + logger_provider=provider ) - logging.getLogger().addHandler(handler) + # Log level + if OTEL_PYTHON_LOG_LEVEL in environ: + handler.setLevel(_get_log_level()) + # Log format + if OTEL_PYTHON_LOG_FORMAT in environ: + log_format = environ.get(OTEL_PYTHON_LOG_FORMAT, logging.BASIC_FORMAT) + handler.setFormatter(logging.Formatter(log_format)) + root_logger.addHandler(handler) def _patch_basic_config(): @@ -470,7 +492,8 @@ class _OTelSDKConfigurator(_BaseConfigurator): Initializes several crucial OTel SDK components (i.e. TracerProvider, MeterProvider, Processors...) according to a default implementation. Other - Configurators can subclass and slightly alter this initialization. + Configurators can subclass and slightly alter + this initialization. NOTE: This class should not be instantiated nor should it become an entry point on the `opentelemetry-sdk` package. Instead, distros should subclass diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py index 23b634fcd85..ab88b8d1bf8 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py @@ -54,6 +54,22 @@ Default: "info" """ +OTEL_PYTHON_LOG_FORMAT = "OTEL_PYTHON_LOG_FORMAT" +""" +.. envvar:: OTEL_PYTHON_LOG_FORMAT + +The :envvar:`OTEL_PYTHON_LOG_FORMAT` environment variable sets the log format for the OpenTelemetry LoggingHandler's Formatter +Default: "logging.BASIC_FORMAT" +""" + +OTEL_PYTHON_LOG_LEVEL = "OTEL_PYTHON_LOG_LEVEL" +""" +.. envvar:: OTEL_PYTHON_LOG_LEVEL + +The :envvar:`OTEL_PYTHON_LOG_LEVEL` environment variable sets the log level for the OpenTelemetry LoggingHandler +Default: "logging.NOTSET" +""" + OTEL_TRACES_SAMPLER = "OTEL_TRACES_SAMPLER" """ .. envvar:: OTEL_TRACES_SAMPLER diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 9fda75b66f0..4d635c2c80c 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -16,7 +16,14 @@ from __future__ import annotations import logging -from logging import WARNING, getLogger +from logging import ( + DEBUG, + ERROR, + INFO, + NOTSET, + WARNING, + getLogger, +) from os import environ from typing import Iterable, Optional, Sequence from unittest import TestCase, mock @@ -33,6 +40,7 @@ _EXPORTER_OTLP_PROTO_HTTP, _get_exporter_names, _get_id_generator, + _get_log_level, _get_sampler, _import_config_components, _import_exporters, @@ -76,6 +84,9 @@ from opentelemetry.util.types import Attributes +CUSTOM_LOG_FORMAT = "CUSTOM FORMAT %(levelname)s:%(name)s:%(message)s" + + class Provider: def __init__(self, resource=None, sampler=None, id_generator=None): self.sampler = sampler @@ -669,7 +680,119 @@ def test_logging_init_exporter(self): @patch.dict( environ, - {"OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service"}, + { + "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", + "OTEL_PYTHON_LOG_LEVEL": "CUSTOM_LOG_LEVEL", + }, + clear=True, + ) + @patch("opentelemetry.sdk._configuration._get_log_level", return_value=39) + def test_logging_init_exporter_level_under(self, log_level_mock): + resource = Resource.create({}) + _init_logging( + {"otlp": DummyOTLPLogExporter}, + resource=resource, + ) + 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.assertTrue(provider.processor.exporter.export_called) + root_logger = getLogger() + handler_present = False + for handler in root_logger.handlers: + if isinstance(handler, LoggingHandler): + handler_present = True + self.assertEqual(handler.level, 39) + self.assertTrue(handler_present) + + @patch.dict( + environ, + { + "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", + "OTEL_PYTHON_LOG_LEVEL": "CUSTOM_LOG_LEVEL", + }, + clear=True, + ) + @patch("opentelemetry.sdk._configuration._get_log_level", return_value=41) + def test_logging_init_exporter_level_over(self, log_level_mock): + resource = Resource.create({}) + _init_logging( + {"otlp": DummyOTLPLogExporter}, + resource=resource, + ) + 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) + root_logger = getLogger() + handler_present = False + for handler in root_logger.handlers: + if isinstance(handler, LoggingHandler): + handler_present = True + self.assertEqual(handler.level, 41) + self.assertTrue(handler_present) + + @patch.dict( + environ, + { + "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", + "OTEL_PYTHON_LOG_FORMAT": CUSTOM_LOG_FORMAT, + }, + ) + def test_logging_init_exporter_format(self): + resource = Resource.create({}) + _init_logging( + {"otlp": DummyOTLPLogExporter}, + resource=resource, + ) + 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.assertTrue(provider.processor.exporter.export_called) + root_logger = getLogger() + self.assertEqual(root_logger.level, WARNING) + handler_present = False + for handler in root_logger.handlers: + if isinstance(handler, LoggingHandler): + self.assertEqual(handler.formatter._fmt, CUSTOM_LOG_FORMAT) + handler_present = True + self.assertTrue(handler_present) + + @patch.dict( + environ, + { + "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", + }, ) def test_logging_init_exporter_without_handler_setup(self): resource = Resource.create({}) @@ -692,6 +815,43 @@ def test_logging_init_exporter_without_handler_setup(self): ) getLogger(__name__).error("hello") self.assertFalse(provider.processor.exporter.export_called) + root_logger = getLogger() + self.assertEqual(root_logger.level, WARNING) + for handler in root_logger.handlers: + if isinstance(handler, LoggingHandler): + self.fail() + + @patch.dict(environ, {}, clear=True) + def test_OTEL_PYTHON_LOG_LEVEL_by_name_default(self): + self.assertEqual(_get_log_level(), NOTSET) + + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": "NOTSET "}, clear=True) + def test_OTEL_PYTHON_LOG_LEVEL_by_name_notset(self): + self.assertEqual(_get_log_level(), NOTSET) + + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " DeBug "}, clear=True) + def test_OTEL_PYTHON_LOG_LEVEL_by_name_debug(self): + self.assertEqual(_get_log_level(), DEBUG) + + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " info "}, clear=True) + def test_OTEL_PYTHON_LOG_LEVEL_by_name_info(self): + self.assertEqual(_get_log_level(), INFO) + + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " warn"}, clear=True) + def test_OTEL_PYTHON_LOG_LEVEL_by_name_warn(self): + self.assertEqual(_get_log_level(), WARNING) + + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " warnING "}, clear=True) + def test_OTEL_PYTHON_LOG_LEVEL_by_name_warning(self): + self.assertEqual(_get_log_level(), WARNING) + + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " eRroR"}, clear=True) + def test_OTEL_PYTHON_LOG_LEVEL_by_name_error(self): + self.assertEqual(_get_log_level(), ERROR) + + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": "foobar"}, clear=True) + def test_OTEL_PYTHON_LOG_LEVEL_by_name_invalid(self): + self.assertEqual(_get_log_level(), NOTSET) @patch.dict( environ, @@ -896,6 +1056,101 @@ def test_basicConfig_preserves_otel_handler(self): 1, "Should still have exactly one OpenTelemetry LoggingHandler", ) + + @patch.dict( + environ, + { + "OTEL_TRACES_EXPORTER": _EXPORTER_OTLP, + "OTEL_METRICS_EXPORTER": _EXPORTER_OTLP_PROTO_GRPC, + "OTEL_LOGS_EXPORTER": _EXPORTER_OTLP_PROTO_HTTP, + }, + ) + @patch.dict( + environ, + { + "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service, custom.key.1=env-value", + "OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED": "False", + }, + ) + @patch("opentelemetry.sdk._configuration.Resource") + @patch("opentelemetry.sdk._configuration._import_exporters") + @patch("opentelemetry.sdk._configuration._get_exporter_names") + @patch("opentelemetry.sdk._configuration._init_tracing") + @patch("opentelemetry.sdk._configuration._init_logging") + @patch("opentelemetry.sdk._configuration._init_metrics") + def test_initialize_components_kwargs_disable_logging_handler( + self, + metrics_mock, + logging_mock, + tracing_mock, + exporter_names_mock, + import_exporters_mock, + resource_mock, + ): + exporter_names_mock.return_value = [ + "env_var_exporter_1", + "env_var_exporter_2", + ] + import_exporters_mock.return_value = ( + "TEST_SPAN_EXPORTERS_DICT", + "TEST_METRICS_EXPORTERS_DICT", + "TEST_LOG_EXPORTERS_DICT", + ) + resource_mock.create.return_value = "TEST_RESOURCE" + kwargs = { + "auto_instrumentation_version": "auto-version", + "trace_exporter_names": ["custom_span_exporter"], + "metric_exporter_names": ["custom_metric_exporter"], + "log_exporter_names": ["custom_log_exporter"], + "sampler": "TEST_SAMPLER", + "resource_attributes": { + "custom.key.1": "pass-in-value-1", + "custom.key.2": "pass-in-value-2", + }, + "id_generator": "TEST_GENERATOR", + } + _initialize_components(**kwargs) + + import_exporters_mock.assert_called_once_with( + [ + "custom_span_exporter", + "env_var_exporter_1", + "env_var_exporter_2", + ], + [ + "custom_metric_exporter", + "env_var_exporter_1", + "env_var_exporter_2", + ], + [ + "custom_log_exporter", + "env_var_exporter_1", + "env_var_exporter_2", + ], + ) + resource_mock.create.assert_called_once_with( + { + "telemetry.auto.version": "auto-version", + "custom.key.1": "pass-in-value-1", + "custom.key.2": "pass-in-value-2", + } + ) + # Resource is checked separates + tracing_mock.assert_called_once_with( + exporters="TEST_SPAN_EXPORTERS_DICT", + id_generator="TEST_GENERATOR", + sampler="TEST_SAMPLER", + resource="TEST_RESOURCE", + ) + metrics_mock.assert_called_once_with( + "TEST_METRICS_EXPORTERS_DICT", + "TEST_RESOURCE", + ) + logging_mock.assert_called_once_with( + "TEST_LOG_EXPORTERS_DICT", + "TEST_RESOURCE", + False, + ) class TestMetricsInit(TestCase): From 7f76bcb02869e7645b8a6cadce69383c56b14a0c Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Mon, 12 May 2025 15:03:04 -0700 Subject: [PATCH 02/11] Clean up --- .../sdk/_configuration/__init__.py | 3 +- opentelemetry-sdk/tests/test_configurator.py | 44 +++++++++---------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 03ba423e231..da2f665fde0 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -492,8 +492,7 @@ class _OTelSDKConfigurator(_BaseConfigurator): Initializes several crucial OTel SDK components (i.e. TracerProvider, MeterProvider, Processors...) according to a default implementation. Other - Configurators can subclass and slightly alter - this initialization. + Configurators can subclass and slightly alter this initialization. NOTE: This class should not be instantiated nor should it become an entry point on the `opentelemetry-sdk` package. Instead, distros should subclass diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 4d635c2c80c..ec0050e5d41 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -682,16 +682,14 @@ def test_logging_init_exporter(self): environ, { "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", - "OTEL_PYTHON_LOG_LEVEL": "CUSTOM_LOG_LEVEL", }, - clear=True, ) - @patch("opentelemetry.sdk._configuration._get_log_level", return_value=39) - def test_logging_init_exporter_level_under(self, log_level_mock): + 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] @@ -706,14 +704,12 @@ def test_logging_init_exporter_level_under(self, log_level_mock): provider.processor.exporter, DummyOTLPLogExporter ) getLogger(__name__).error("hello") - self.assertTrue(provider.processor.exporter.export_called) + self.assertFalse(provider.processor.exporter.export_called) root_logger = getLogger() - handler_present = False + self.assertEqual(root_logger.level, WARNING) for handler in root_logger.handlers: if isinstance(handler, LoggingHandler): - handler_present = True - self.assertEqual(handler.level, 39) - self.assertTrue(handler_present) + self.fail() @patch.dict( environ, @@ -723,8 +719,8 @@ def test_logging_init_exporter_level_under(self, log_level_mock): }, clear=True, ) - @patch("opentelemetry.sdk._configuration._get_log_level", return_value=41) - def test_logging_init_exporter_level_over(self, log_level_mock): + @patch("opentelemetry.sdk._configuration._get_log_level", return_value=39) + def test_logging_init_exporter_level_under(self, log_level_mock): resource = Resource.create({}) _init_logging( {"otlp": DummyOTLPLogExporter}, @@ -743,23 +739,25 @@ def test_logging_init_exporter_level_over(self, log_level_mock): provider.processor.exporter, DummyOTLPLogExporter ) getLogger(__name__).error("hello") - self.assertFalse(provider.processor.exporter.export_called) + self.assertTrue(provider.processor.exporter.export_called) root_logger = getLogger() handler_present = False for handler in root_logger.handlers: if isinstance(handler, LoggingHandler): handler_present = True - self.assertEqual(handler.level, 41) + self.assertEqual(handler.level, 39) self.assertTrue(handler_present) @patch.dict( environ, { "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", - "OTEL_PYTHON_LOG_FORMAT": CUSTOM_LOG_FORMAT, + "OTEL_PYTHON_LOG_LEVEL": "CUSTOM_LOG_LEVEL", }, + clear=True, ) - def test_logging_init_exporter_format(self): + @patch("opentelemetry.sdk._configuration._get_log_level", return_value=41) + def test_logging_init_exporter_level_over(self, log_level_mock): resource = Resource.create({}) _init_logging( {"otlp": DummyOTLPLogExporter}, @@ -778,28 +776,27 @@ def test_logging_init_exporter_format(self): provider.processor.exporter, DummyOTLPLogExporter ) getLogger(__name__).error("hello") - self.assertTrue(provider.processor.exporter.export_called) + self.assertFalse(provider.processor.exporter.export_called) root_logger = getLogger() - self.assertEqual(root_logger.level, WARNING) handler_present = False for handler in root_logger.handlers: if isinstance(handler, LoggingHandler): - self.assertEqual(handler.formatter._fmt, CUSTOM_LOG_FORMAT) handler_present = True + self.assertEqual(handler.level, 41) self.assertTrue(handler_present) @patch.dict( environ, { "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", + "OTEL_PYTHON_LOG_FORMAT": CUSTOM_LOG_FORMAT, }, ) - def test_logging_init_exporter_without_handler_setup(self): + def test_logging_init_exporter_format(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] @@ -814,12 +811,15 @@ def test_logging_init_exporter_without_handler_setup(self): provider.processor.exporter, DummyOTLPLogExporter ) getLogger(__name__).error("hello") - self.assertFalse(provider.processor.exporter.export_called) + self.assertTrue(provider.processor.exporter.export_called) root_logger = getLogger() self.assertEqual(root_logger.level, WARNING) + handler_present = False for handler in root_logger.handlers: if isinstance(handler, LoggingHandler): - self.fail() + self.assertEqual(handler.formatter._fmt, CUSTOM_LOG_FORMAT) + handler_present = True + self.assertTrue(handler_present) @patch.dict(environ, {}, clear=True) def test_OTEL_PYTHON_LOG_LEVEL_by_name_default(self): From 8f9797a8650115e4bd1e0c1d86dd11220cbf81f2 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Mon, 12 May 2025 15:09:40 -0700 Subject: [PATCH 03/11] tests pass --- opentelemetry-sdk/tests/test_configurator.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index ec0050e5d41..47228b7ae09 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -680,9 +680,7 @@ def test_logging_init_exporter(self): @patch.dict( environ, - { - "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", - }, + {"OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service"}, ) def test_logging_init_exporter_without_handler_setup(self): resource = Resource.create({}) @@ -706,7 +704,6 @@ def test_logging_init_exporter_without_handler_setup(self): getLogger(__name__).error("hello") self.assertFalse(provider.processor.exporter.export_called) root_logger = getLogger() - self.assertEqual(root_logger.level, WARNING) for handler in root_logger.handlers: if isinstance(handler, LoggingHandler): self.fail() @@ -813,7 +810,6 @@ def test_logging_init_exporter_format(self): getLogger(__name__).error("hello") self.assertTrue(provider.processor.exporter.export_called) root_logger = getLogger() - self.assertEqual(root_logger.level, WARNING) handler_present = False for handler in root_logger.handlers: if isinstance(handler, LoggingHandler): From bb8884a5bfa02a9fa7055c4ae25e67cc147e5a89 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Mon, 12 May 2025 15:24:22 -0700 Subject: [PATCH 04/11] Reorg tests added for past PR: https://github.com/open-telemetry/opentelemetry-python/pull/4340 --- opentelemetry-sdk/tests/test_configurator.py | 108 +++++++++---------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 47228b7ae09..068268b80f2 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -998,60 +998,6 @@ def test_initialize_components_kwargs( "TEST_RESOURCE", True, ) - - def test_basicConfig_works_with_otel_handler(self): - with ClearLoggingHandlers(): - _init_logging( - {"otlp": DummyOTLPLogExporter}, - Resource.create({}), - setup_logging_handler=True, - ) - - logging.basicConfig(level=logging.INFO) - - root_logger = logging.getLogger() - stream_handlers = [ - h - for h in root_logger.handlers - if isinstance(h, logging.StreamHandler) - ] - self.assertEqual( - len(stream_handlers), - 1, - "basicConfig should add a StreamHandler even when OTel handler exists", - ) - - def test_basicConfig_preserves_otel_handler(self): - with ClearLoggingHandlers(): - _init_logging( - {"otlp": DummyOTLPLogExporter}, - Resource.create({}), - setup_logging_handler=True, - ) - - root_logger = logging.getLogger() - self.assertEqual( - len(root_logger.handlers), - 1, - "Should be exactly one OpenTelemetry LoggingHandler", - ) - handler = root_logger.handlers[0] - self.assertIsInstance(handler, LoggingHandler) - - logging.basicConfig() - - self.assertGreater(len(root_logger.handlers), 1) - - logging_handlers = [ - h - for h in root_logger.handlers - if isinstance(h, LoggingHandler) - ] - self.assertEqual( - len(logging_handlers), - 1, - "Should still have exactly one OpenTelemetry LoggingHandler", - ) @patch.dict( environ, @@ -1148,6 +1094,60 @@ def test_initialize_components_kwargs_disable_logging_handler( False, ) + def test_basicConfig_works_with_otel_handler(self): + with ClearLoggingHandlers(): + _init_logging( + {"otlp": DummyOTLPLogExporter}, + Resource.create({}), + setup_logging_handler=True, + ) + + logging.basicConfig(level=logging.INFO) + + root_logger = logging.getLogger() + stream_handlers = [ + h + for h in root_logger.handlers + if isinstance(h, logging.StreamHandler) + ] + self.assertEqual( + len(stream_handlers), + 1, + "basicConfig should add a StreamHandler even when OTel handler exists", + ) + + def test_basicConfig_preserves_otel_handler(self): + with ClearLoggingHandlers(): + _init_logging( + {"otlp": DummyOTLPLogExporter}, + Resource.create({}), + setup_logging_handler=True, + ) + + root_logger = logging.getLogger() + self.assertEqual( + len(root_logger.handlers), + 1, + "Should be exactly one OpenTelemetry LoggingHandler", + ) + handler = root_logger.handlers[0] + self.assertIsInstance(handler, LoggingHandler) + + logging.basicConfig() + + self.assertGreater(len(root_logger.handlers), 1) + + logging_handlers = [ + h + for h in root_logger.handlers + if isinstance(h, LoggingHandler) + ] + self.assertEqual( + len(logging_handlers), + 1, + "Should still have exactly one OpenTelemetry LoggingHandler", + ) + class TestMetricsInit(TestCase): def setUp(self): From f48b79948934c56bb62114c38b526107d2b44e55 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Mon, 12 May 2025 15:45:29 -0700 Subject: [PATCH 05/11] lint --- .../src/opentelemetry/sdk/_configuration/__init__.py | 4 ++-- opentelemetry-sdk/tests/test_configurator.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index da2f665fde0..fdc058123df 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -45,10 +45,10 @@ OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, - OTEL_TRACES_SAMPLER, - OTEL_TRACES_SAMPLER_ARG, OTEL_PYTHON_LOG_LEVEL, OTEL_PYTHON_LOG_FORMAT, + OTEL_TRACES_SAMPLER, + OTEL_TRACES_SAMPLER_ARG, ) from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.metrics.export import ( diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 068268b80f2..b0fd84dc8bf 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -998,7 +998,7 @@ def test_initialize_components_kwargs( "TEST_RESOURCE", True, ) - + @patch.dict( environ, { From 5044a80493203395d05d02010691aaae68ab2acc Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Mon, 12 May 2025 15:48:51 -0700 Subject: [PATCH 06/11] lint --- .../opentelemetry/sdk/_configuration/__init__.py | 16 ++++++++++------ opentelemetry-sdk/tests/test_configurator.py | 1 - 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index fdc058123df..51262ba2fec 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -45,8 +45,8 @@ OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, - OTEL_PYTHON_LOG_LEVEL, OTEL_PYTHON_LOG_FORMAT, + OTEL_PYTHON_LOG_LEVEL, OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG, ) @@ -143,8 +143,12 @@ def _get_sampler() -> str | None: def _get_id_generator() -> str: return environ.get(OTEL_PYTHON_ID_GENERATOR, _DEFAULT_ID_GENERATOR) + def _get_log_level() -> int: - return _OTEL_PYTHON_LOG_LEVEL_BY_NAME.get(environ.get(OTEL_PYTHON_LOG_LEVEL, "notset").lower().strip(), logging.NOTSET) + return _OTEL_PYTHON_LOG_LEVEL_BY_NAME.get( + environ.get(OTEL_PYTHON_LOG_LEVEL, "notset").lower().strip(), + logging.NOTSET, + ) def _get_exporter_entry_point( @@ -271,15 +275,15 @@ def _init_logging( # Log Handler root_logger = logging.getLogger() - handler = LoggingHandler( - logger_provider=provider - ) + handler = LoggingHandler(logger_provider=provider) # Log level if OTEL_PYTHON_LOG_LEVEL in environ: handler.setLevel(_get_log_level()) # Log format if OTEL_PYTHON_LOG_FORMAT in environ: - log_format = environ.get(OTEL_PYTHON_LOG_FORMAT, logging.BASIC_FORMAT) + log_format = environ.get( + OTEL_PYTHON_LOG_FORMAT, logging.BASIC_FORMAT + ) handler.setFormatter(logging.Formatter(log_format)) root_logger.addHandler(handler) diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index b0fd84dc8bf..08c78aab68c 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -83,7 +83,6 @@ from opentelemetry.trace.span import TraceState from opentelemetry.util.types import Attributes - CUSTOM_LOG_FORMAT = "CUSTOM FORMAT %(levelname)s:%(name)s:%(message)s" From 190d035a0f56962d2bd7a01a1e12dbc840d72482 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Tue, 13 May 2025 12:19:13 -0700 Subject: [PATCH 07/11] Fix tests on python 3.8 --- opentelemetry-sdk/tests/test_configurator.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 08c78aab68c..a798bc3faa2 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -620,6 +620,8 @@ def setUp(self): self.set_event_logger_provider_patch.start() ) + getLogger().handlers.clear() + def tearDown(self): self.processor_patch.stop() self.set_provider_patch.stop() From 293c62c09ba3449056588d939826e9aec9bfcbb3 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Wed, 14 May 2025 10:16:50 -0700 Subject: [PATCH 08/11] OTEL_PYTHON_LOG_HANDLER_LOG_LEVEL --- .../sdk/_configuration/__init__.py | 10 +++--- .../sdk/environment_variables/__init__.py | 6 ++-- opentelemetry-sdk/tests/test_configurator.py | 34 +++++++++---------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 51262ba2fec..9976c48fc14 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -46,7 +46,7 @@ OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, OTEL_PYTHON_LOG_FORMAT, - OTEL_PYTHON_LOG_LEVEL, + OTEL_PYTHON_LOG_HANDLER_LEVEL, OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG, ) @@ -91,7 +91,7 @@ _OTEL_SAMPLER_ENTRY_POINT_GROUP = "opentelemetry_traces_sampler" -_OTEL_PYTHON_LOG_LEVEL_BY_NAME = { +_OTEL_PYTHON_LOG_HANDLER_LEVEL_BY_NAME = { "notset": logging.NOTSET, "debug": logging.DEBUG, "info": logging.INFO, @@ -145,8 +145,8 @@ def _get_id_generator() -> str: def _get_log_level() -> int: - return _OTEL_PYTHON_LOG_LEVEL_BY_NAME.get( - environ.get(OTEL_PYTHON_LOG_LEVEL, "notset").lower().strip(), + return _OTEL_PYTHON_LOG_HANDLER_LEVEL_BY_NAME.get( + environ.get(OTEL_PYTHON_LOG_HANDLER_LEVEL, "notset").lower().strip(), logging.NOTSET, ) @@ -277,7 +277,7 @@ def _init_logging( root_logger = logging.getLogger() handler = LoggingHandler(logger_provider=provider) # Log level - if OTEL_PYTHON_LOG_LEVEL in environ: + if OTEL_PYTHON_LOG_HANDLER_LEVEL in environ: handler.setLevel(_get_log_level()) # Log format if OTEL_PYTHON_LOG_FORMAT in environ: diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py index ab88b8d1bf8..bc7e2b6da9a 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py @@ -62,11 +62,11 @@ Default: "logging.BASIC_FORMAT" """ -OTEL_PYTHON_LOG_LEVEL = "OTEL_PYTHON_LOG_LEVEL" +OTEL_PYTHON_LOG_HANDLER_LEVEL = "OTEL_PYTHON_LOG_HANDLER_LEVEL" """ -.. envvar:: OTEL_PYTHON_LOG_LEVEL +.. envvar:: OTEL_PYTHON_LOG_HANDLER_LEVEL -The :envvar:`OTEL_PYTHON_LOG_LEVEL` environment variable sets the log level for the OpenTelemetry LoggingHandler +The :envvar:`OTEL_PYTHON_LOG_HANDLER_LEVEL` environment variable sets the log level for the OpenTelemetry LoggingHandler Default: "logging.NOTSET" """ diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index a798bc3faa2..bbe5a876476 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -713,7 +713,7 @@ def test_logging_init_exporter_without_handler_setup(self): environ, { "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", - "OTEL_PYTHON_LOG_LEVEL": "CUSTOM_LOG_LEVEL", + "OTEL_PYTHON_LOG_HANDLER_LEVEL": "CUSTOM_LOG_LEVEL", }, clear=True, ) @@ -750,7 +750,7 @@ def test_logging_init_exporter_level_under(self, log_level_mock): environ, { "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", - "OTEL_PYTHON_LOG_LEVEL": "CUSTOM_LOG_LEVEL", + "OTEL_PYTHON_LOG_HANDLER_LEVEL": "CUSTOM_LOG_LEVEL", }, clear=True, ) @@ -819,35 +819,35 @@ def test_logging_init_exporter_format(self): self.assertTrue(handler_present) @patch.dict(environ, {}, clear=True) - def test_OTEL_PYTHON_LOG_LEVEL_by_name_default(self): + def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_default(self): self.assertEqual(_get_log_level(), NOTSET) - @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": "NOTSET "}, clear=True) - def test_OTEL_PYTHON_LOG_LEVEL_by_name_notset(self): + @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": "NOTSET "}, clear=True) + def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_notset(self): self.assertEqual(_get_log_level(), NOTSET) - @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " DeBug "}, clear=True) - def test_OTEL_PYTHON_LOG_LEVEL_by_name_debug(self): + @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " DeBug "}, clear=True) + def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_debug(self): self.assertEqual(_get_log_level(), DEBUG) - @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " info "}, clear=True) - def test_OTEL_PYTHON_LOG_LEVEL_by_name_info(self): + @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " info "}, clear=True) + def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_info(self): self.assertEqual(_get_log_level(), INFO) - @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " warn"}, clear=True) - def test_OTEL_PYTHON_LOG_LEVEL_by_name_warn(self): + @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " warn"}, clear=True) + def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_warn(self): self.assertEqual(_get_log_level(), WARNING) - @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " warnING "}, clear=True) - def test_OTEL_PYTHON_LOG_LEVEL_by_name_warning(self): + @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " warnING "}, clear=True) + def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_warning(self): self.assertEqual(_get_log_level(), WARNING) - @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " eRroR"}, clear=True) - def test_OTEL_PYTHON_LOG_LEVEL_by_name_error(self): + @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " eRroR"}, clear=True) + def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_error(self): self.assertEqual(_get_log_level(), ERROR) - @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": "foobar"}, clear=True) - def test_OTEL_PYTHON_LOG_LEVEL_by_name_invalid(self): + @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": "foobar"}, clear=True) + def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_invalid(self): self.assertEqual(_get_log_level(), NOTSET) @patch.dict( From be2111f2e777f1ef6329bf27967fa28960be7d1d Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Wed, 14 May 2025 10:27:14 -0700 Subject: [PATCH 09/11] clean up test names --- opentelemetry-sdk/tests/test_configurator.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index bbe5a876476..4c323e443f8 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -819,35 +819,35 @@ def test_logging_init_exporter_format(self): self.assertTrue(handler_present) @patch.dict(environ, {}, clear=True) - def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_default(self): + def test_otel_log_level_by_name_default(self): self.assertEqual(_get_log_level(), NOTSET) @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": "NOTSET "}, clear=True) - def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_notset(self): + def test_otel_log_level_by_name_notset(self): self.assertEqual(_get_log_level(), NOTSET) @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " DeBug "}, clear=True) - def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_debug(self): + def test_otel_log_level_by_name_debug(self): self.assertEqual(_get_log_level(), DEBUG) @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " info "}, clear=True) - def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_info(self): + def test_otel_log_level_by_name_info(self): self.assertEqual(_get_log_level(), INFO) @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " warn"}, clear=True) - def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_warn(self): + def test_otel_log_level_by_name_warn(self): self.assertEqual(_get_log_level(), WARNING) @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " warnING "}, clear=True) - def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_warning(self): + def test_otel_log_level_by_name_warning(self): self.assertEqual(_get_log_level(), WARNING) @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " eRroR"}, clear=True) - def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_error(self): + def test_otel_log_level_by_name_error(self): self.assertEqual(_get_log_level(), ERROR) @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": "foobar"}, clear=True) - def test_OTEL_PYTHON_LOG_HANDLER_LEVEL_by_name_invalid(self): + def test_otel_log_level_by_name_invalid(self): self.assertEqual(_get_log_level(), NOTSET) @patch.dict( From c5dcf467413aff22f6d88c5e20dd282438164e55 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Wed, 14 May 2025 10:30:00 -0700 Subject: [PATCH 10/11] lint --- opentelemetry-sdk/tests/test_configurator.py | 28 +++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index 4c323e443f8..ba4c6aa6d1b 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -822,31 +822,45 @@ def test_logging_init_exporter_format(self): def test_otel_log_level_by_name_default(self): self.assertEqual(_get_log_level(), NOTSET) - @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": "NOTSET "}, clear=True) + @patch.dict( + environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": "NOTSET "}, clear=True + ) def test_otel_log_level_by_name_notset(self): self.assertEqual(_get_log_level(), NOTSET) - @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " DeBug "}, clear=True) + @patch.dict( + environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " DeBug "}, clear=True + ) def test_otel_log_level_by_name_debug(self): self.assertEqual(_get_log_level(), DEBUG) - @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " info "}, clear=True) + @patch.dict( + environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " info "}, clear=True + ) def test_otel_log_level_by_name_info(self): self.assertEqual(_get_log_level(), INFO) - @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " warn"}, clear=True) + @patch.dict( + environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " warn"}, clear=True + ) def test_otel_log_level_by_name_warn(self): self.assertEqual(_get_log_level(), WARNING) - @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " warnING "}, clear=True) + @patch.dict( + environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " warnING "}, clear=True + ) def test_otel_log_level_by_name_warning(self): self.assertEqual(_get_log_level(), WARNING) - @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " eRroR"}, clear=True) + @patch.dict( + environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " eRroR"}, clear=True + ) def test_otel_log_level_by_name_error(self): self.assertEqual(_get_log_level(), ERROR) - @patch.dict(environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": "foobar"}, clear=True) + @patch.dict( + environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": "foobar"}, clear=True + ) def test_otel_log_level_by_name_invalid(self): self.assertEqual(_get_log_level(), NOTSET) From 1753970fbd243197a18ea4f180b6ca1817c3b7d3 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Wed, 14 May 2025 10:52:35 -0700 Subject: [PATCH 11/11] OTEL_PYTHON_LOG_LEVEL --- .../sdk/_configuration/__init__.py | 10 +++--- .../sdk/environment_variables/__init__.py | 6 ++-- opentelemetry-sdk/tests/test_configurator.py | 32 ++++++------------- 3 files changed, 17 insertions(+), 31 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py index 9976c48fc14..51262ba2fec 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py @@ -46,7 +46,7 @@ OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, OTEL_PYTHON_LOG_FORMAT, - OTEL_PYTHON_LOG_HANDLER_LEVEL, + OTEL_PYTHON_LOG_LEVEL, OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG, ) @@ -91,7 +91,7 @@ _OTEL_SAMPLER_ENTRY_POINT_GROUP = "opentelemetry_traces_sampler" -_OTEL_PYTHON_LOG_HANDLER_LEVEL_BY_NAME = { +_OTEL_PYTHON_LOG_LEVEL_BY_NAME = { "notset": logging.NOTSET, "debug": logging.DEBUG, "info": logging.INFO, @@ -145,8 +145,8 @@ def _get_id_generator() -> str: def _get_log_level() -> int: - return _OTEL_PYTHON_LOG_HANDLER_LEVEL_BY_NAME.get( - environ.get(OTEL_PYTHON_LOG_HANDLER_LEVEL, "notset").lower().strip(), + return _OTEL_PYTHON_LOG_LEVEL_BY_NAME.get( + environ.get(OTEL_PYTHON_LOG_LEVEL, "notset").lower().strip(), logging.NOTSET, ) @@ -277,7 +277,7 @@ def _init_logging( root_logger = logging.getLogger() handler = LoggingHandler(logger_provider=provider) # Log level - if OTEL_PYTHON_LOG_HANDLER_LEVEL in environ: + if OTEL_PYTHON_LOG_LEVEL in environ: handler.setLevel(_get_log_level()) # Log format if OTEL_PYTHON_LOG_FORMAT in environ: diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py index bc7e2b6da9a..ab88b8d1bf8 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py @@ -62,11 +62,11 @@ Default: "logging.BASIC_FORMAT" """ -OTEL_PYTHON_LOG_HANDLER_LEVEL = "OTEL_PYTHON_LOG_HANDLER_LEVEL" +OTEL_PYTHON_LOG_LEVEL = "OTEL_PYTHON_LOG_LEVEL" """ -.. envvar:: OTEL_PYTHON_LOG_HANDLER_LEVEL +.. envvar:: OTEL_PYTHON_LOG_LEVEL -The :envvar:`OTEL_PYTHON_LOG_HANDLER_LEVEL` environment variable sets the log level for the OpenTelemetry LoggingHandler +The :envvar:`OTEL_PYTHON_LOG_LEVEL` environment variable sets the log level for the OpenTelemetry LoggingHandler Default: "logging.NOTSET" """ diff --git a/opentelemetry-sdk/tests/test_configurator.py b/opentelemetry-sdk/tests/test_configurator.py index ba4c6aa6d1b..05e033c2d97 100644 --- a/opentelemetry-sdk/tests/test_configurator.py +++ b/opentelemetry-sdk/tests/test_configurator.py @@ -713,7 +713,7 @@ def test_logging_init_exporter_without_handler_setup(self): environ, { "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", - "OTEL_PYTHON_LOG_HANDLER_LEVEL": "CUSTOM_LOG_LEVEL", + "OTEL_PYTHON_LOG_LEVEL": "CUSTOM_LOG_LEVEL", }, clear=True, ) @@ -750,7 +750,7 @@ def test_logging_init_exporter_level_under(self, log_level_mock): environ, { "OTEL_RESOURCE_ATTRIBUTES": "service.name=otlp-service", - "OTEL_PYTHON_LOG_HANDLER_LEVEL": "CUSTOM_LOG_LEVEL", + "OTEL_PYTHON_LOG_LEVEL": "CUSTOM_LOG_LEVEL", }, clear=True, ) @@ -822,45 +822,31 @@ def test_logging_init_exporter_format(self): def test_otel_log_level_by_name_default(self): self.assertEqual(_get_log_level(), NOTSET) - @patch.dict( - environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": "NOTSET "}, clear=True - ) + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": "NOTSET "}, clear=True) def test_otel_log_level_by_name_notset(self): self.assertEqual(_get_log_level(), NOTSET) - @patch.dict( - environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " DeBug "}, clear=True - ) + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " DeBug "}, clear=True) def test_otel_log_level_by_name_debug(self): self.assertEqual(_get_log_level(), DEBUG) - @patch.dict( - environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " info "}, clear=True - ) + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " info "}, clear=True) def test_otel_log_level_by_name_info(self): self.assertEqual(_get_log_level(), INFO) - @patch.dict( - environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " warn"}, clear=True - ) + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " warn"}, clear=True) def test_otel_log_level_by_name_warn(self): self.assertEqual(_get_log_level(), WARNING) - @patch.dict( - environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " warnING "}, clear=True - ) + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " warnING "}, clear=True) def test_otel_log_level_by_name_warning(self): self.assertEqual(_get_log_level(), WARNING) - @patch.dict( - environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": " eRroR"}, clear=True - ) + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": " eRroR"}, clear=True) def test_otel_log_level_by_name_error(self): self.assertEqual(_get_log_level(), ERROR) - @patch.dict( - environ, {"OTEL_PYTHON_LOG_HANDLER_LEVEL": "foobar"}, clear=True - ) + @patch.dict(environ, {"OTEL_PYTHON_LOG_LEVEL": "foobar"}, clear=True) def test_otel_log_level_by_name_invalid(self): self.assertEqual(_get_log_level(), NOTSET)