diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md b/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md index bca0672f7b02..fe7be4f1e622 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md @@ -16,8 +16,10 @@ Install the Microsoft Opentelemetry exporter for Azure Monitor with [pip][pip]: pip install azure-monitor-opentelemetry-exporter --pre ``` -### Prerequisites: +### Prerequisites + To use this package, you must have: + * Azure subscription - [Create a free account][azure_sub] * Azure Monitor - [How to use application insights][application_insights_namespace] * Opentelemetry SDK - [Opentelemtry SDK for Python][ot_sdk_python] @@ -25,11 +27,13 @@ To use this package, you must have: ### Instantiate the client -Interaction with Azure monitor exporter starts with an instance of the `AzureMonitorTraceExporter` class for distributed tracing or `AzureMonitorLogExporter` for logging. You will need a **connection_string** to instantiate the object. +Interaction with Azure monitor exporter starts with an instance of the `AzureMonitorTraceExporter` class for distributed tracing, `AzureMonitorLogExporter` for logging and `AzureMonitorMetricExporter` for metrics. You will need a **connection_string** to instantiate the object. Please find the samples linked below for demonstration as to how to construct the exporter using a connection string. #### Logging +NOTE: The logging signal for the `AzureMonitorLogExporter` is currently in an EXPERIMENTAL state. Possible breaking changes may ensue in the future. + ```Python from azure.monitor.opentelemetry.exporter import AzureMonitorLogExporter exporter = AzureMonitorLogExporter.from_connection_string( @@ -37,6 +41,16 @@ exporter = AzureMonitorLogExporter.from_connection_string( ) ``` +#### Metrics + +```Python +from azure.monitor.opentelemetry.exporter import AzureMonitorMetricExporter +exporter = AzureMonitorMetricExporter.from_connection_string( + conn_str = os.environ["APPLICATIONINSIGHTS_CONNECTION_STRING"] +) + +``` + #### Tracing ```Python @@ -53,6 +67,11 @@ from azure.monitor.opentelemetry.exporter import AzureMonitorLogExporter exporter = AzureMonitorLogExporter() ``` +```python +from azure.monitor.opentelemetry.exporter import AzureMonitorMetricExporter +exporter = AzureMonitorMetricExporter() +``` + ```python from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter exporter = AzureMonitorTraceExporter() @@ -80,7 +99,21 @@ Some of the key concepts for the Azure monitor exporter include: * [AzureMonitorLogExporter][log_reference]: This is the class that is initialized to send logging related telemetry to Azure Monitor. -* [Trace][trace_concept]: Trace refers to distributed tracing. It can be thought of as a directed acyclic graph (DAG) of `Span`s, where the edges between `Span`s are defined as parent/child relationship. +* [Metric][metric_concept]: `Metric` refers to recording raw measurements with predefined aggregation and sets of attributes for a period in time. + +* [Measurement][measurement]: Represents a data point recorded at a point in time. + +* [Instrument][instrument]: Instruments are used to report `Measurement`s. + +* [Meter][meter]: The `Meter` is responsible for creating `Instruments`. + +* [Meter Provider][meter_provider]: Provides a `Meter` for the given instrumentation library. + +* [Metric Reader][metric_reader]: An SDK implementation object that provides the common configurable aspects of the OpenTelemetry Metrics SDK such as collection, flushing and shutdown. + +* [AzureMonitorMetricExporter][metric_reference]: This is the class that is initialized to send metric related telemetry to Azure Monitor. + +* [Trace][trace_concept]: Trace refers to distributed tracing. A distributed trace is a set of events, triggered as a result of a single logical operation, consolidated across various components of an application. In particular, a Trace can be thought of as a directed acyclic graph (DAG) of Spans, where the edges between Spans are defined as parent/child relationship. * [Span][span]: Represents a single operation within a `Trace`. Can be nested to form a trace tree. Each trace contains a root span, which typically describes the entire operation and, optionally, one ore more sub-spans for its sub-operations. @@ -105,6 +138,7 @@ The following sections provide several code snippets covering some of the most c * [Exporting a log record](#export-hello-world-log) * [Exporting correlated log record](#export-correlated-log) * [Exporting log record with custom properties](#export-custom-properties-log) +* [Exporting an exceptions log record](#export-exceptions-log) #### Export Hello World Log @@ -216,6 +250,131 @@ logger = logging.getLogger(__name__) logger.debug("DEBUG: Debug with properties", extra={"debug": "true"}) ``` +#### Export Exceptions Log + +```Python +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +""" +An example showing how to export exception telemetry using the AzureMonitorLogExporter. +""" +import os +import logging + +from opentelemetry.sdk._logs import ( + LogEmitterProvider, + LoggingHandler, + get_log_emitter_provider, + set_log_emitter_provider, +) +from opentelemetry.sdk._logs.export import BatchLogProcessor + +from azure.monitor.opentelemetry.exporter import AzureMonitorLogExporter + +set_log_emitter_provider(LogEmitterProvider()) +exporter = AzureMonitorLogExporter.from_connection_string( + os.environ["APPLICATIONINSIGHTS_CONNECTION_STRING"] +) +get_log_emitter_provider().add_log_processor(BatchLogProcessor(exporter)) + +# Attach LoggingHandler to namespaced logger +handler = LoggingHandler() +logger = logging.getLogger(__name__) +logger.addHandler(handler) +logger.setLevel(logging.NOTSET) + +# The following code will generate two pieces of exception telemetry +# that are identical in nature +try: + val = 1 / 0 + print(val) +except ZeroDivisionError: + logger.exception("Error: Division by zero") + +try: + val = 1 / 0 + print(val) +except ZeroDivisionError: + logger.error("Error: Division by zero", stack_info=True, exc_info=True) +``` + +### Metrics + +The following sections provide several code snippets covering some of the most common tasks, including: + +* [Using different metric instruments](#metric-instrument-usage) + +#### Metric instrument usage + +```python +# 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 typing import Iterable + +from opentelemetry import metrics +from opentelemetry.metrics import CallbackOptions, Observation +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(options: CallbackOptions) -> Iterable[Observation]: + yield Observation(1, {}) + + +def observable_up_down_counter_func( + options: CallbackOptions, +) -> Iterable[Observation]: + yield Observation(-10, {}) + + +def observable_gauge_func(options: CallbackOptions) -> Iterable[Observation]: + yield Observation(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]) + +``` + ### Tracing The following sections provide several code snippets covering some of the most common tasks, including: @@ -334,11 +493,18 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio [log_emitter_provider]: https://opentelemetry-python.readthedocs.io/en/stable/sdk/logs.html#opentelemetry.sdk._logs.LogEmitterProvider [log_processor]: https://opentelemetry-python.readthedocs.io/en/stable/sdk/logs.html#opentelemetry.sdk._logs.LogProcessor [logging_handler]: https://opentelemetry-python.readthedocs.io/en/stable/sdk/logs.html#opentelemetry.sdk._logs.LoggingHandler -[log_reference]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/logs/_exporter.py#L30 +[log_reference]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/logs/_exporter.py +[metric_concept]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#metric-signal +[measurement]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#measurement +[instrument]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument +[meter]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#meter +[meter_provider]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#meterprovider +[metric_reader]:https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#metricreader +[metric_reference]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/metrics/_exporter.py [trace_concept]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#tracing-signal [span]: https://opentelemetry-python.readthedocs.io/en/stable/api/trace.html?highlight=TracerProvider#opentelemetry.trace.Span [tracer]: https://opentelemetry-python.readthedocs.io/en/stable/api/trace.html?highlight=TracerProvider#opentelemetry.trace.Tracer [tracer_provider]: https://opentelemetry-python.readthedocs.io/en/stable/api/trace.html?highlight=TracerProvider#opentelemetry.trace.TracerProvider [span_processor]: https://opentelemetry-python.readthedocs.io/en/stable/_modules/opentelemetry/sdk/trace.html?highlight=SpanProcessor# -[trace_reference]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py#L30 +[trace_reference]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py [sampler_ref]: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#sampling diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/logs/sample_exception.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/logs/sample_exception.py index 33ca53246d8b..169dd97d8c5f 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/logs/sample_exception.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/logs/sample_exception.py @@ -28,8 +28,16 @@ logger.addHandler(handler) logger.setLevel(logging.NOTSET) +# The following code will generate two pieces of exception telemetry +# that are identical in nature try: val = 1 / 0 print(val) except ZeroDivisionError: logger.exception("Error: Division by zero") + +try: + val = 1 / 0 + print(val) +except ZeroDivisionError: + logger.error("Error: Division by zero", stack_info=True, exc_info=True) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/README.md b/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/README.md index 6f1d5cfbedaf..b17872abcc8a 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/README.md +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/README.md @@ -10,10 +10,8 @@ products: 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 @@ -22,17 +20,6 @@ $ 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 diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/sample_metrics.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/sample_metrics.py deleted file mode 100644 index 58435fa128f1..000000000000 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/samples/metrics/sample_metrics.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. -""" -An example to show an application using Opentelemetry metrics 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.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") - -# Create Counter instrument with the meter -counter = meter.create_counter("counter") -counter.add(1)