Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
3 changes: 3 additions & 0 deletions sdk/monitor/azure-monitor-opentelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## 1.0.1 (Unreleased)

- Add message ids for AppLens
([#32195](https://github.com/Azure/azure-sdk-for-python/pull/32195))

### Features Added

### Breaking Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# --------------------------------------------------------------------------


import logging
from warnings import warn

from opentelemetry.sdk._configuration import _OTelSDKConfigurator
Expand All @@ -16,25 +15,35 @@
)
from azure.monitor.opentelemetry._diagnostics.diagnostic_logging import (
AzureDiagnosticLogging,
_ATTACH_FAILURE_CONFIGURATOR,
_ATTACH_SUCCESS_CONFIGURATOR,
)
from azure.monitor.opentelemetry._diagnostics.status_logger import (
AzureStatusLogger,
)

_logger = logging.getLogger(__name__)


class AzureMonitorConfigurator(_OTelSDKConfigurator):
def _configure(self, **kwargs):
if not _is_attach_enabled():
warn(_PREVIEW_ENTRY_POINT_WARNING)
try:
AzureDiagnosticLogging.enable(_logger)
AzureStatusLogger.log_status(False, "Configurator being configured.")
super()._configure(**kwargs)
AzureStatusLogger.log_status(True)
Comment thread
lzchen marked this conversation as resolved.
AzureDiagnosticLogging.info(
"Azure Monitor Configurator configured successfully.",
_ATTACH_SUCCESS_CONFIGURATOR
)
except ValueError as e:
_logger.error(
"Azure Monitor Configurator failed during configuration due to a ValueError: %s", e
AzureDiagnosticLogging.error(
"Azure Monitor Configurator failed during configuration due to a ValueError: %s" % str(e),
Comment thread
jeremydvoss marked this conversation as resolved.
Outdated
_ATTACH_FAILURE_CONFIGURATOR,
)
raise e
except Exception as e:
_logger.error(
"Azure Monitor Configurator failed during configuration: %s", e
AzureDiagnosticLogging.error(
"Azure Monitor Configurator failed during configuration: %s" % str(e),
_ATTACH_FAILURE_CONFIGURATOR,
)
raise e
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
# Licensed under the MIT License. See License in the project root for
# license information.
# --------------------------------------------------------------------------
import logging
from os import environ
from warnings import warn

Expand All @@ -27,55 +26,48 @@
)
from azure.monitor.opentelemetry._diagnostics.diagnostic_logging import (
AzureDiagnosticLogging,
_ATTACH_FAILURE_DISTRO,
_ATTACH_SUCCESS_DISTRO,
)
from azure.monitor.opentelemetry._diagnostics.status_logger import (
AzureStatusLogger,
)

_CONFIG_FAILED_MSG = "Azure Monitor OpenTelemetry Distro failed during configuration: %s"
Comment thread
jeremydvoss marked this conversation as resolved.
Outdated
Comment thread
jeremydvoss marked this conversation as resolved.
Outdated

_logger = logging.getLogger(__name__)
_opentelemetry_logger = logging.getLogger("opentelemetry")
# TODO: Enabled when duplicate logging issue is solved
# _exporter_logger = logging.getLogger("azure.monitor.opentelemetry.exporter")


class AzureMonitorDistro(BaseDistro):
def _configure(self, **kwargs) -> None:
if not _is_attach_enabled():
warn(_PREVIEW_ENTRY_POINT_WARNING)
try:
_configure_auto_instrumentation()
except Exception as ex:
_logger.exception(
("Error occurred auto-instrumenting AzureMonitorDistro")
except Exception as e:
AzureStatusLogger.log_status(False, reason=str(e))
Comment thread
lzchen marked this conversation as resolved.
AzureDiagnosticLogging.error(
_CONFIG_FAILED_MSG % str(e),
_ATTACH_FAILURE_DISTRO,
)
raise ex
raise e


def _configure_auto_instrumentation() -> None:
try:
AzureStatusLogger.log_status(False, "Distro being configured.")
AzureDiagnosticLogging.enable(_logger)
AzureDiagnosticLogging.enable(_opentelemetry_logger)
environ.setdefault(
OTEL_METRICS_EXPORTER, "azure_monitor_opentelemetry_exporter"
)
environ.setdefault(
OTEL_TRACES_EXPORTER, "azure_monitor_opentelemetry_exporter"
)
environ.setdefault(
OTEL_LOGS_EXPORTER, "azure_monitor_opentelemetry_exporter"
)
environ.setdefault(
_OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED, "true"
)
settings.tracing_implementation = OpenTelemetrySpan
AzureStatusLogger.log_status(True)
_logger.info(
"Azure Monitor OpenTelemetry Distro configured successfully."
)
except Exception as exc:
AzureStatusLogger.log_status(False, reason=exc)
_logger.error(_CONFIG_FAILED_MSG, exc)
raise exc
AzureStatusLogger.log_status(False, "Distro being configured.")
environ.setdefault(
OTEL_METRICS_EXPORTER, "azure_monitor_opentelemetry_exporter"
)
environ.setdefault(
OTEL_TRACES_EXPORTER, "azure_monitor_opentelemetry_exporter"
)
environ.setdefault(
OTEL_LOGS_EXPORTER, "azure_monitor_opentelemetry_exporter"
)
environ.setdefault(
_OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED, "true"
)
settings.tracing_implementation = OpenTelemetrySpan
AzureStatusLogger.log_status(True)
AzureDiagnosticLogging.info(
Comment thread
jeremydvoss marked this conversation as resolved.
Outdated
"Azure Monitor OpenTelemetry Distro configured successfully.",
_ATTACH_SUCCESS_DISTRO
)
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@
_IS_ON_APP_SERVICE = "WEBSITE_SITE_NAME" in environ
# TODO: Add environment variable to enabled diagnostics off of App Service
_IS_DIAGNOSTICS_ENABLED = _IS_ON_APP_SERVICE
# TODO: Enabled when duplicate logging issue is solved
Comment thread
jeremydvoss marked this conversation as resolved.
# _EXPORTER_DIAGNOSTICS_ENABLED_ENV_VAR = (
# "AZURE_MONITOR_OPENTELEMETRY_DISTRO_ENABLE_EXPORTER_DIAGNOSTICS"
# )
_CUSTOMER_IKEY_ENV_VAR = None
_PREVIEW_ENTRY_POINT_WARNING = "Autoinstrumentation for the Azure Monitor OpenTelemetry Distro is in preview."
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -74,19 +70,9 @@ def _env_var_or_default(var_name, default_val=""):
return default_val


# TODO: Enabled when duplicate logging issue is solved
# def _is_exporter_diagnostics_enabled():
# return (
# _EXPORTER_DIAGNOSTICS_ENABLED_ENV_VAR in environ
# and environ[_EXPORTER_DIAGNOSTICS_ENABLED_ENV_VAR] == "True"
# )


_EXTENSION_VERSION = _env_var_or_default(
"ApplicationInsightsAgent_EXTENSION_VERSION", "disabled"
)
# TODO: Enabled when duplicate logging issue is solved
# _EXPORTER_DIAGNOSTICS_ENABLED = _is_exporter_diagnostics_enabled()


def _is_attach_enabled():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@
_SUBSCRIPTION_ID_ENV_VAR.split("+")[0] if _SUBSCRIPTION_ID_ENV_VAR else None
)
_logger = logging.getLogger(__name__)
_logger.propagate = False
_logger.setLevel(logging.INFO)
_DIAGNOSTIC_LOG_PATH = _get_log_path()
_ATTACH_SUCCESS_DISTRO = "4200"
Comment thread
jeremydvoss marked this conversation as resolved.
_ATTACH_SUCCESS_CONFIGURATOR = "4201"
Comment thread
lzchen marked this conversation as resolved.
_ATTACH_FAILURE_DISTRO = "4400"
_ATTACH_FAILURE_CONFIGURATOR = "4401"


class AzureDiagnosticLogging:
_initialized = False
_lock = threading.Lock()
_f_handler = None

@classmethod
def _initialize(cls):
Expand All @@ -51,29 +56,36 @@ def _initialize(cls):
+ f'"extensionVersion":"{_EXTENSION_VERSION}", '
+ f'"sdkVersion":"{VERSION}", '
+ f'"subscriptionId":"{_SUBSCRIPTION_ID}", '
+ '"msgId":"%(msgId)s", '
+ '"language":"python"'
+ "}"
+ "}"
)
if not exists(_DIAGNOSTIC_LOG_PATH):
makedirs(_DIAGNOSTIC_LOG_PATH)
AzureDiagnosticLogging._f_handler = logging.FileHandler(
f_handler = logging.FileHandler(
join(
_DIAGNOSTIC_LOG_PATH, _DIAGNOSTIC_LOGGER_FILE_NAME
)
)
formatter = logging.Formatter(
fmt=log_format, datefmt="%Y-%m-%dT%H:%M:%S"
)
AzureDiagnosticLogging._f_handler.setFormatter(formatter)
f_handler.setFormatter(formatter)
_logger.addHandler(f_handler)
AzureDiagnosticLogging._initialized = True
_logger.info("Initialized Azure Diagnostic Logger.")

@classmethod
def enable(cls, logger: logging.Logger):
def info(cls, message: str, message_id: int):
AzureDiagnosticLogging._initialize()
if AzureDiagnosticLogging._initialized and AzureDiagnosticLogging._f_handler:
logger.addHandler(AzureDiagnosticLogging._f_handler)
_logger.info(
"Added Azure diagnostics logging to %s.", logger.name
)
_logger.info(message, extra={'msgId': message_id})

@classmethod
def warning(cls, message: str, message_id: int):
AzureDiagnosticLogging._initialize()
_logger.warning(message, extra={'msgId': message_id})

@classmethod
def error(cls, message: str, message_id: int):
AzureDiagnosticLogging._initialize()
_logger.error(message, extra={'msgId': message_id})
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,51 @@
from azure.monitor.opentelemetry._autoinstrumentation.configurator import (
AzureMonitorConfigurator,
)
from azure.monitor.opentelemetry._diagnostics.diagnostic_logging import (
_ATTACH_FAILURE_CONFIGURATOR,
_ATTACH_SUCCESS_CONFIGURATOR
)


class TestConfigurator(TestCase):
@patch("azure.monitor.opentelemetry._autoinstrumentation.configurator._is_attach_enabled", return_value=True)
@patch(
"azure.monitor.opentelemetry._autoinstrumentation.configurator.AzureDiagnosticLogging.enable"
"azure.monitor.opentelemetry._autoinstrumentation.configurator.AzureDiagnosticLogging"
)
def test_configure(self, mock_diagnostics, attach_mock):
configurator = AzureMonitorConfigurator()
with warnings.catch_warnings():
warnings.simplefilter("error")
configurator._configure()
mock_diagnostics.assert_called_once()
mock_diagnostics.info.assert_called_once_with(
"Azure Monitor Configurator configured successfully.",
_ATTACH_SUCCESS_CONFIGURATOR
)

@patch("azure.monitor.opentelemetry._autoinstrumentation.configurator._is_attach_enabled", return_value=False)
@patch(
"azure.monitor.opentelemetry._autoinstrumentation.configurator.AzureDiagnosticLogging.enable"
"azure.monitor.opentelemetry._autoinstrumentation.configurator.AzureDiagnosticLogging"
)
def test_configure_preview(self, mock_diagnostics, attach_mock):
configurator = AzureMonitorConfigurator()
with self.assertWarns(Warning):
configurator._configure()
mock_diagnostics.assert_called_once()
mock_diagnostics.info.assert_called_once_with(
"Azure Monitor Configurator configured successfully.",
_ATTACH_SUCCESS_CONFIGURATOR
)

@patch("azure.monitor.opentelemetry._autoinstrumentation.configurator.super")
@patch("azure.monitor.opentelemetry._autoinstrumentation.configurator._is_attach_enabled", return_value=True)
@patch(
"azure.monitor.opentelemetry._autoinstrumentation.configurator.AzureDiagnosticLogging"
)
def test_configure_exc(self, mock_diagnostics, attach_mock, super_mock):
configurator = AzureMonitorConfigurator()
super_mock()._configure.side_effect = Exception("Test Exception")
with self.assertRaises(Exception):
configurator._configure()
mock_diagnostics.error.assert_called_once_with(
"Azure Monitor Configurator failed during configuration: Test Exception",
_ATTACH_FAILURE_CONFIGURATOR
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,60 @@
from azure.monitor.opentelemetry._autoinstrumentation.distro import (
AzureMonitorDistro,
)
from azure.monitor.opentelemetry._diagnostics.diagnostic_logging import (
_ATTACH_FAILURE_DISTRO,
_ATTACH_SUCCESS_DISTRO
)


class TestDistro(TestCase):
@patch("azure.monitor.opentelemetry._autoinstrumentation.distro._is_attach_enabled", return_value=True)
@patch("azure.monitor.opentelemetry._autoinstrumentation.distro.settings")
@patch(
"azure.monitor.opentelemetry._autoinstrumentation.distro.AzureDiagnosticLogging.enable"
"azure.monitor.opentelemetry._autoinstrumentation.distro.AzureDiagnosticLogging"
)
def test_configure(self, mock_diagnostics, azure_core_mock, attach_mock):
distro = AzureMonitorDistro()
with warnings.catch_warnings():
warnings.simplefilter("error")
distro.configure()
self.assertEqual(mock_diagnostics.call_count, 2)
mock_diagnostics.info.assert_called_once_with(
"Azure Monitor OpenTelemetry Distro configured successfully.",
_ATTACH_SUCCESS_DISTRO
)
self.assertEqual(
azure_core_mock.tracing_implementation, OpenTelemetrySpan
)

@patch("azure.monitor.opentelemetry._autoinstrumentation.distro._is_attach_enabled", return_value=False)
@patch("azure.monitor.opentelemetry._autoinstrumentation.distro.settings")
@patch(
"azure.monitor.opentelemetry._autoinstrumentation.distro.AzureDiagnosticLogging.enable"
"azure.monitor.opentelemetry._autoinstrumentation.distro.AzureDiagnosticLogging"
)
def test_configure_preview(self, mock_diagnostics, azure_core_mock, attach_mock):
distro = AzureMonitorDistro()
with self.assertWarns(Warning):
distro.configure()
self.assertEqual(mock_diagnostics.call_count, 2)
mock_diagnostics.info.assert_called_once_with(
"Azure Monitor OpenTelemetry Distro configured successfully.",
_ATTACH_SUCCESS_DISTRO
)
self.assertEqual(
azure_core_mock.tracing_implementation, OpenTelemetrySpan
)

@patch("azure.monitor.opentelemetry._autoinstrumentation.distro._configure_auto_instrumentation")
@patch("azure.monitor.opentelemetry._autoinstrumentation.distro._is_attach_enabled", return_value=True)
@patch("azure.monitor.opentelemetry._autoinstrumentation.distro.settings")
@patch(
"azure.monitor.opentelemetry._autoinstrumentation.distro.AzureDiagnosticLogging"
)
def test_configure_exc(self, mock_diagnostics, azure_core_mock, attach_mock, configure_mock):
distro = AzureMonitorDistro()
configure_mock.side_effect = Exception("Test Exception")
with self.assertRaises(Exception):
distro.configure()
mock_diagnostics.error.assert_called_once_with(
"Azure Monitor OpenTelemetry Distro failed during configuration: Test Exception",
_ATTACH_FAILURE_DISTRO
)
Loading