Skip to content

Commit ac410be

Browse files
lzchenl0lawrence
authored andcommitted
Add OpenTelemetry LoggingHandler conditionally (Azure#38549)
1 parent c991345 commit ac410be

File tree

4 files changed

+69
-8
lines changed

4 files changed

+69
-8
lines changed

sdk/monitor/azure-monitor-opentelemetry/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Features Added
66

7+
- Only add OpenTelemetry LoggingHandler if current logger does not have it
8+
([#38549](https://github.com/Azure/azure-sdk-for-python/pull/38549))
79
- Distro to automatically configure event logger provider
810
([#38543](https://github.com/Azure/azure-sdk-for-python/pull/38543))
911

sdk/monitor/azure-monitor-opentelemetry/azure/monitor/opentelemetry/_configure.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,13 @@ def _setup_logging(configurations: Dict[str, ConfigurationValue]):
170170
)
171171
logger_provider.add_log_record_processor(log_record_processor)
172172
set_logger_provider(logger_provider)
173-
handler = LoggingHandler(logger_provider=logger_provider)
174173
logger_name: str = configurations[LOGGER_NAME_ARG] # type: ignore
175-
getLogger(logger_name).addHandler(handler)
174+
logger = getLogger(logger_name)
175+
# Only add OpenTelemetry LoggingHandler if logger does not already have the handler
176+
# This is to prevent most duplicate logging telemetry
177+
if not any(isinstance(handler, LoggingHandler) for handler in logger.handlers):
178+
handler = LoggingHandler(logger_provider=logger_provider)
179+
logger.addHandler(handler)
176180

177181
# Setup EventLoggerProvider
178182
event_provider = EventLoggerProvider(logger_provider)

sdk/monitor/azure-monitor-opentelemetry/samples/logging/basic.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@
2929
logger.warning("warning log")
3030
logger.error("error log")
3131

32-
logger.info("info log")
33-
logger.warning("warning log")
34-
logger.error("error log")
32+
logger_child.info("Child: info log")
33+
logger_child.warning("Child: warning log")
34+
logger_child.error("Child: error log")
3535

36-
logger_not_tracked.info("info log2")
37-
logger_not_tracked.warning("warning log2")
38-
logger_not_tracked.error("error log2")
36+
logger_not_tracked.info("Not tracked: info log")
37+
logger_not_tracked.warning("Not tracked: warning log")
38+
logger_not_tracked.error("Not tracked: error log")
3939

4040
input()

sdk/monitor/azure-monitor-opentelemetry/tests/test_configure.py

+55
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import unittest
1515
from unittest.mock import Mock, call, patch
1616

17+
from opentelemetry.sdk._logs import LoggingHandler
1718
from opentelemetry.sdk.resources import Resource
1819

1920
from azure.core.tracing.ext.opentelemetry_span import OpenTelemetrySpan
@@ -351,6 +352,7 @@ def test_setup_logging(
351352
logging_handler_init_mock = Mock()
352353
logging_handler_mock.return_value = logging_handler_init_mock
353354
logger_mock = Mock()
355+
logger_mock.handlers = []
354356
get_logger_mock.return_value = logger_mock
355357

356358
configurations = {
@@ -373,6 +375,59 @@ def test_setup_logging(
373375
elp_mock.assert_called_once_with(lp_init_mock)
374376
set_elp_mock.assert_called_once_with(elp_init_mock)
375377

378+
@patch(
379+
"azure.monitor.opentelemetry._configure.getLogger",
380+
)
381+
@patch(
382+
"azure.monitor.opentelemetry._configure.BatchLogRecordProcessor",
383+
)
384+
@patch(
385+
"azure.monitor.opentelemetry._configure.AzureMonitorLogExporter",
386+
)
387+
@patch(
388+
"azure.monitor.opentelemetry._configure.set_logger_provider",
389+
)
390+
@patch(
391+
"azure.monitor.opentelemetry._configure.LoggerProvider",
392+
autospec=True,
393+
)
394+
def test_setup_logging_duplicate_logger(
395+
self,
396+
lp_mock,
397+
set_logger_provider_mock,
398+
log_exporter_mock,
399+
blrp_mock,
400+
get_logger_mock,
401+
):
402+
lp_init_mock = Mock()
403+
lp_mock.return_value = lp_init_mock
404+
log_exp_init_mock = Mock()
405+
log_exporter_mock.return_value = log_exp_init_mock
406+
blrp_init_mock = Mock()
407+
blrp_mock.return_value = blrp_init_mock
408+
logging_handler_init_mock = Mock(spec=LoggingHandler)
409+
logger_mock = Mock()
410+
logger_mock.handlers = [logging_handler_init_mock]
411+
get_logger_mock.return_value = logger_mock
412+
413+
configurations = {
414+
"connection_string": "test_cs",
415+
"logger_name": "test",
416+
"resource": TEST_RESOURCE,
417+
}
418+
_setup_logging(configurations)
419+
420+
lp_mock.assert_called_once_with(resource=TEST_RESOURCE)
421+
set_logger_provider_mock.assert_called_once_with(lp_init_mock)
422+
log_exporter_mock.assert_called_once_with(**configurations)
423+
blrp_mock.assert_called_once_with(
424+
log_exp_init_mock,
425+
)
426+
lp_init_mock.add_log_record_processor.assert_called_once_with(blrp_init_mock)
427+
# logging_handler_mock.assert_not_called()
428+
get_logger_mock.assert_called_once_with("test")
429+
logger_mock.addHandler.assert_not_called()
430+
376431
@patch(
377432
"azure.monitor.opentelemetry._configure.PeriodicExportingMetricReader",
378433
)

0 commit comments

Comments
 (0)