-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
623 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
132 changes: 132 additions & 0 deletions
132
...r-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/metrics/_exporter.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
# Copyright (c) Microsoft Corporation. All rights reserved. | ||
# Licensed under the MIT License. | ||
import logging | ||
from typing import Sequence, Any | ||
|
||
from opentelemetry.sdk._metrics.export import MetricExporter, MetricExportResult | ||
from opentelemetry.sdk._metrics.point import ( | ||
Gauge, | ||
Histogram, | ||
Metric, | ||
Sum, | ||
) | ||
|
||
from azure.monitor.opentelemetry.exporter import _utils | ||
from azure.monitor.opentelemetry.exporter._generated.models import ( | ||
MetricDataPoint, | ||
MetricsData, | ||
MonitorBase, | ||
TelemetryItem, | ||
) | ||
from azure.monitor.opentelemetry.exporter.export._base import ( | ||
BaseExporter, | ||
ExportResult, | ||
) | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
__all__ = ["AzureMonitorMetricExporter"] | ||
|
||
|
||
class AzureMonitorMetricExporter(BaseExporter, MetricExporter): | ||
"""Azure Monitor Metric exporter for OpenTelemetry.""" | ||
|
||
def export( | ||
self, metrics: Sequence[Metric], **kwargs: Any # pylint: disable=unused-argument | ||
) -> MetricExportResult: | ||
"""Exports a batch of metric data | ||
:param metrics: Open Telemetry Metric(s) to export. | ||
:type metrics: Sequence[~opentelemetry._metrics.point.Metric] | ||
:rtype: ~opentelemetry.sdk._metrics.export.MetricExportResult | ||
""" | ||
envelopes = [self._metric_to_envelope(metric) for metric in metrics] | ||
try: | ||
result = self._transmit(envelopes) | ||
if result == ExportResult.FAILED_RETRYABLE: | ||
envelopes_to_store = [x.as_dict() for x in envelopes] | ||
self.storage.put(envelopes_to_store, 1) | ||
if result == ExportResult.SUCCESS: | ||
# Try to send any cached events | ||
self._transmit_from_storage() | ||
return _get_metric_export_result(result) | ||
except Exception: # pylint: disable=broad-except | ||
_logger.exception("Exception occurred while exporting the data.") | ||
return _get_metric_export_result(ExportResult.FAILED_NOT_RETRYABLE) | ||
|
||
def shutdown(self) -> None: | ||
"""Shuts down the exporter. | ||
Called when the SDK is shut down. | ||
""" | ||
self.storage.close() | ||
|
||
def _metric_to_envelope(self, metric: Metric) -> TelemetryItem: | ||
if not metric: | ||
return None | ||
envelope = _convert_metric_to_envelope(metric) | ||
envelope.instrumentation_key = self._instrumentation_key | ||
return envelope | ||
|
||
@classmethod | ||
def from_connection_string( | ||
cls, conn_str: str, **kwargs: Any | ||
) -> "AzureMonitorMetricExporter": | ||
""" | ||
Create an AzureMonitorMetricExporter from a connection string. | ||
This is the recommended way of instantation if a connection string is passed in explicitly. | ||
If a user wants to use a connection string provided by environment variable, the constructor | ||
of the exporter can be called directly. | ||
:param str conn_str: The connection string to be used for authentication. | ||
:keyword str api_version: The service API version used. Defaults to latest. | ||
:returns an instance of ~AzureMonitorMetricExporter | ||
""" | ||
return cls(connection_string=conn_str, **kwargs) | ||
|
||
|
||
# pylint: disable=protected-access | ||
def _convert_metric_to_envelope(metric: Metric) -> TelemetryItem: | ||
point = metric.point | ||
envelope = _utils._create_telemetry_item(point.time_unix_nano) | ||
envelope.name = "Microsoft.ApplicationInsights.Metric" | ||
envelope.tags.update(_utils._populate_part_a_fields(metric.resource)) | ||
properties = metric.attributes | ||
value = 0 | ||
# TODO | ||
count = 1 | ||
# min = None | ||
# max = None | ||
# std_dev = None | ||
|
||
if isinstance(point, (Gauge, Sum)): | ||
value = point.value | ||
elif isinstance(point, Histogram): | ||
value = sum(point.bucket_counts) | ||
count = sum(point.bucket_counts) | ||
|
||
data_point = MetricDataPoint( | ||
name=metric.name, | ||
value=value, | ||
data_point_type="Aggregation", | ||
count=count, | ||
) | ||
data = MetricsData( | ||
properties=properties, | ||
metrics=[data_point], | ||
) | ||
|
||
envelope.data = MonitorBase(base_data=data, base_type="MetricData") | ||
|
||
return envelope | ||
|
||
|
||
def _get_metric_export_result(result: ExportResult) -> MetricExportResult: | ||
if result == ExportResult.SUCCESS: | ||
return MetricExportResult.SUCCESS | ||
if result in ( | ||
ExportResult.FAILED_RETRYABLE, | ||
ExportResult.FAILED_NOT_RETRYABLE, | ||
): | ||
return MetricExportResult.FAILURE | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
--- | ||
page_type: sample | ||
languages: | ||
- python | ||
products: | ||
- azure-monitor | ||
--- | ||
|
||
# Microsoft Azure Monitor Opentelemetry Exporter Metric Python Samples | ||
|
||
These code samples show common champion scenario operations with the AzureMonitorMetricExporter. | ||
|
||
* Metrics: [sample_metrics.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/sample_metrics.py) | ||
* Instruments: [sample_instruments.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/sample_instruments.py) | ||
|
||
|
||
## Installation | ||
|
||
```sh | ||
$ pip install azure-monitor-opentelemetry-exporter --pre | ||
``` | ||
|
||
## Run the Applications | ||
|
||
### Metrics | ||
|
||
* Update `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable | ||
|
||
* Run the sample | ||
|
||
```sh | ||
$ # from this directory | ||
$ python sample_metrics.py | ||
``` | ||
|
||
### Instrument usage | ||
|
||
* Update `APPLICATIONINSIGHTS_CONNECTION_STRING` environment variable | ||
|
||
* Run the sample | ||
|
||
```sh | ||
$ # from this directory | ||
$ python sample_instruments.py | ||
``` | ||
|
||
## Explore the data | ||
|
||
After running the applications, data would be available in [Azure]( | ||
https://docs.microsoft.com/azure/azure-monitor/app/app-insights-overview#where-do-i-see-my-telemetry) |
64 changes: 64 additions & 0 deletions
64
sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/sample_instruments.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Copyright (c) Microsoft Corporation. All rights reserved. | ||
# Licensed under the MIT License. | ||
""" | ||
An example to show an application using all instruments in the OpenTelemetry SDK. Metrics created | ||
and recorded using the sdk are tracked and telemetry is exported to application insights with the | ||
AzureMonitorMetricsExporter. | ||
""" | ||
import os | ||
|
||
from opentelemetry import _metrics | ||
from opentelemetry._metrics.measurement import Measurement | ||
from opentelemetry.sdk._metrics import MeterProvider | ||
from opentelemetry.sdk._metrics.export import PeriodicExportingMetricReader | ||
|
||
from azure.monitor.opentelemetry.exporter import AzureMonitorMetricExporter | ||
|
||
exporter = AzureMonitorMetricExporter.from_connection_string( | ||
os.environ["APPLICATIONINSIGHTS_CONNECTION_STRING"] | ||
) | ||
reader = PeriodicExportingMetricReader(exporter, export_interval_millis=5000) | ||
_metrics.set_meter_provider(MeterProvider(metric_readers=[reader])) | ||
|
||
# Create a namespaced meter | ||
meter = _metrics.get_meter_provider().get_meter("sample") | ||
|
||
# Callback functions for observable instruments | ||
def observable_counter_func(): | ||
yield Measurement(1, {}) | ||
|
||
|
||
def observable_up_down_counter_func(): | ||
yield Measurement(-10, {}) | ||
|
||
|
||
def observable_gauge_func(): | ||
yield Measurement(9, {}) | ||
|
||
# Counter | ||
counter = meter.create_counter("counter") | ||
counter.add(1) | ||
|
||
# Async Counter | ||
observable_counter = meter.create_observable_counter( | ||
"observable_counter", observable_counter_func | ||
) | ||
|
||
# UpDownCounter | ||
updown_counter = meter.create_up_down_counter("updown_counter") | ||
updown_counter.add(1) | ||
updown_counter.add(-5) | ||
|
||
# Async UpDownCounter | ||
observable_updown_counter = meter.create_observable_up_down_counter( | ||
"observable_updown_counter", observable_up_down_counter_func | ||
) | ||
|
||
# Histogram | ||
histogram = meter.create_histogram("histogram") | ||
histogram.record(99.9) | ||
|
||
# Async Gauge | ||
gauge = meter.create_observable_gauge("gauge", observable_gauge_func) | ||
|
||
input(...) |
Oops, something went wrong.