diff --git a/README.md b/README.md index 955fede..6b2b4b8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# OpenTelemetry Azure Monitor Exporters +# OpenTelemetry Azure Monitor SDKs and Exporters -[![Gitter chat](https://img.shields.io/gitter/room/opentelemetry/opentelemetry-python)](https://gitter.im/Microsoft/azure-monitor-python) -[![Build status](https://travis-ci.org/microsoft/opentelemetry-exporters-python.svg?branch=master)](https://travis-ci.org/microsoft/opentelemetry-exporters-python) +[![Gitter chat](https://img.shields.io/gitter/room/Microsoft/azure-monitor-python)](https://gitter.im/Microsoft/azure-monitor-python) +[![Build status](https://travis-ci.org/microsoft/opentelemetry-azure-monitor-python.svg?branch=master)](https://travis-ci.org/microsoft/opentelemetry-exporters-python) [![PyPI version](https://badge.fury.io/py/opentelemetry-azure-monitor-exporter.svg)](https://badge.fury.io/py/opentelemetry-azure-monitor-exporter) ## Installation diff --git a/azure_monitor/examples/metrics/auto_collector.py b/azure_monitor/examples/metrics/auto_collector.py index 65ed70d..cd899d7 100644 --- a/azure_monitor/examples/metrics/auto_collector.py +++ b/azure_monitor/examples/metrics/auto_collector.py @@ -4,7 +4,8 @@ from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.metrics.export.controller import PushController -from azure_monitor import AutoCollection, AzureMonitorMetricsExporter +from azure_monitor import AzureMonitorMetricsExporter +from azure_monitor.sdk.auto_collection import AutoCollection metrics.set_meter_provider(MeterProvider()) meter = metrics.get_meter(__name__) diff --git a/azure_monitor/examples/metrics/client.py b/azure_monitor/examples/metrics/client.py new file mode 100644 index 0000000..57bec03 --- /dev/null +++ b/azure_monitor/examples/metrics/client.py @@ -0,0 +1,26 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# pylint: disable=import-error +# pylint: disable=no-member +# pylint: disable=no-name-in-module +import requests +from opentelemetry import trace +from opentelemetry.ext import http_requests +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import BatchExportSpanProcessor + +from azure_monitor import AzureMonitorSpanExporter + +trace.set_tracer_provider(TracerProvider()) +tracer = trace.get_tracer(__name__) +http_requests.enable(trace.get_tracer_provider()) +span_processor = BatchExportSpanProcessor( + AzureMonitorSpanExporter( + connection_string="InstrumentationKey=" + ) +) +trace.get_tracer_provider().add_span_processor(span_processor) + +response = requests.get(url="http://google.com") + +input("Press any key to exit...") diff --git a/azure_monitor/examples/traces/trace.py b/azure_monitor/examples/traces/trace.py index b5bd7a4..6bbce67 100644 --- a/azure_monitor/examples/traces/trace.py +++ b/azure_monitor/examples/traces/trace.py @@ -1,3 +1,5 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchExportSpanProcessor diff --git a/azure_monitor/src/azure_monitor/__init__.py b/azure_monitor/src/azure_monitor/__init__.py index f0a8d37..4a963e4 100644 --- a/azure_monitor/src/azure_monitor/__init__.py +++ b/azure_monitor/src/azure_monitor/__init__.py @@ -1,13 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -from azure_monitor.auto_collection import AutoCollection from azure_monitor.export.metrics import AzureMonitorMetricsExporter from azure_monitor.export.trace import AzureMonitorSpanExporter -from azure_monitor.options import ExporterOptions -__all__ = [ - "AutoCollection", - "AzureMonitorMetricsExporter", - "AzureMonitorSpanExporter", - "ExporterOptions", -] +__all__ = ["AzureMonitorMetricsExporter", "AzureMonitorSpanExporter"] diff --git a/azure_monitor/src/azure_monitor/sdk/__init__.py b/azure_monitor/src/azure_monitor/sdk/__init__.py new file mode 100644 index 0000000..4eeadf2 --- /dev/null +++ b/azure_monitor/src/azure_monitor/sdk/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +from . import auto_collection + +__all__ = ["auto_collection"] diff --git a/azure_monitor/src/azure_monitor/auto_collection/__init__.py b/azure_monitor/src/azure_monitor/sdk/auto_collection/__init__.py similarity index 76% rename from azure_monitor/src/azure_monitor/auto_collection/__init__.py rename to azure_monitor/src/azure_monitor/sdk/auto_collection/__init__.py index 89437bc..b7ebe41 100644 --- a/azure_monitor/src/azure_monitor/auto_collection/__init__.py +++ b/azure_monitor/src/azure_monitor/sdk/auto_collection/__init__.py @@ -3,11 +3,13 @@ # from opentelemetry.metrics import LabelSet, Meter -from azure_monitor.auto_collection.dependency_metrics import DependencyMetrics -from azure_monitor.auto_collection.performance_metrics import ( +from azure_monitor.sdk.auto_collection.dependency_metrics import ( + DependencyMetrics, +) +from azure_monitor.sdk.auto_collection.performance_metrics import ( PerformanceMetrics, ) -from azure_monitor.auto_collection.request_metrics import RequestMetrics +from azure_monitor.sdk.auto_collection.request_metrics import RequestMetrics __all__ = [ "AutoCollection", diff --git a/azure_monitor/src/azure_monitor/auto_collection/dependency_metrics.py b/azure_monitor/src/azure_monitor/sdk/auto_collection/dependency_metrics.py similarity index 100% rename from azure_monitor/src/azure_monitor/auto_collection/dependency_metrics.py rename to azure_monitor/src/azure_monitor/sdk/auto_collection/dependency_metrics.py diff --git a/azure_monitor/src/azure_monitor/auto_collection/performance_metrics.py b/azure_monitor/src/azure_monitor/sdk/auto_collection/performance_metrics.py similarity index 100% rename from azure_monitor/src/azure_monitor/auto_collection/performance_metrics.py rename to azure_monitor/src/azure_monitor/sdk/auto_collection/performance_metrics.py diff --git a/azure_monitor/src/azure_monitor/auto_collection/request_metrics.py b/azure_monitor/src/azure_monitor/sdk/auto_collection/request_metrics.py similarity index 100% rename from azure_monitor/src/azure_monitor/auto_collection/request_metrics.py rename to azure_monitor/src/azure_monitor/sdk/auto_collection/request_metrics.py diff --git a/azure_monitor/tests/auto_collection/test_auto_collection.py b/azure_monitor/tests/auto_collection/test_auto_collection.py index 8266b88..301d249 100644 --- a/azure_monitor/tests/auto_collection/test_auto_collection.py +++ b/azure_monitor/tests/auto_collection/test_auto_collection.py @@ -7,7 +7,7 @@ from opentelemetry import metrics from opentelemetry.sdk.metrics import MeterProvider -from azure_monitor.auto_collection import AutoCollection +from azure_monitor.sdk.auto_collection import AutoCollection # pylint: disable=protected-access @@ -24,12 +24,14 @@ def tearDownClass(cls): metrics._METER_PROVIDER = None @mock.patch( - "azure_monitor.auto_collection.PerformanceMetrics", autospec=True + "azure_monitor.sdk.auto_collection.PerformanceMetrics", autospec=True ) @mock.patch( - "azure_monitor.auto_collection.DependencyMetrics", autospec=True + "azure_monitor.sdk.auto_collection.DependencyMetrics", autospec=True + ) + @mock.patch( + "azure_monitor.sdk.auto_collection.RequestMetrics", autospec=True ) - @mock.patch("azure_monitor.auto_collection.RequestMetrics", autospec=True) def test_constructor( self, mock_performance, mock_dependencies, mock_requests ): diff --git a/azure_monitor/tests/auto_collection/test_dependency_metrics.py b/azure_monitor/tests/auto_collection/test_dependency_metrics.py index dfedc74..fe273df 100644 --- a/azure_monitor/tests/auto_collection/test_dependency_metrics.py +++ b/azure_monitor/tests/auto_collection/test_dependency_metrics.py @@ -9,7 +9,7 @@ from opentelemetry import metrics from opentelemetry.sdk.metrics import MeterProvider, Observer -from azure_monitor.auto_collection import DependencyMetrics, dependency_metrics +from azure_monitor.sdk.auto_collection import dependency_metrics ORIGINAL_FUNCTION = requests.Session.request ORIGINAL_CONS = HTTPServer.__init__ @@ -27,6 +27,8 @@ def setUpClass(cls): @classmethod def tearDown(cls): metrics._METER_PROVIDER = None + requests.Session.request = ORIGINAL_FUNCTION + dependency_metrics.ORIGINAL_CONSTRUCTOR = ORIGINAL_CONS def setUp(self): dependency_metrics.dependency_map.clear() @@ -35,7 +37,7 @@ def setUp(self): def test_constructor(self): mock_meter = mock.Mock() - metrics_collector = DependencyMetrics( + metrics_collector = dependency_metrics.DependencyMetrics( meter=mock_meter, label_set=self._test_label_set ) self.assertEqual(metrics_collector._meter, mock_meter) @@ -49,10 +51,10 @@ def test_constructor(self): value_type=int, ) - @mock.patch("azure_monitor.auto_collection.dependency_metrics.time") + @mock.patch("azure_monitor.sdk.auto_collection.dependency_metrics.time") def test_track_dependency_rate(self, time_mock): time_mock.time.return_value = 100 - metrics_collector = DependencyMetrics( + metrics_collector = dependency_metrics.DependencyMetrics( meter=self._meter, label_set=self._test_label_set ) obs = Observer( @@ -68,10 +70,10 @@ def test_track_dependency_rate(self, time_mock): metrics_collector._track_dependency_rate(obs) self.assertEqual(obs.aggregators[self._test_label_set].current, 2) - @mock.patch("azure_monitor.auto_collection.dependency_metrics.time") + @mock.patch("azure_monitor.sdk.auto_collection.dependency_metrics.time") def test_track_dependency_rate_time_none(self, time_mock): time_mock.time.return_value = 100 - metrics_collector = DependencyMetrics( + metrics_collector = dependency_metrics.DependencyMetrics( meter=self._meter, label_set=self._test_label_set ) dependency_metrics.dependency_map["last_time"] = None @@ -86,10 +88,10 @@ def test_track_dependency_rate_time_none(self, time_mock): metrics_collector._track_dependency_rate(obs) self.assertEqual(obs.aggregators[self._test_label_set].current, 0) - @mock.patch("azure_monitor.auto_collection.dependency_metrics.time") + @mock.patch("azure_monitor.sdk.auto_collection.dependency_metrics.time") def test_track_dependency_rate_error(self, time_mock): time_mock.time.return_value = 100 - metrics_collector = DependencyMetrics( + metrics_collector = dependency_metrics.DependencyMetrics( meter=self._meter, label_set=self._test_label_set ) dependency_metrics.dependency_map["last_time"] = 100 @@ -105,10 +107,22 @@ def test_track_dependency_rate_error(self, time_mock): metrics_collector._track_dependency_rate(obs) self.assertEqual(obs.aggregators[self._test_label_set].current, 5) - def test_dependency_patch(self): - dependency_metrics.ORIGINAL_REQUEST = lambda x: None + @mock.patch( + "azure_monitor.sdk.auto_collection.dependency_metrics.ORIGINAL_REQUEST" + ) + def test_dependency_patch(self, request_mock): session = requests.Session() - result = dependency_metrics.dependency_patch(session) - + dependency_metrics.dependency_patch(session) self.assertEqual(dependency_metrics.dependency_map["count"], 1) - self.assertIsNone(result) + request_mock.assert_called_with(session) + + @mock.patch( + "azure_monitor.sdk.auto_collection.dependency_metrics.ORIGINAL_REQUEST" + ) + @mock.patch("azure_monitor.sdk.auto_collection.dependency_metrics.context") + def test_dependency_patch_suppress(self, context_mock, request_mock): + context_mock.get_value.return_value = {} + session = requests.Session() + dependency_metrics.dependency_patch(session) + self.assertEqual(dependency_metrics.dependency_map.get("count"), None) + request_mock.assert_called_with(session) diff --git a/azure_monitor/tests/auto_collection/test_performance_metrics.py b/azure_monitor/tests/auto_collection/test_performance_metrics.py index 03a9b61..6637913 100644 --- a/azure_monitor/tests/auto_collection/test_performance_metrics.py +++ b/azure_monitor/tests/auto_collection/test_performance_metrics.py @@ -8,7 +8,7 @@ from opentelemetry import metrics from opentelemetry.sdk.metrics import MeterProvider, Observer -from azure_monitor.auto_collection import PerformanceMetrics +from azure_monitor.sdk.auto_collection import PerformanceMetrics def throw(exc_type, *args, **kwargs): @@ -111,10 +111,10 @@ def test_track_memory(self, psutil_mock): performance_metrics_collector._track_memory(obs) self.assertEqual(obs.aggregators[self._test_label_set].current, 100) - @mock.patch("azure_monitor.auto_collection.performance_metrics.psutil") + @mock.patch("azure_monitor.sdk.auto_collection.performance_metrics.psutil") def test_track_process_cpu(self, psutil_mock): with mock.patch( - "azure_monitor.auto_collection.performance_metrics.PROCESS" + "azure_monitor.sdk.auto_collection.performance_metrics.PROCESS" ) as process_mock: performance_metrics_collector = PerformanceMetrics( meter=self._meter, label_set=self._test_label_set @@ -134,10 +134,10 @@ def test_track_process_cpu(self, psutil_mock): obs.aggregators[self._test_label_set].current, 22.2 ) - @mock.patch("azure_monitor.auto_collection.performance_metrics.logger") + @mock.patch("azure_monitor.sdk.auto_collection.performance_metrics.logger") def test_track_process_cpu_exception(self, logger_mock): with mock.patch( - "azure_monitor.auto_collection.performance_metrics.psutil" + "azure_monitor.sdk.auto_collection.performance_metrics.psutil" ) as psutil_mock: performance_metrics_collector = PerformanceMetrics( meter=self._meter, label_set=self._test_label_set @@ -156,7 +156,7 @@ def test_track_process_cpu_exception(self, logger_mock): def test_track_process_memory(self): with mock.patch( - "azure_monitor.auto_collection.performance_metrics.PROCESS" + "azure_monitor.sdk.auto_collection.performance_metrics.PROCESS" ) as process_mock: performance_metrics_collector = PerformanceMetrics( meter=self._meter, label_set=self._test_label_set @@ -177,10 +177,10 @@ def test_track_process_memory(self): obs.aggregators[self._test_label_set].current, 100 ) - @mock.patch("azure_monitor.auto_collection.performance_metrics.logger") + @mock.patch("azure_monitor.sdk.auto_collection.performance_metrics.logger") def test_track_process_memory_exception(self, logger_mock): with mock.patch( - "azure_monitor.auto_collection.performance_metrics.PROCESS", + "azure_monitor.sdk.auto_collection.performance_metrics.PROCESS", throw(Exception), ): performance_metrics_collector = PerformanceMetrics( diff --git a/azure_monitor/tests/auto_collection/test_request_metrics.py b/azure_monitor/tests/auto_collection/test_request_metrics.py index 389e5c2..63030d1 100644 --- a/azure_monitor/tests/auto_collection/test_request_metrics.py +++ b/azure_monitor/tests/auto_collection/test_request_metrics.py @@ -9,7 +9,7 @@ from opentelemetry import metrics from opentelemetry.sdk.metrics import MeterProvider, Observer -from azure_monitor.auto_collection import RequestMetrics, request_metrics +from azure_monitor.sdk.auto_collection import request_metrics ORIGINAL_FUNCTION = requests.Session.request ORIGINAL_CONS = HTTPServer.__init__ @@ -35,7 +35,7 @@ def setUp(self): def test_constructor(self): mock_meter = mock.Mock() - request_metrics_collector = RequestMetrics( + request_metrics_collector = request_metrics.RequestMetrics( meter=mock_meter, label_set=self._test_label_set ) self.assertEqual(request_metrics_collector._meter, mock_meter) @@ -64,7 +64,7 @@ def test_constructor(self): ) def test_track_request_duration(self): - request_metrics_collector = RequestMetrics( + request_metrics_collector = request_metrics.RequestMetrics( meter=self._meter, label_set=self._test_label_set ) request_metrics.requests_map["duration"] = 0.1 @@ -82,7 +82,7 @@ def test_track_request_duration(self): self.assertEqual(obs.aggregators[self._test_label_set].current, 20) def test_track_request_duration_error(self): - request_metrics_collector = RequestMetrics( + request_metrics_collector = request_metrics.RequestMetrics( meter=self._meter, label_set=self._test_label_set ) request_metrics.requests_map["duration"] = 0.1 @@ -99,9 +99,9 @@ def test_track_request_duration_error(self): request_metrics_collector._track_request_duration(obs) self.assertEqual(obs.aggregators[self._test_label_set].current, 0) - @mock.patch("azure_monitor.auto_collection.request_metrics.time") + @mock.patch("azure_monitor.sdk.auto_collection.request_metrics.time") def test_track_request_rate(self, time_mock): - request_metrics_collector = RequestMetrics( + request_metrics_collector = request_metrics.RequestMetrics( meter=self._meter, label_set=self._test_label_set ) time_mock.time.return_value = 100 @@ -118,10 +118,10 @@ def test_track_request_rate(self, time_mock): request_metrics_collector._track_request_rate(obs) self.assertEqual(obs.aggregators[self._test_label_set].current, 2) - @mock.patch("azure_monitor.auto_collection.request_metrics.time") + @mock.patch("azure_monitor.sdk.auto_collection.request_metrics.time") def test_track_request_rate_time_none(self, time_mock): time_mock.time.return_value = 100 - request_metrics_collector = RequestMetrics( + request_metrics_collector = request_metrics.RequestMetrics( meter=self._meter, label_set=self._test_label_set ) request_metrics.requests_map["last_time"] = None @@ -136,9 +136,9 @@ def test_track_request_rate_time_none(self, time_mock): request_metrics_collector._track_request_rate(obs) self.assertEqual(obs.aggregators[self._test_label_set].current, 0) - @mock.patch("azure_monitor.auto_collection.request_metrics.time") + @mock.patch("azure_monitor.sdk.auto_collection.request_metrics.time") def test_track_request_rate_error(self, time_mock): - request_metrics_collector = RequestMetrics( + request_metrics_collector = request_metrics.RequestMetrics( meter=self._meter, label_set=self._test_label_set ) time_mock.time.return_value = 100 @@ -168,7 +168,7 @@ def test_request_patch(self): def test_server_patch(self): request_metrics.ORIGINAL_CONSTRUCTOR = lambda x, y, z: None with mock.patch( - "azure_monitor.auto_collection.request_metrics.request_patch" + "azure_monitor.sdk.auto_collection.request_metrics.request_patch" ) as request_mock: handler = mock.Mock() handler.do_DELETE.return_value = None @@ -191,7 +191,7 @@ def test_server_patch(self): def test_server_patch_no_methods(self): request_metrics.ORIGINAL_CONSTRUCTOR = lambda x, y, z: None with mock.patch( - "azure_monitor.auto_collection.request_metrics.request_patch" + "azure_monitor.sdk.auto_collection.request_metrics.request_patch" ) as request_mock: handler = mock.Mock() result = request_metrics.server_patch(None, None, handler) diff --git a/azure_monitor/tests/metrics/test_metrics.py b/azure_monitor/tests/metrics/test_metrics.py index b8b4711..7053dba 100644 --- a/azure_monitor/tests/metrics/test_metrics.py +++ b/azure_monitor/tests/metrics/test_metrics.py @@ -200,6 +200,49 @@ def test_observer_to_envelope(self): self.assertIsNotNone(envelope.tags["ai.device.type"]) self.assertIsNotNone(envelope.tags["ai.internal.sdkVersion"]) + def test_observer_to_envelope_value_none(self): + aggregator = ObserverAggregator() + aggregator.update(None) + aggregator.take_checkpoint() + record = MetricRecord(aggregator, self._test_label_set, self._test_obs) + exporter = AzureMonitorMetricsExporter() + envelope = exporter._metric_to_envelope(record) + self.assertIsInstance(envelope, Envelope) + self.assertEqual(envelope.ver, 1) + self.assertEqual(envelope.name, "Microsoft.ApplicationInsights.Metric") + # TODO: implement last updated timestamp for observer + # self.assertEqual( + # envelope.time, + # ns_to_iso_str( + # record.metric.bind( + # record.label_set + # ).last_update_timestamp + # ), + # ) + self.assertEqual(envelope.sample_rate, None) + self.assertEqual(envelope.seq, None) + self.assertEqual(envelope.ikey, "1234abcd-5678-4efa-8abc-1234567890ab") + self.assertEqual(envelope.flags, None) + + self.assertIsInstance(envelope.data, Data) + self.assertIsInstance(envelope.data.base_data, MetricData) + self.assertEqual(envelope.data.base_data.ver, 2) + self.assertEqual(len(envelope.data.base_data.metrics), 1) + self.assertIsInstance(envelope.data.base_data.metrics[0], DataPoint) + self.assertEqual(envelope.data.base_data.metrics[0].ns, "testdesc") + self.assertEqual(envelope.data.base_data.metrics[0].name, "testname") + self.assertEqual(envelope.data.base_data.metrics[0].value, 0) + self.assertEqual( + envelope.data.base_data.properties["environment"], "staging" + ) + self.assertIsNotNone(envelope.tags["ai.cloud.role"]) + self.assertIsNotNone(envelope.tags["ai.cloud.roleInstance"]) + self.assertIsNotNone(envelope.tags["ai.device.id"]) + self.assertIsNotNone(envelope.tags["ai.device.locale"]) + self.assertIsNotNone(envelope.tags["ai.device.osVersion"]) + self.assertIsNotNone(envelope.tags["ai.device.type"]) + self.assertIsNotNone(envelope.tags["ai.internal.sdkVersion"]) + @mock.patch("azure_monitor.export.metrics.logger") def test_measure_to_envelope(self, logger_mock): aggregator = MinMaxSumCountAggregator() diff --git a/docs/azure_monitor/auto-collection/auto-collection.standard-metrics.rst b/docs/azure_monitor/sdk/auto-collection/auto-collection.standard-metrics.rst similarity index 59% rename from docs/azure_monitor/auto-collection/auto-collection.standard-metrics.rst rename to docs/azure_monitor/sdk/auto-collection/auto-collection.standard-metrics.rst index 3c1dba3..f825c79 100644 --- a/docs/azure_monitor/auto-collection/auto-collection.standard-metrics.rst +++ b/docs/azure_monitor/sdk/auto-collection/auto-collection.standard-metrics.rst @@ -2,7 +2,7 @@ Standard Metrics ================ -.. automodule:: azure_monitor.auto_collection +.. automodule:: azure_monitor.sdk.auto_collection :members: :undoc-members: diff --git a/docs/azure_monitor/auto-collection/main.rst b/docs/azure_monitor/sdk/auto-collection/main.rst similarity index 100% rename from docs/azure_monitor/auto-collection/main.rst rename to docs/azure_monitor/sdk/auto-collection/main.rst diff --git a/docs/index.rst b/docs/index.rst index 0958181..e360c22 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -27,7 +27,7 @@ The package is available on PyPI, and can installed via pip: :name: documentation azure_monitor/export/main - azure_monitor/auto-collection/main + azure_monitor/sdk/auto-collection/main Indices and tables