Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

Remove label sets + add is_remote to spancontext #75

Merged
merged 6 commits into from
Apr 6, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions azure_monitor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ requests_counter = meter.create_metric(
label_keys=("environment",),
)

testing_label_set = meter.get_label_set({"environment": "testing"})
testing_labels = {"environment": "testing"}

requests_counter.add(25, testing_label_set)
requests_counter.add(25, testing_labels)
time.sleep(100)
```

Expand Down
4 changes: 2 additions & 2 deletions azure_monitor/examples/metrics/auto_collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
)
controller = PushController(meter, exporter, 5)

testing_label_set = meter.get_label_set({"environment": "testing"})
testing_label_set = {"environment": "testing"}

# Automatically collect standard metrics
auto_collection = AutoCollection(meter=meter, label_set=testing_label_set)
auto_collection = AutoCollection(meter=meter, labels=testing_label_set)

# To configure a separate export interval specific for standard metrics
# meter_standard = metrics.get_meter(__name__ + "_standard")
Expand Down
26 changes: 0 additions & 26 deletions azure_monitor/examples/metrics/client.py

This file was deleted.

50 changes: 50 additions & 0 deletions azure_monitor/examples/metrics/observer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import psutil
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export.controller import PushController

from azure_monitor import AzureMonitorMetricsExporter

metrics.set_meter_provider(MeterProvider())
meter = metrics.get_meter(__name__)
exporter = AzureMonitorMetricsExporter(
connection_string="InstrumentationKey=<INSTRUMENTATION KEY HERE>"
)
controller = PushController(meter=meter, exporter=exporter, interval=2)


# Callback to gather cpu usage
def get_cpu_usage_callback(observer):
for (number, percent) in enumerate(psutil.cpu_percent(percpu=True)):
labels = {"cpu_number": str(number)}
observer.observe(percent, labels)


meter.register_observer(
callback=get_cpu_usage_callback,
name="cpu_percent",
description="per-cpu usage",
unit="1",
value_type=float,
label_keys=("cpu_number",),
)


# Callback to gather RAM memory usage
def get_ram_usage_callback(observer):
ram_percent = psutil.virtual_memory().percent
observer.observe(ram_percent, {})


meter.register_observer(
callback=get_ram_usage_callback,
name="ram_percent",
description="RAM memory usage",
unit="1",
value_type=float,
label_keys=(),
)

input("Metrics will be printed soon. Press a key to finish...\n")
4 changes: 2 additions & 2 deletions azure_monitor/examples/metrics/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
label_keys=("environment",),
)

testing_label_set = meter.get_label_set({"environment": "testing"})
testing_labels = {"environment": "testing"}

requests_counter.add(25, testing_label_set)
requests_counter.add(25, testing_labels)

input("Press any key to exit...")
8 changes: 4 additions & 4 deletions azure_monitor/src/azure_monitor/export/metrics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ def _metric_to_envelope(

if not metric_record:
return None
# TODO: Opentelemetry does not have last updated timestamp for observer
# type metrics yet.
# TODO: Opentelemetry has timestamp for Observer, awaiting release
# TODO: Timestamp info is also moved into aggregators
_time = time_ns()
if isinstance(metric_record.metric, Metric):
_time = metric_record.metric.bind(
metric_record.label_set
dict(metric_record.labels)
).last_update_timestamp
envelope = protocol.Envelope(
ikey=self.options.instrumentation_key,
Expand Down Expand Up @@ -93,7 +93,7 @@ def _metric_to_envelope(
)

properties = {}
for label_tuple in metric_record.label_set.labels:
for label_tuple in metric_record.labels:
properties[label_tuple[0]] = label_tuple[1]
data = protocol.MetricData(metrics=[data_point], properties=properties)
envelope.data = protocol.Data(base_data=data, base_type="MetricData")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
#
from opentelemetry.metrics import LabelSet, Meter
from typing import Dict

from opentelemetry.metrics import Meter

from azure_monitor.sdk.auto_collection.dependency_metrics import (
DependencyMetrics,
Expand All @@ -25,10 +27,10 @@ class AutoCollection:

Args:
meter: OpenTelemetry Meter
label_set: OpenTelemetry label set
labels: Dictionary of labels
"""

def __init__(self, meter: Meter, label_set: LabelSet):
self._performance_metrics = PerformanceMetrics(meter, label_set)
self._dependency_metrics = DependencyMetrics(meter, label_set)
self._request_metrics = RequestMetrics(meter, label_set)
def __init__(self, meter: Meter, labels: Dict[str, str]):
self._performance_metrics = PerformanceMetrics(meter, labels)
self._dependency_metrics = DependencyMetrics(meter, labels)
self._request_metrics = RequestMetrics(meter, labels)
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
# Licensed under the MIT License.
import threading
import time
from typing import Dict

import requests
from opentelemetry import context
from opentelemetry.metrics import Meter
from opentelemetry.sdk.metrics import LabelSet

dependency_map = dict()
_dependency_lock = threading.Lock()
Expand All @@ -30,12 +30,12 @@ class DependencyMetrics:

Args:
meter: OpenTelemetry Meter
label_set: OpenTelemetry label set
labels: Dictionary of labels
"""

def __init__(self, meter: Meter, label_set: LabelSet):
def __init__(self, meter: Meter, labels: Dict[str, str]):
self._meter = meter
self._label_set = label_set
self._labels = labels
# Patch requests
requests.Session.request = dependency_patch
meter.register_observer(
Expand Down Expand Up @@ -70,8 +70,8 @@ def _track_dependency_rate(self, observer) -> None:
dependency_map["last_time"] = current_time
dependency_map["last_count"] = current_count
dependency_map["last_result"] = result
observer.observe(int(result), self._label_set)
observer.observe(int(result), self._labels)
except ZeroDivisionError:
# If elapsed_seconds is 0, exporter call made too close to previous
# Return the previous result if this is the case
observer.observe(int(last_result), self._label_set)
observer.observe(int(last_result), self._labels)
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import logging
from typing import Dict

import psutil
from opentelemetry.metrics import Meter
from opentelemetry.sdk.metrics import LabelSet

logger = logging.getLogger(__name__)
PROCESS = psutil.Process()
Expand All @@ -18,12 +18,12 @@ class PerformanceMetrics:

Args:
meter: OpenTelemetry Meter
label_set: OpenTelemetry label set
labels: Dictionary of labels
"""

def __init__(self, meter: Meter, label_set: LabelSet):
def __init__(self, meter: Meter, labels: Dict[str, str]):
self._meter = meter
self._label_set = label_set
self._labels = labels
# Create performance metrics
meter.register_observer(
callback=self._track_cpu,
Expand Down Expand Up @@ -63,15 +63,15 @@ def _track_cpu(self, observer) -> None:
from 0.0 to 100.0 inclusive.
"""
cpu_times_percent = psutil.cpu_times_percent()
observer.observe(100.0 - cpu_times_percent.idle, self._label_set)
observer.observe(100.0 - cpu_times_percent.idle, self._labels)

def _track_memory(self, observer) -> None:
""" Track Memory

Available memory is defined as memory that can be given instantly to
processes without the system going into swap.
"""
observer.observe(psutil.virtual_memory().available, self._label_set)
observer.observe(psutil.virtual_memory().available, self._labels)

def _track_process_cpu(self, observer) -> None:
""" Track Process CPU time
Expand All @@ -84,9 +84,7 @@ def _track_process_cpu(self, observer) -> None:
# CPU cores, the returned value of cpu_percent() can be > 100.0. We
# normalize the cpu process using the number of logical CPUs
cpu_count = psutil.cpu_count(logical=True)
observer.observe(
PROCESS.cpu_percent() / cpu_count, self._label_set
)
observer.observe(PROCESS.cpu_percent() / cpu_count, self._labels)
except Exception: # pylint: disable=broad-except
logger.exception("Error handling get process cpu usage.")

Expand All @@ -97,6 +95,6 @@ def _track_process_memory(self, observer) -> None:
processes without the system going into swap.
"""
try:
observer.observe(PROCESS.memory_info().rss, self._label_set)
observer.observe(PROCESS.memory_info().rss, self._labels)
except Exception: # pylint: disable=broad-except
logger.exception("Error handling get process private bytes.")
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import threading
import time
from http.server import HTTPServer
from typing import Dict

from opentelemetry.metrics import LabelSet, Meter
from opentelemetry.metrics import Meter

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -59,12 +60,12 @@ class RequestMetrics:

Args:
meter: OpenTelemetry Meter
label_set: OpenTelemetry label set
labels: Dictionary of labels
"""

def __init__(self, meter: Meter, label_set: LabelSet):
def __init__(self, meter: Meter, labels: Dict[str, str]):
self._meter = meter
self._label_set = label_set
self._labels = labels
# Patch the HTTPServer handler to track request information
HTTPServer.__init__ = server_patch

Expand Down Expand Up @@ -102,13 +103,11 @@ def _track_request_duration(self, observer) -> None:
requests_map["last_average_duration"] = result
requests_map["last_duration"] = requests_map.get("duration", 0)
# Convert to milliseconds
observer.observe(int(result * 1000.0), self._label_set)
observer.observe(int(result * 1000.0), self._labels)
except ZeroDivisionError:
# If interval_count is 0, exporter call made too close to previous
# Return the previous result if this is the case
observer.observe(
int(last_average_duration * 1000.0), self._label_set
)
observer.observe(int(last_average_duration * 1000.0), self._labels)

def _track_request_rate(self, observer) -> None:
""" Track Request execution rate
Expand All @@ -134,8 +133,8 @@ def _track_request_rate(self, observer) -> None:
requests_map["last_time"] = current_time
requests_map["last_count"] = requests_map.get("count", 0)
requests_map["last_rate"] = result
observer.observe(int(result), self._label_set)
observer.observe(int(result), self._labels)
except ZeroDivisionError:
# If elapsed_seconds is 0, exporter call made too close to previous
# Return the previous result if this is the case
observer.observe(int(last_rate), self._label_set)
observer.observe(int(last_rate), self._labels)
17 changes: 10 additions & 7 deletions azure_monitor/src/azure_monitor/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,24 +187,27 @@ def put(self, data, lease_period=0, silent=False):

def _check_storage_size(self):
size = 0
# pylint: disable=unused-variable
for dirpath, dirnames, filenames in os.walk(self.path):
for f in filenames:
fp = os.path.join(dirpath, f)
for filename in filenames:
path = os.path.join(dirpath, filename)
# skip if it is symbolic link
if not os.path.islink(fp):
if not os.path.islink(path):
try:
size += os.path.getsize(fp)
size += os.path.getsize(path)
except OSError:
logger.error("Path %s does not exist or is "
"inaccessible.", fp)
logger.error(
"Path %s does not exist or is " "inaccessible.",
path,
)
continue
if size >= self.max_size:
logger.warning(
"Persistent storage max capacity has been "
"reached. Currently at %fKB. Telemetry will be "
"lost. Please consider increasing the value of "
"'storage_max_size' in exporter config.",
format(size/1024)
format(size / 1024),
)
return False
return True
15 changes: 5 additions & 10 deletions azure_monitor/tests/auto_collection/test_auto_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ class TestAutoCollection(unittest.TestCase):
def setUpClass(cls):
metrics.set_meter_provider(MeterProvider())
cls._meter = metrics.get_meter(__name__)
kvp = {"environment": "staging"}
cls._test_label_set = cls._meter.get_label_set(kvp)
cls._test_labels = tuple({"environment": "staging"}.items())

@classmethod
def tearDownClass(cls):
Expand All @@ -36,17 +35,13 @@ def test_constructor(
self, mock_performance, mock_dependencies, mock_requests
):
"""Test the constructor."""
AutoCollection(meter=self._meter, label_set=self._test_label_set)
AutoCollection(meter=self._meter, labels=self._test_labels)
self.assertEqual(mock_performance.called, True)
self.assertEqual(mock_dependencies.called, True)
self.assertEqual(mock_requests.called, True)
self.assertEqual(mock_performance.call_args[0][0], self._meter)
self.assertEqual(
mock_performance.call_args[0][1], self._test_label_set
)
self.assertEqual(mock_performance.call_args[0][1], self._test_labels)
self.assertEqual(mock_dependencies.call_args[0][0], self._meter)
self.assertEqual(
mock_dependencies.call_args[0][1], self._test_label_set
)
self.assertEqual(mock_dependencies.call_args[0][1], self._test_labels)
self.assertEqual(mock_requests.call_args[0][0], self._meter)
self.assertEqual(mock_requests.call_args[0][1], self._test_label_set)
self.assertEqual(mock_requests.call_args[0][1], self._test_labels)