Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
([#34141](https://github.com/Azure/azure-sdk-for-python/pull/34141))
- Add application.ver to part A fields
([#34401](https://github.com/Azure/azure-sdk-for-python/pull/34401))
- Add `APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN`
([#34463](https://github.com/Azure/azure-sdk-for-python/pull/34463))

### Breaking Changes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
_APPLICATIONINSIGHTS_STATSBEAT_DISABLED_ALL = "APPLICATIONINSIGHTS_STATSBEAT_DISABLED_ALL"
_APPLICATIONINSIGHTS_OPENTELEMETRY_RESOURCE_METRIC_DISABLED = \
"APPLICATIONINSIGHTS_OPENTELEMETRY_RESOURCE_METRIC_DISABLED"
_APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN = "APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN"
_WEBSITE_SITE_NAME = "WEBSITE_SITE_NAME"
_WEBSITE_HOME_STAMPNAME = "WEBSITE_HOME_STAMPNAME"
_WEBSITE_HOSTNAME = "WEBSITE_HOSTNAME"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import logging
import os

from typing import Dict, Optional, Union, Any

Expand All @@ -23,8 +24,10 @@
NumberDataPoint,
)
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.util.instrumentation import InstrumentationScope

from azure.monitor.opentelemetry.exporter._constants import (
_APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN,
_AUTOCOLLECTED_INSTRUMENT_NAMES,
_METRIC_ENVELOPE_NAME,
)
Expand Down Expand Up @@ -94,6 +97,7 @@ def export(
point,
metric.name,
resource_metric.resource,
scope_metric.scope,
)
if envelope is not None:
envelopes.append(envelope)
Expand Down Expand Up @@ -133,8 +137,9 @@ def _point_to_envelope(
point: DataPointT,
name: str,
resource: Optional[Resource] = None,
scope: Optional[InstrumentationScope] = None,
) -> Optional[TelemetryItem]:
envelope = _convert_point_to_envelope(point, name, resource)
envelope = _convert_point_to_envelope(point, name, resource, scope)
if name in _AUTOCOLLECTED_INSTRUMENT_NAMES:
envelope = _handle_std_metric_envelope(envelope, name, point.attributes) # type: ignore
if envelope is not None:
Expand Down Expand Up @@ -168,10 +173,14 @@ def _convert_point_to_envelope(
point: DataPointT,
name: str,
resource: Optional[Resource] = None,
scope: Optional[InstrumentationScope] = None
) -> TelemetryItem:
envelope = _utils._create_telemetry_item(point.time_unix_nano)
envelope.name = _METRIC_ENVELOPE_NAME
envelope.tags.update(_utils._populate_part_a_fields(resource)) # type: ignore
namespace = None
if scope is not None and _is_metric_namespace_opted_in():
namespace = str(scope.name)[:256]
value: Union[int, float] = 0
count = 1
min_ = None
Expand All @@ -191,6 +200,7 @@ def _convert_point_to_envelope(

data_point = MetricDataPoint(
name=str(name)[:1024],
namespace=namespace,
value=value,
count=count,
min=min_,
Expand Down Expand Up @@ -266,6 +276,8 @@ def _handle_std_metric_envelope(
def _is_status_code_success(status_code: Optional[str], threshold: int) -> bool:
return status_code is not None and int(status_code) < threshold

def _is_metric_namespace_opted_in() -> bool:
return os.environ.get(_APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN, "False").lower() == "true"

def _get_metric_export_result(result: ExportResult) -> MetricExportResult:
if result == ExportResult.SUCCESS:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Optional
from opentelemetry.sdk.metrics.export import DataPointT
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.util.instrumentation import InstrumentationScope

from azure.monitor.opentelemetry.exporter._generated.models import TelemetryItem
from azure.monitor.opentelemetry.exporter import AzureMonitorMetricExporter
Expand All @@ -17,11 +18,13 @@ def _point_to_envelope(
point: DataPointT,
name: str,
resource: Optional[Resource] = None,
scope: Optional[InstrumentationScope] = None
) -> Optional[TelemetryItem]:
# map statsbeat name from OpenTelemetry name
name = _STATSBEAT_METRIC_NAME_MAPPINGS[name]
return super()._point_to_envelope(
point,
name,
resource,
None,
)
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ def test_point_to_envelope_partA_default(self):
def test_point_to_envelope_number(self):
exporter = self._exporter
resource = Resource.create(attributes={"asd":"test_resource"})
scope = InstrumentationScope("test_scope")
point=NumberDataPoint(
attributes={
"test": "attribute",
Expand All @@ -221,7 +222,7 @@ def test_point_to_envelope_number(self):
time_unix_nano=1646865018558419457,
value=10,
)
envelope = exporter._point_to_envelope(point, "test name", resource)
envelope = exporter._point_to_envelope(point, "test name", resource, scope)
self.assertEqual(envelope.instrumentation_key, exporter._instrumentation_key)
self.assertEqual(envelope.name, 'Microsoft.ApplicationInsights.Metric')
self.assertEqual(envelope.time, ns_to_iso_str(point.time_unix_nano))
Expand All @@ -230,6 +231,7 @@ def test_point_to_envelope_number(self):
self.assertEqual(envelope.data.base_data.properties['test'], 'attribute')
self.assertEqual(len(envelope.data.base_data.metrics), 1)
self.assertEqual(envelope.data.base_data.metrics[0].name, "test name")
self.assertEqual(envelope.data.base_data.metrics[0].namespace, None)
self.assertEqual(envelope.data.base_data.metrics[0].value, 10)
self.assertEqual(envelope.data.base_data.metrics[0].count, 1)

Expand Down Expand Up @@ -261,6 +263,37 @@ def test_point_to_envelope_histogram(self):
self.assertEqual(envelope.data.base_data.metrics[0].value, 31)
self.assertEqual(envelope.data.base_data.metrics[0].count, 7)

@mock.patch.dict(
"os.environ",
{
"APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN": "True",
},
)
def test_point_to_envelope_metric_namespace(self):
exporter = self._exporter
resource = Resource.create(attributes={"asd":"test_resource"})
scope = InstrumentationScope("test_scope")
point=NumberDataPoint(
attributes={
"test": "attribute",
},
start_time_unix_nano=1646865018558419456,
time_unix_nano=1646865018558419457,
value=10,
)
envelope = exporter._point_to_envelope(point, "test name", resource, scope)
self.assertEqual(envelope.instrumentation_key, exporter._instrumentation_key)
self.assertEqual(envelope.name, 'Microsoft.ApplicationInsights.Metric')
self.assertEqual(envelope.time, ns_to_iso_str(point.time_unix_nano))
self.assertEqual(envelope.data.base_type, 'MetricData')
self.assertEqual(len(envelope.data.base_data.properties), 1)
self.assertEqual(envelope.data.base_data.properties['test'], 'attribute')
self.assertEqual(len(envelope.data.base_data.metrics), 1)
self.assertEqual(envelope.data.base_data.metrics[0].name, "test name")
self.assertEqual(envelope.data.base_data.metrics[0].namespace, "test_scope")
self.assertEqual(envelope.data.base_data.metrics[0].value, 10)
self.assertEqual(envelope.data.base_data.metrics[0].count, 1)

def test_point_to_envelope_std_metric_client_duration(self):
exporter = self._exporter
resource = Resource(
Expand Down