Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logging_format configuration option in api #40057

Merged
merged 9 commits into from
Mar 26, 2025
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
# license information.
# --------------------------------------------------------------------------
from functools import cached_property
from logging import getLogger
from logging import getLogger, Formatter
from typing import Dict, List, cast

from opentelemetry._events import _set_event_logger_provider
@@ -42,6 +42,7 @@
DISABLE_TRACING_ARG,
ENABLE_LIVE_METRICS_ARG,
LOGGER_NAME_ARG,
LOGGING_FORMAT_ARG,
RESOURCE_ARG,
SAMPLING_RATIO_ARG,
SPAN_PROCESSORS_ARG,
@@ -172,11 +173,23 @@ def _setup_logging(configurations: Dict[str, ConfigurationValue]):
logger_provider.add_log_record_processor(log_record_processor)
set_logger_provider(logger_provider)
logger_name: str = configurations[LOGGER_NAME_ARG] # type: ignore
logging_format: str = configurations[LOGGING_FORMAT_ARG] # type: ignore
logger = getLogger(logger_name)
# Only add OpenTelemetry LoggingHandler if logger does not already have the handler
# This is to prevent most duplicate logging telemetry
if not any(isinstance(handler, LoggingHandler) for handler in logger.handlers):
handler = LoggingHandler(logger_provider=logger_provider)
if logging_format:
formatter = None
try:
formatter = Formatter(logging_format)
except Exception as ex:
_logger.warning(
"Exception occurred when constructing logging Formatter: %s.",
ex,
)
if formatter:
handler.setFormatter(formatter)
logger.addHandler(handler)

# Setup EventLoggerProvider
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
DISABLE_TRACING_ARG = "disable_tracing"
DISTRO_VERSION_ARG = _AZURE_MONITOR_DISTRO_VERSION_ARG
LOGGER_NAME_ARG = "logger_name"
LOGGING_FORMAT_ARG = "logging_format"
INSTRUMENTATION_OPTIONS_ARG = "instrumentation_options"
RESOURCE_ARG = "resource"
SAMPLING_RATIO_ARG = "sampling_ratio"
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@
ENABLE_LIVE_METRICS_ARG,
INSTRUMENTATION_OPTIONS_ARG,
LOGGER_NAME_ARG,
LOGGING_FORMAT_ARG,
RESOURCE_ARG,
SAMPLING_RATIO_ARG,
SPAN_PROCESSORS_ARG,
@@ -66,6 +67,7 @@ def _get_configurations(**kwargs) -> Dict[str, ConfigurationValue]:
_default_disable_metrics(configurations)
_default_disable_tracing(configurations)
_default_logger_name(configurations)
_default_logging_format(configurations)
_default_resource(configurations)
_default_sampling_ratio(configurations)
_default_instrumentation_options(configurations)
@@ -104,6 +106,10 @@ def _default_logger_name(configurations):
configurations.setdefault(LOGGER_NAME_ARG, "")


def _default_logging_format(configurations):
configurations.setdefault(LOGGING_FORMAT_ARG, "")


def _default_resource(configurations):
environ.setdefault(OTEL_EXPERIMENTAL_RESOURCE_DETECTORS, ",".join(_SUPPORTED_RESOURCE_DETECTORS))
if RESOURCE_ARG not in configurations:
Original file line number Diff line number Diff line change
@@ -8,22 +8,29 @@

from azure.monitor.opentelemetry import configure_azure_monitor

# logging.basicConfig and logging.config will be overwritten by the SDK
# We recommend using logger specific configuration or the below apis to configure logging

configure_azure_monitor(
# Set logger_name to the name of the logger you want to capture logging telemetry with
# This is imperative so you do not collect logging telemetry from the SDK itself.
logger_name="my_application_logger",
logger_name="my_app_logger",
# You can specify the logging format of your collected logs
logging_format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)

# formatter = Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# Logging telemetry will be collected from logging calls made with this logger and all of it's children loggers.
logger = getLogger("my_application_logger")
logger = getLogger("my_app_logger")
logger.setLevel(INFO)

# Logging calls with any logger that is a child logger will also be tracked
logger_child = getLogger("my-application_logger.module")
logger_child = getLogger("my_app_logger.module")
logger_child.setLevel(INFO)

# Logging calls with this logger will not be tracked
logger_not_tracked = getLogger("not_my_application_logger")
logger_not_tracked = getLogger("not_my_app_logger")
logger_not_tracked.setLevel(INFO)

logger.info("info log")
29 changes: 29 additions & 0 deletions sdk/monitor/azure-monitor-opentelemetry/tests/test_configure.py
Original file line number Diff line number Diff line change
@@ -311,6 +311,9 @@ def test_setup_tracing(
"azure.monitor.opentelemetry._configure.EventLoggerProvider",
autospec=True,
)
@patch(
"azure.monitor.opentelemetry._configure.Formatter",
)
@patch(
"azure.monitor.opentelemetry._configure.getLogger",
)
@@ -338,6 +341,7 @@ def test_setup_logging(
blrp_mock,
logging_handler_mock,
get_logger_mock,
formatter_mock,
elp_mock,
set_elp_mock,
):
@@ -354,11 +358,14 @@ def test_setup_logging(
logger_mock = Mock()
logger_mock.handlers = []
get_logger_mock.return_value = logger_mock
formatter_init_mock = Mock()
formatter_mock.return_value = formatter_init_mock

configurations = {
"connection_string": "test_cs",
"logger_name": "test",
"resource": TEST_RESOURCE,
"logging_format": "test_format"
}
_setup_logging(configurations)

@@ -370,6 +377,7 @@ def test_setup_logging(
)
lp_init_mock.add_log_record_processor.assert_called_once_with(blrp_init_mock)
logging_handler_mock.assert_called_once_with(logger_provider=lp_init_mock)
logging_handler_init_mock.setFormatter.assert_called_once_with(formatter_init_mock)
get_logger_mock.assert_called_once_with("test")
logger_mock.addHandler.assert_called_once_with(logging_handler_init_mock)
elp_mock.assert_called_once_with(lp_init_mock)
@@ -414,6 +422,7 @@ def test_setup_logging_duplicate_logger(
"connection_string": "test_cs",
"logger_name": "test",
"resource": TEST_RESOURCE,
"logging_format": ""
}
_setup_logging(configurations)

@@ -660,26 +669,46 @@ def test_setup_instrumentations_disabled(
logger_mock.debug.assert_called_once()

@patch("azure.monitor.opentelemetry._configure.AzureDiagnosticLogging")
@patch("azure.monitor.opentelemetry._configure._is_on_functions")
@patch("azure.monitor.opentelemetry._configure._is_attach_enabled")
def test_send_attach_warning_true(
self,
is_attach_enabled_mock,
is_on_functions_mock,
mock_diagnostics,
):
is_attach_enabled_mock.return_value = True
is_on_functions_mock.return_value = False
_send_attach_warning()
mock_diagnostics.warning.assert_called_once_with(
"Distro detected that automatic attach may have occurred. Check your data to ensure that telemetry is not being duplicated. This may impact your cost.",
_DISTRO_DETECTS_ATTACH,
)

@patch("azure.monitor.opentelemetry._configure.AzureDiagnosticLogging")
@patch("azure.monitor.opentelemetry._configure._is_on_functions")
@patch("azure.monitor.opentelemetry._configure._is_attach_enabled")
def test_send_attach_warning_false(
self,
is_attach_enabled_mock,
is_on_functions_mock,
mock_diagnostics,
):
is_attach_enabled_mock.return_value = False
is_on_functions_mock.return_value = False
_send_attach_warning()
mock_diagnostics.warning.assert_not_called()

@patch("azure.monitor.opentelemetry._configure.AzureDiagnosticLogging")
@patch("azure.monitor.opentelemetry._configure._is_on_functions")
@patch("azure.monitor.opentelemetry._configure._is_attach_enabled")
def test_send_attach_warning_false_on_functions(
self,
is_attach_enabled_mock,
is_on_functions_mock,
mock_diagnostics,
):
is_attach_enabled_mock.return_value = True
is_on_functions_mock.return_value = True
_send_attach_warning()
mock_diagnostics.warning.assert_not_called()