Skip to content

Commit

Permalink
Introduce enable live metrics to distro (#35566)
Browse files Browse the repository at this point in the history
  • Loading branch information
lzchen committed May 22, 2024
1 parent b63db11 commit a618656
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 24 deletions.
3 changes: 3 additions & 0 deletions sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

### Other Changes

- Update live metrics to use typespec generated swagger
([#34840](https://github.com/Azure/azure-sdk-for-python/pull/34840))

## 1.0.0b25 (2024-04-19)

### Features Added
Expand Down
9 changes: 9 additions & 0 deletions sdk/monitor/azure-monitor-opentelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

### Features Added

- Enable live metrics feature
([#35566](https://github.com/Azure/azure-sdk-for-python/pull/35566))

### Breaking Changes

### Bugs Fixed
Expand All @@ -17,6 +20,12 @@
- Add diagnostics for sdk detection and backoff
([#35610](https://github.com/Azure/azure-sdk-for-python/pull/35610))

### Breaking Changes

### Bugs Fixed

### Other Changes

## 1.4.1 (2024-04-25)

### Features Added
Expand Down
2 changes: 2 additions & 0 deletions sdk/monitor/azure-monitor-opentelemetry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ You can use `configure_azure_monitor` to set up instrumentation for your app to
| Parameter | Description | Environment Variable |
|-------------------|----------------------------------------------------|----------------------|
| `connection_string` | The [connection string][connection_string_doc] for your Application Insights resource. The connection string will be automatically populated from the `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable if not explicitly passed in. | `APPLICATIONINSIGHTS_CONNECTION_STRING` |
| `enable_live_metrics` | Enable [live metrics][application_insights_live_metrics] feature. Defaults to `False`. | `N/A` |
| `logger_name` | The name of the [Python logger][python_logger] under which telemetry is collected. | `N/A` |
| `instrumentation_options` | A nested dictionary that determines which instrumentations to enable or disable. Instrumentations are referred to by their [Library Names](#officially-supported-instrumentations). For example, `{"azure_sdk": {"enabled": False}, "flask": {"enabled": False}, "django": {"enabled": True}}` will disable Azure Core Tracing and the Flask instrumentation but leave Django and the other default instrumentations enabled. The `OTEL_PYTHON_DISABLED_INSTRUMENTATIONS` environment variable explained below can also be used to disable instrumentations. | `N/A` |
| `resource` | Specifies the OpenTelemetry [Resource][ot_spec_resource] associated with your application. Passed in [Resource Attributes][ot_spec_resource_attributes] take priority over default attributes and those from [Resource Detectors][ot_python_resource_detectors]. | [OTEL_SERVICE_NAME][ot_spec_service_name], [OTEL_RESOURCE_ATTRIBUTES][ot_spec_resource_attributes], [OTEL_EXPERIMENTAL_RESOURCE_DETECTORS][ot_python_resource_detectors] |
Expand Down Expand Up @@ -210,6 +211,7 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio
[azure_monitor_opentelemetry_exporters]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry-exporter#microsoft-opentelemetry-exporter-for-azure-monitor
[azure_portal]: https://portal.azure.com
[azure_sub]: https://azure.microsoft.com/free/
[application_insights_live_metrics]: https://learn.microsoft.com/azure/azure-monitor/app/live-stream
[application_insights_namespace]: https://learn.microsoft.com/azure/azure-monitor/app/app-insights-overview
[application_insights_sampling]: https://learn.microsoft.com/azure/azure-monitor/app/sampling
[connection_string_doc]: https://learn.microsoft.com/azure/azure-monitor/app/sdk-connection-string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from logging import getLogger
from typing import Dict, cast

from opentelemetry._logs import get_logger_provider, set_logger_provider
from opentelemetry._logs import set_logger_provider
from opentelemetry.instrumentation.dependencies import (
get_dist_dependency_conflicts,
)
Expand All @@ -21,7 +21,7 @@
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.trace import get_tracer_provider, set_tracer_provider
from opentelemetry.trace import set_tracer_provider
from pkg_resources import iter_entry_points # type: ignore

from azure.core.settings import settings
Expand All @@ -32,12 +32,18 @@
DISABLE_LOGGING_ARG,
DISABLE_METRICS_ARG,
DISABLE_TRACING_ARG,
ENABLE_LIVE_METRICS_ARG,
LOGGER_NAME_ARG,
RESOURCE_ARG,
SAMPLING_RATIO_ARG,
SPAN_PROCESSORS_ARG,
)
from azure.monitor.opentelemetry._types import ConfigurationValue
from azure.monitor.opentelemetry.exporter._quickpulse import enable_live_metrics # pylint: disable=import-error,no-name-in-module
from azure.monitor.opentelemetry.exporter._quickpulse._processor import ( # pylint: disable=import-error,no-name-in-module
_QuickpulseLogRecordProcessor,
_QuickpulseSpanProcessor,
)
from azure.monitor.opentelemetry.exporter import ( # pylint: disable=import-error,no-name-in-module
ApplicationInsightsSampler,
AzureMonitorLogExporter,
Expand Down Expand Up @@ -78,6 +84,8 @@ def configure_azure_monitor(**kwargs) -> None: # pylint: disable=C4758
Attributes take priority over default attributes and those from Resource Detectors.
:keyword list[~opentelemetry.sdk.trace.SpanProcessor] span_processors: List of `SpanProcessor` objects
to process every span prior to exporting. Will be run sequentially.
:keyword bool enable_live_metrics: Boolean value to determine whether to enable live metrics feature.
Defaults to `False`.
:keyword str storage_directory: Storage directory in which to store retry files. Defaults to
`<tempfile.gettempdir()>/Microsoft/AzureMonitor/opentelemetry-python-<your-instrumentation-key>`.
:rtype: None
Expand All @@ -90,6 +98,7 @@ def configure_azure_monitor(**kwargs) -> None: # pylint: disable=C4758
disable_tracing = configurations[DISABLE_TRACING_ARG]
disable_logging = configurations[DISABLE_LOGGING_ARG]
disable_metrics = configurations[DISABLE_METRICS_ARG]
enable_live_metrics_config = configurations[ENABLE_LIVE_METRICS_ARG]

# Setup tracing pipeline
if not disable_tracing:
Expand All @@ -103,6 +112,10 @@ def configure_azure_monitor(**kwargs) -> None: # pylint: disable=C4758
if not disable_metrics:
_setup_metrics(configurations)

# Setup live metrics
if enable_live_metrics_config:
_setup_live_metrics(configurations)

# Setup instrumentations
# Instrumentations need to be setup last so to use the global providers
# instanstiated in the other setup steps
Expand All @@ -116,28 +129,34 @@ def _setup_tracing(configurations: Dict[str, ConfigurationValue]):
sampler=ApplicationInsightsSampler(sampling_ratio=cast(float, sampling_ratio)),
resource=resource
)
set_tracer_provider(tracer_provider)
for span_processor in configurations[SPAN_PROCESSORS_ARG]: # type: ignore
get_tracer_provider().add_span_processor(span_processor) # type: ignore
tracer_provider.add_span_processor(span_processor) # type: ignore
if configurations.get(ENABLE_LIVE_METRICS_ARG):
qsp = _QuickpulseSpanProcessor()
tracer_provider.add_span_processor(qsp)
trace_exporter = AzureMonitorTraceExporter(**configurations)
bsp = BatchSpanProcessor(
trace_exporter,
)
get_tracer_provider().add_span_processor(bsp) # type: ignore
tracer_provider.add_span_processor(bsp)
set_tracer_provider(tracer_provider)
if _is_instrumentation_enabled(configurations, _AZURE_SDK_INSTRUMENTATION_NAME):
settings.tracing_implementation = OpenTelemetrySpan


def _setup_logging(configurations: Dict[str, ConfigurationValue]):
resource: Resource = configurations[RESOURCE_ARG] # type: ignore
logger_provider = LoggerProvider(resource=resource)
set_logger_provider(logger_provider)
if configurations.get(ENABLE_LIVE_METRICS_ARG):
qlp = _QuickpulseLogRecordProcessor()
logger_provider.add_log_record_processor(qlp)
log_exporter = AzureMonitorLogExporter(**configurations)
log_record_processor = BatchLogRecordProcessor(
log_exporter,
)
get_logger_provider().add_log_record_processor(log_record_processor) # type: ignore
handler = LoggingHandler(logger_provider=get_logger_provider())
logger_provider.add_log_record_processor(log_record_processor)
set_logger_provider(logger_provider)
handler = LoggingHandler(logger_provider=logger_provider)
logger_name: str = configurations[LOGGER_NAME_ARG] # type: ignore
getLogger(logger_name).addHandler(handler)

Expand All @@ -153,6 +172,10 @@ def _setup_metrics(configurations: Dict[str, ConfigurationValue]):
set_meter_provider(meter_provider)


def _setup_live_metrics(configurations):
enable_live_metrics(**configurations)


def _setup_instrumentations(configurations: Dict[str, ConfigurationValue]):
# use pkg_resources for now until https://github.com/open-telemetry/opentelemetry-python/pull/3168 is merged
for entry_point in iter_entry_points(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# --------------------Configuration------------------------------------------

CONNECTION_STRING_ARG = "connection_string"
ENABLE_LIVE_METRICS_ARG = "enable_live_metrics"
DISABLE_AZURE_CORE_TRACING_ARG = "disable_azure_core_tracing"
DISABLE_LOGGING_ARG = "disable_logging"
DISABLE_METRICS_ARG = "disable_metrics"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
DISABLE_METRICS_ARG,
DISABLE_TRACING_ARG,
DISTRO_VERSION_ARG,
ENABLE_LIVE_METRICS_ARG,
INSTRUMENTATION_OPTIONS_ARG,
LOGGER_NAME_ARG,
RESOURCE_ARG,
Expand Down Expand Up @@ -68,6 +69,7 @@ def _get_configurations(**kwargs) -> Dict[str, ConfigurationValue]:
_default_sampling_ratio(configurations)
_default_instrumentation_options(configurations)
_default_span_processors(configurations)
_default_enable_live_metrics(configurations)

return configurations

Expand Down Expand Up @@ -97,8 +99,7 @@ def _default_disable_tracing(configurations):


def _default_logger_name(configurations):
if LOGGER_NAME_ARG not in configurations:
configurations[LOGGER_NAME_ARG] = ""
configurations.setdefault(LOGGER_NAME_ARG, "")


def _default_resource(configurations):
Expand Down Expand Up @@ -147,8 +148,11 @@ def _default_instrumentation_options(configurations):


def _default_span_processors(configurations):
if SPAN_PROCESSORS_ARG not in configurations:
configurations[SPAN_PROCESSORS_ARG] = []
configurations.setdefault(SPAN_PROCESSORS_ARG, [])


def _default_enable_live_metrics(configurations):
configurations.setdefault(ENABLE_LIVE_METRICS_ARG, False)


def _get_otel_disabled_instrumentations():
Expand Down
2 changes: 2 additions & 0 deletions sdk/monitor/azure-monitor-opentelemetry/samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ For guidance on the samples README, visit the [sample guide](https://github.com/
|[logging/basic.py][logging_basic] | Produce logs |
|[metrics/attributes.py][attributes] | Add attributes to custom metrics counters |
|[metrics/instruments.py][instruments] | Create observable instruments |
|[metrics/live_metrics.py][live_metrics] | Live metrics feature |
|[tracing/django/sample/manage.py][django] | Instrument a django app |
|[tracing/db_psycopg2.py][db_psycopg2] | Instrument the PsycoPG2 library |
|[tracing/http_fastapi.py][http_fastapi] | Instrument a FastAPI app |
Expand Down Expand Up @@ -68,6 +69,7 @@ To learn more, see the [Azure Monitor OpenTelemetry Distro documentation][distro
[logging_basic]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/logging/basic.py
[attributes]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/metrics/attributes.py
[instruments]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/metrics/instruments.py
[instruments]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/metrics/live_metrics.py
[django]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/tracing/django/sample/manage.py
[db_psycopg2]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/tracing/db_psycopg2.py
[http_fastapi]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/tracing/http_fastapi.py
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
"""
This example shows how configure live metrics to be enabled. It sets up a minimal example of sending dependency,
trace and exception telemetry to demonstrate the capabilities and collection set of live metrics.
"""
import logging
import requests
import time

from azure.monitor.opentelemetry import configure_azure_monitor
from opentelemetry import trace

from opentelemetry.sdk.resources import Resource

configure_azure_monitor(
resource=Resource.create({
"service.name": "live_metrics_service",
"service.instance.id": "qp_instance_id",
}),
logger_name=__name__,
enable_live_metrics=True, # Enable live metrics configuration
)

tracer = trace.get_tracer(__name__)
logger = logging.getLogger(__name__)

# Continuously send metrics
while True:
with tracer.start_as_current_span("parent"):
logger.warning("sending request")
response = requests.get("https://azure.microsoft.com/", timeout=5)
try:
val = 1 / 0
print(val)
except ZeroDivisionError:
logger.error("Error: Division by zero", stack_info=True, exc_info=True)
time.sleep(2)
Loading

0 comments on commit a618656

Please sign in to comment.