Skip to content

Commit a618656

Browse files
authored
Introduce enable live metrics to distro (Azure#35566)
1 parent b63db11 commit a618656

File tree

10 files changed

+177
-24
lines changed

10 files changed

+177
-24
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
### Other Changes
1212

13+
- Update live metrics to use typespec generated swagger
14+
([#34840](https://github.com/Azure/azure-sdk-for-python/pull/34840))
15+
1316
## 1.0.0b25 (2024-04-19)
1417

1518
### Features Added

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
### Features Added
66

7+
- Enable live metrics feature
8+
([#35566](https://github.com/Azure/azure-sdk-for-python/pull/35566))
9+
710
### Breaking Changes
811

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

23+
### Breaking Changes
24+
25+
### Bugs Fixed
26+
27+
### Other Changes
28+
2029
## 1.4.1 (2024-04-25)
2130

2231
### Features Added

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ You can use `configure_azure_monitor` to set up instrumentation for your app to
6060
| Parameter | Description | Environment Variable |
6161
|-------------------|----------------------------------------------------|----------------------|
6262
| `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` |
63+
| `enable_live_metrics` | Enable [live metrics][application_insights_live_metrics] feature. Defaults to `False`. | `N/A` |
6364
| `logger_name` | The name of the [Python logger][python_logger] under which telemetry is collected. | `N/A` |
6465
| `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` |
6566
| `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] |
@@ -210,6 +211,7 @@ contact [[email protected]](mailto:[email protected]) with any additio
210211
[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
211212
[azure_portal]: https://portal.azure.com
212213
[azure_sub]: https://azure.microsoft.com/free/
214+
[application_insights_live_metrics]: https://learn.microsoft.com/azure/azure-monitor/app/live-stream
213215
[application_insights_namespace]: https://learn.microsoft.com/azure/azure-monitor/app/app-insights-overview
214216
[application_insights_sampling]: https://learn.microsoft.com/azure/azure-monitor/app/sampling
215217
[connection_string_doc]: https://learn.microsoft.com/azure/azure-monitor/app/sdk-connection-string

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

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from logging import getLogger
77
from typing import Dict, cast
88

9-
from opentelemetry._logs import get_logger_provider, set_logger_provider
9+
from opentelemetry._logs import set_logger_provider
1010
from opentelemetry.instrumentation.dependencies import (
1111
get_dist_dependency_conflicts,
1212
)
@@ -21,7 +21,7 @@
2121
from opentelemetry.sdk.resources import Resource
2222
from opentelemetry.sdk.trace import TracerProvider
2323
from opentelemetry.sdk.trace.export import BatchSpanProcessor
24-
from opentelemetry.trace import get_tracer_provider, set_tracer_provider
24+
from opentelemetry.trace import set_tracer_provider
2525
from pkg_resources import iter_entry_points # type: ignore
2626

2727
from azure.core.settings import settings
@@ -32,12 +32,18 @@
3232
DISABLE_LOGGING_ARG,
3333
DISABLE_METRICS_ARG,
3434
DISABLE_TRACING_ARG,
35+
ENABLE_LIVE_METRICS_ARG,
3536
LOGGER_NAME_ARG,
3637
RESOURCE_ARG,
3738
SAMPLING_RATIO_ARG,
3839
SPAN_PROCESSORS_ARG,
3940
)
4041
from azure.monitor.opentelemetry._types import ConfigurationValue
42+
from azure.monitor.opentelemetry.exporter._quickpulse import enable_live_metrics # pylint: disable=import-error,no-name-in-module
43+
from azure.monitor.opentelemetry.exporter._quickpulse._processor import ( # pylint: disable=import-error,no-name-in-module
44+
_QuickpulseLogRecordProcessor,
45+
_QuickpulseSpanProcessor,
46+
)
4147
from azure.monitor.opentelemetry.exporter import ( # pylint: disable=import-error,no-name-in-module
4248
ApplicationInsightsSampler,
4349
AzureMonitorLogExporter,
@@ -78,6 +84,8 @@ def configure_azure_monitor(**kwargs) -> None: # pylint: disable=C4758
7884
Attributes take priority over default attributes and those from Resource Detectors.
7985
:keyword list[~opentelemetry.sdk.trace.SpanProcessor] span_processors: List of `SpanProcessor` objects
8086
to process every span prior to exporting. Will be run sequentially.
87+
:keyword bool enable_live_metrics: Boolean value to determine whether to enable live metrics feature.
88+
Defaults to `False`.
8189
:keyword str storage_directory: Storage directory in which to store retry files. Defaults to
8290
`<tempfile.gettempdir()>/Microsoft/AzureMonitor/opentelemetry-python-<your-instrumentation-key>`.
8391
:rtype: None
@@ -90,6 +98,7 @@ def configure_azure_monitor(**kwargs) -> None: # pylint: disable=C4758
9098
disable_tracing = configurations[DISABLE_TRACING_ARG]
9199
disable_logging = configurations[DISABLE_LOGGING_ARG]
92100
disable_metrics = configurations[DISABLE_METRICS_ARG]
101+
enable_live_metrics_config = configurations[ENABLE_LIVE_METRICS_ARG]
93102

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

115+
# Setup live metrics
116+
if enable_live_metrics_config:
117+
_setup_live_metrics(configurations)
118+
106119
# Setup instrumentations
107120
# Instrumentations need to be setup last so to use the global providers
108121
# instanstiated in the other setup steps
@@ -116,28 +129,34 @@ def _setup_tracing(configurations: Dict[str, ConfigurationValue]):
116129
sampler=ApplicationInsightsSampler(sampling_ratio=cast(float, sampling_ratio)),
117130
resource=resource
118131
)
119-
set_tracer_provider(tracer_provider)
120132
for span_processor in configurations[SPAN_PROCESSORS_ARG]: # type: ignore
121-
get_tracer_provider().add_span_processor(span_processor) # type: ignore
133+
tracer_provider.add_span_processor(span_processor) # type: ignore
134+
if configurations.get(ENABLE_LIVE_METRICS_ARG):
135+
qsp = _QuickpulseSpanProcessor()
136+
tracer_provider.add_span_processor(qsp)
122137
trace_exporter = AzureMonitorTraceExporter(**configurations)
123138
bsp = BatchSpanProcessor(
124139
trace_exporter,
125140
)
126-
get_tracer_provider().add_span_processor(bsp) # type: ignore
141+
tracer_provider.add_span_processor(bsp)
142+
set_tracer_provider(tracer_provider)
127143
if _is_instrumentation_enabled(configurations, _AZURE_SDK_INSTRUMENTATION_NAME):
128144
settings.tracing_implementation = OpenTelemetrySpan
129145

130146

131147
def _setup_logging(configurations: Dict[str, ConfigurationValue]):
132148
resource: Resource = configurations[RESOURCE_ARG] # type: ignore
133149
logger_provider = LoggerProvider(resource=resource)
134-
set_logger_provider(logger_provider)
150+
if configurations.get(ENABLE_LIVE_METRICS_ARG):
151+
qlp = _QuickpulseLogRecordProcessor()
152+
logger_provider.add_log_record_processor(qlp)
135153
log_exporter = AzureMonitorLogExporter(**configurations)
136154
log_record_processor = BatchLogRecordProcessor(
137155
log_exporter,
138156
)
139-
get_logger_provider().add_log_record_processor(log_record_processor) # type: ignore
140-
handler = LoggingHandler(logger_provider=get_logger_provider())
157+
logger_provider.add_log_record_processor(log_record_processor)
158+
set_logger_provider(logger_provider)
159+
handler = LoggingHandler(logger_provider=logger_provider)
141160
logger_name: str = configurations[LOGGER_NAME_ARG] # type: ignore
142161
getLogger(logger_name).addHandler(handler)
143162

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

155174

175+
def _setup_live_metrics(configurations):
176+
enable_live_metrics(**configurations)
177+
178+
156179
def _setup_instrumentations(configurations: Dict[str, ConfigurationValue]):
157180
# use pkg_resources for now until https://github.com/open-telemetry/opentelemetry-python/pull/3168 is merged
158181
for entry_point in iter_entry_points(

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# --------------------Configuration------------------------------------------
1212

1313
CONNECTION_STRING_ARG = "connection_string"
14+
ENABLE_LIVE_METRICS_ARG = "enable_live_metrics"
1415
DISABLE_AZURE_CORE_TRACING_ARG = "disable_azure_core_tracing"
1516
DISABLE_LOGGING_ARG = "disable_logging"
1617
DISABLE_METRICS_ARG = "disable_metrics"

sdk/monitor/azure-monitor-opentelemetry/azure/monitor/opentelemetry/_utils/configurations.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
DISABLE_METRICS_ARG,
3232
DISABLE_TRACING_ARG,
3333
DISTRO_VERSION_ARG,
34+
ENABLE_LIVE_METRICS_ARG,
3435
INSTRUMENTATION_OPTIONS_ARG,
3536
LOGGER_NAME_ARG,
3637
RESOURCE_ARG,
@@ -68,6 +69,7 @@ def _get_configurations(**kwargs) -> Dict[str, ConfigurationValue]:
6869
_default_sampling_ratio(configurations)
6970
_default_instrumentation_options(configurations)
7071
_default_span_processors(configurations)
72+
_default_enable_live_metrics(configurations)
7173

7274
return configurations
7375

@@ -97,8 +99,7 @@ def _default_disable_tracing(configurations):
9799

98100

99101
def _default_logger_name(configurations):
100-
if LOGGER_NAME_ARG not in configurations:
101-
configurations[LOGGER_NAME_ARG] = ""
102+
configurations.setdefault(LOGGER_NAME_ARG, "")
102103

103104

104105
def _default_resource(configurations):
@@ -147,8 +148,11 @@ def _default_instrumentation_options(configurations):
147148

148149

149150
def _default_span_processors(configurations):
150-
if SPAN_PROCESSORS_ARG not in configurations:
151-
configurations[SPAN_PROCESSORS_ARG] = []
151+
configurations.setdefault(SPAN_PROCESSORS_ARG, [])
152+
153+
154+
def _default_enable_live_metrics(configurations):
155+
configurations.setdefault(ENABLE_LIVE_METRICS_ARG, False)
152156

153157

154158
def _get_otel_disabled_instrumentations():

sdk/monitor/azure-monitor-opentelemetry/samples/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ For guidance on the samples README, visit the [sample guide](https://github.com/
2424
|[logging/basic.py][logging_basic] | Produce logs |
2525
|[metrics/attributes.py][attributes] | Add attributes to custom metrics counters |
2626
|[metrics/instruments.py][instruments] | Create observable instruments |
27+
|[metrics/live_metrics.py][live_metrics] | Live metrics feature |
2728
|[tracing/django/sample/manage.py][django] | Instrument a django app |
2829
|[tracing/db_psycopg2.py][db_psycopg2] | Instrument the PsycoPG2 library |
2930
|[tracing/http_fastapi.py][http_fastapi] | Instrument a FastAPI app |
@@ -68,6 +69,7 @@ To learn more, see the [Azure Monitor OpenTelemetry Distro documentation][distro
6869
[logging_basic]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/logging/basic.py
6970
[attributes]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/metrics/attributes.py
7071
[instruments]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/metrics/instruments.py
72+
[instruments]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/metrics/live_metrics.py
7173
[django]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/tracing/django/sample/manage.py
7274
[db_psycopg2]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/tracing/db_psycopg2.py
7375
[http_fastapi]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry/samples/tracing/http_fastapi.py
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
"""
4+
This example shows how configure live metrics to be enabled. It sets up a minimal example of sending dependency,
5+
trace and exception telemetry to demonstrate the capabilities and collection set of live metrics.
6+
"""
7+
import logging
8+
import requests
9+
import time
10+
11+
from azure.monitor.opentelemetry import configure_azure_monitor
12+
from opentelemetry import trace
13+
14+
from opentelemetry.sdk.resources import Resource
15+
16+
configure_azure_monitor(
17+
resource=Resource.create({
18+
"service.name": "live_metrics_service",
19+
"service.instance.id": "qp_instance_id",
20+
}),
21+
logger_name=__name__,
22+
enable_live_metrics=True, # Enable live metrics configuration
23+
)
24+
25+
tracer = trace.get_tracer(__name__)
26+
logger = logging.getLogger(__name__)
27+
28+
# Continuously send metrics
29+
while True:
30+
with tracer.start_as_current_span("parent"):
31+
logger.warning("sending request")
32+
response = requests.get("https://azure.microsoft.com/", timeout=5)
33+
try:
34+
val = 1 / 0
35+
print(val)
36+
except ZeroDivisionError:
37+
logger.error("Error: Division by zero", stack_info=True, exc_info=True)
38+
time.sleep(2)

0 commit comments

Comments
 (0)