From 6f6028a1f45d4aecf8ed58fc53e960a631b32717 Mon Sep 17 00:00:00 2001 From: Yulin Li Date: Sun, 18 Sep 2022 17:05:19 +0800 Subject: [PATCH 1/7] collect threads count in opentelemetry-instrumentation-system-metrics --- .../system_metrics/__init__.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py index d0cd10739c..8d806e8b6f 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py @@ -42,7 +42,8 @@ "system.network.connections": ["family", "type"], "runtime.memory": ["rss", "vms"], "runtime.cpu.time": ["user", "system"], - "runtime.gc_count": None + "runtime.gc_count": None, + "runtime.threading.active_count": None } Usage @@ -80,6 +81,7 @@ import gc import os +import threading from platform import python_implementation from typing import Collection, Dict, Iterable, List, Optional @@ -118,6 +120,7 @@ "runtime.memory": ["rss", "vms"], "runtime.cpu.time": ["user", "system"], "runtime.gc_count": None, + "runtime.threading.active_count": None, } @@ -168,6 +171,7 @@ def __init__( self._runtime_memory_labels = self._labels.copy() self._runtime_cpu_time_labels = self._labels.copy() self._runtime_gc_count_labels = self._labels.copy() + self._runtime_threading_active_count_labels = self._labels.copy() def instrumentation_dependencies(self) -> Collection[str]: return _instruments @@ -415,6 +419,14 @@ def _instrument(self, **kwargs): unit="bytes", ) + if "runtime.threading.active_count" in self._config: + self._meter.create_observable_gauge( + name=f"runtime.{self._python_implementation}.threading.active_count", + callbacks=[self._get_runtime_threading_active_count], + description=f"Runtime {self._python_implementation} active threads count", + unit="threads", + ) + def _uninstrument(self, **__): pass @@ -747,3 +759,11 @@ def _get_runtime_gc_count( for index, count in enumerate(gc.get_count()): self._runtime_gc_count_labels["count"] = str(index) yield Observation(count, self._runtime_gc_count_labels.copy()) + + def _get_runtime_threading_active_count( + self, options: CallbackOptions + ) -> Iterable[Observation]: + """Observer callback for threading active count""" + yield Observation( + threading.active_count(), self._runtime_threading_active_count_labels + ) \ No newline at end of file From 36e76e4b5aff25b5f0813e2586847d88ab360c55 Mon Sep 17 00:00:00 2001 From: Yulin Li Date: Sun, 18 Sep 2022 18:17:14 +0800 Subject: [PATCH 2/7] update --- .../system_metrics/__init__.py | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py index 8d806e8b6f..6df1d3ac46 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py @@ -40,10 +40,10 @@ "system.network.io.transmit": None, "system.network.io.receive": None, "system.network.connections": ["family", "type"], + "system.threading.active_count": None "runtime.memory": ["rss", "vms"], "runtime.cpu.time": ["user", "system"], - "runtime.gc_count": None, - "runtime.threading.active_count": None + "runtime.gc_count": None } Usage @@ -117,10 +117,10 @@ "system.network.io.transmit": None, "system.network.io.receive": None, "system.network.connections": ["family", "type"], + "system.threading.active_count": None, "runtime.memory": ["rss", "vms"], "runtime.cpu.time": ["user", "system"], "runtime.gc_count": None, - "runtime.threading.active_count": None, } @@ -168,10 +168,11 @@ def __init__( self._system_network_io_receive_labels = self._labels.copy() self._system_network_connections_labels = self._labels.copy() + self._system_threading_active_count_labels = self._labels.copy() + self._runtime_memory_labels = self._labels.copy() self._runtime_cpu_time_labels = self._labels.copy() self._runtime_gc_count_labels = self._labels.copy() - self._runtime_threading_active_count_labels = self._labels.copy() def instrumentation_dependencies(self) -> Collection[str]: return _instruments @@ -395,6 +396,13 @@ def _instrument(self, **kwargs): unit="connections", ) + if "system.threading.active_count" in self._config: + self._meter.create_observable_gauge( + name=f"system.threading.active_count", + callbacks=[self._get_system_threading_active_count], + description=f"System active threads count", + ) + if "runtime.memory" in self._config: self._meter.create_observable_counter( name=f"runtime.{self._python_implementation}.memory", @@ -419,14 +427,6 @@ def _instrument(self, **kwargs): unit="bytes", ) - if "runtime.threading.active_count" in self._config: - self._meter.create_observable_gauge( - name=f"runtime.{self._python_implementation}.threading.active_count", - callbacks=[self._get_runtime_threading_active_count], - description=f"Runtime {self._python_implementation} active threads count", - unit="threads", - ) - def _uninstrument(self, **__): pass @@ -726,6 +726,14 @@ def _get_system_network_connections( connection_counter["labels"], ) + def _get_system_threading_active_count( + self, options: CallbackOptions + ) -> Iterable[Observation]: + """Observer callback for active threads count""" + yield Observation( + threading.active_count(), self._system_threading_active_count_labels + ) + def _get_runtime_memory( self, options: CallbackOptions ) -> Iterable[Observation]: @@ -759,11 +767,3 @@ def _get_runtime_gc_count( for index, count in enumerate(gc.get_count()): self._runtime_gc_count_labels["count"] = str(index) yield Observation(count, self._runtime_gc_count_labels.copy()) - - def _get_runtime_threading_active_count( - self, options: CallbackOptions - ) -> Iterable[Observation]: - """Observer callback for threading active count""" - yield Observation( - threading.active_count(), self._runtime_threading_active_count_labels - ) \ No newline at end of file From 118eb9aae6f41c0c9e69c3d243ed0e9af89bc35f Mon Sep 17 00:00:00 2001 From: Yulin Li Date: Tue, 20 Sep 2022 22:18:36 +0800 Subject: [PATCH 3/7] avoid devidedByZero exception when sawp memory is 0 --- .../opentelemetry/instrumentation/system_metrics/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py index d0cd10739c..6f6c2be5eb 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py @@ -500,7 +500,7 @@ def _get_system_swap_utilization( if hasattr(system_swap, metric): self._system_swap_utilization_labels["state"] = metric yield Observation( - getattr(system_swap, metric) / system_swap.total, + getattr(system_swap, metric) / system_swap.total if system_swap.total else 0, self._system_swap_utilization_labels.copy(), ) From 87fa026828755d4fea699354655ee66330a77aeb Mon Sep 17 00:00:00 2001 From: Yulin Li Date: Wed, 28 Sep 2022 13:09:43 +0800 Subject: [PATCH 4/7] add ut --- .../instrumentation/system_metrics/__init__.py | 18 +++++++++--------- .../tests/test_system_metrics.py | 10 +++++++++- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py index 1410086bcf..4be69b0240 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py @@ -33,7 +33,7 @@ "system.network.errors": ["transmit", "receive"], "system.network.io": ["transmit", "receive"], "system.network.connections": ["family", "type"], - "system.threading.active_count": None + "system.thread_count": None "runtime.memory": ["rss", "vms"], "runtime.cpu.time": ["user", "system"], } @@ -101,7 +101,7 @@ "system.network.errors": ["transmit", "receive"], "system.network.io": ["transmit", "receive"], "system.network.connections": ["family", "type"], - "system.threading.active_count": None, + "system.thread_count": None, "runtime.memory": ["rss", "vms"], "runtime.cpu.time": ["user", "system"], "runtime.gc_count": None, @@ -145,7 +145,7 @@ def __init__( self._system_network_io_labels = self._labels.copy() self._system_network_connections_labels = self._labels.copy() - self._system_threading_active_count_labels = self._labels.copy() + self._system_thread_count_labels = self._labels.copy() self._runtime_memory_labels = self._labels.copy() self._runtime_cpu_time_labels = self._labels.copy() @@ -316,10 +316,10 @@ def _instrument(self, **kwargs): unit="connections", ) - if "system.threading.active_count" in self._config: + if "system.thread_count" in self._config: self._meter.create_observable_gauge( - name=f"system.threading.active_count", - callbacks=[self._get_system_threading_active_count], + name=f"system.thread_count", + callbacks=[self._get_system_thread_count], description=f"System active threads count", ) @@ -605,12 +605,12 @@ def _get_system_network_connections( connection_counter["labels"], ) - def _get_system_threading_active_count( + def _get_system_thread_count( self, options: CallbackOptions ) -> Iterable[Observation]: - """Observer callback for active threads count""" + """Observer callback for active thread count""" yield Observation( - threading.active_count(), self._system_threading_active_count_labels + threading.active_count(), self._system_thread_count_labels ) def _get_runtime_memory( diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/tests/test_system_metrics.py b/instrumentation/opentelemetry-instrumentation-system-metrics/tests/test_system_metrics.py index 04d7674dba..04df73dd9e 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/tests/test_system_metrics.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/tests/test_system_metrics.py @@ -75,7 +75,7 @@ def test_system_metrics_instrument(self): for scope_metrics in resource_metrics.scope_metrics: for metric in scope_metrics.metrics: metric_names.append(metric.name) - self.assertEqual(len(metric_names), 17) + self.assertEqual(len(metric_names), 18) observer_names = [ "system.cpu.time", @@ -92,6 +92,7 @@ def test_system_metrics_instrument(self): "system.network.errors", "system.network.io", "system.network.connections", + "system.thread_count", f"runtime.{self.implementation}.memory", f"runtime.{self.implementation}.cpu_time", f"runtime.{self.implementation}.gc_count", @@ -680,6 +681,13 @@ def test_system_network_connections(self, mock_net_connections): ] self._test_metrics("system.network.connections", expected) + @mock.patch("threading.active_count") + def test_system_thread_count(self, threading_active_count): + threading_active_count.return_value = 42 + + expected = [_SystemMetricsResult({}, 42)] + self._test_metrics("system.thread_count", expected) + @mock.patch("psutil.Process.memory_info") def test_runtime_memory(self, mock_process_memory_info): From 289c280386426e5b59f09e5298981de83f540fb9 Mon Sep 17 00:00:00 2001 From: Yulin Li Date: Wed, 28 Sep 2022 13:13:20 +0800 Subject: [PATCH 5/7] change log --- CHANGELOG.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dfee88d7b..c07bbb7444 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.13.0-0.34b0...HEAD) +### Added + +- `opentelemetry-instrumentation-system-metrics` add supports to collect system thread count. ([#1339](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1339)) + ## [1.13.0-0.34b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.13.0-0.34b0) - 2022-09-26 @@ -26,14 +30,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#1253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1253)) - Add metric instrumentation in starlette ([#1327](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1327)) - + ### Fixed - `opentelemetry-instrumentation-boto3sqs` Make propagation compatible with other SQS instrumentations, add 'messaging.url' span attribute, and fix missing package dependencies. - ([#1234](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1234)) + ([#1234](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1234)) - `opentelemetry-instrumentation-pymongo` Change span names to not contain queries but only database name and command name - ([#1247](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1247)) + ([#1247](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1247)) - restoring metrics in django framework ([#1208](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1208)) - `opentelemetry-instrumentation-aiohttp-client` Fix producing additional spans with each newly created ClientSession From 43cc49775097fa8b23039911c66a82cac24bbb0a Mon Sep 17 00:00:00 2001 From: Yulin Li Date: Wed, 28 Sep 2022 13:20:45 +0800 Subject: [PATCH 6/7] lint --- .../opentelemetry/instrumentation/system_metrics/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py index 4be69b0240..420bad5d66 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py @@ -318,9 +318,9 @@ def _instrument(self, **kwargs): if "system.thread_count" in self._config: self._meter.create_observable_gauge( - name=f"system.thread_count", + name="system.thread_count", callbacks=[self._get_system_thread_count], - description=f"System active threads count", + description="System active threads count", ) if "runtime.memory" in self._config: From 17f765e9944abda4ff590c7a79c5eb2a9698d6cb Mon Sep 17 00:00:00 2001 From: Yulin Li Date: Wed, 28 Sep 2022 13:30:41 +0800 Subject: [PATCH 7/7] lint --- .../tests/test_system_metrics.py | 1 + 1 file changed, 1 insertion(+) diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/tests/test_system_metrics.py b/instrumentation/opentelemetry-instrumentation-system-metrics/tests/test_system_metrics.py index 04df73dd9e..aadc834301 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/tests/test_system_metrics.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/tests/test_system_metrics.py @@ -51,6 +51,7 @@ def __init__(self, attributes, value) -> None: self.value = value +# pylint:disable=too-many-public-methods class TestSystemMetrics(TestBase): def setUp(self): super().setUp()