Skip to content

Commit 9c514f8

Browse files
committed
add gc_count metrics with correct collection unit .
fixes #3549
1 parent f9453b9 commit 9c514f8

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2525
([#3601](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3601))
2626

2727
### Fixed
28-
2928
- `opentelemetry-instrumentation-asgi`: fix excluded_urls in instrumentation-asgi
3029
([#3567](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3567))
3130
- `opentelemetry-resource-detector-containerid`: make it more quiet on platforms without cgroups
3231
([#3579](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3579))
32+
- `opentelemetry-instrumentation-system-metrics`: Add process.runtime.cpython.gc_count metrics with collection unit is specified in semconv ([3617](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3617))
3333

3434
## Version 1.34.0/0.55b0 (2025-06-04)
3535

instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ def __init__(
196196
self._runtime_memory_labels = self._labels.copy()
197197
self._runtime_cpu_time_labels = self._labels.copy()
198198
self._runtime_gc_count_labels = self._labels.copy()
199+
self._runtime_gc_collections_labels = self._labels.copy()
199200
self._runtime_thread_count_labels = self._labels.copy()
200201
self._runtime_cpu_utilization_labels = self._labels.copy()
201202
self._runtime_context_switches_labels = self._labels.copy()
@@ -469,6 +470,12 @@ def _instrument(self, **kwargs: Any):
469470
description=f"Runtime {self._python_implementation} GC count",
470471
unit="By",
471472
)
473+
self._meter.create_observable_counter(
474+
name=f"process.runtime.{self._python_implementation}.gc_count",
475+
callbacks=[self._get_runtime_gc_collections],
476+
description="The number of times a generation was collected since interpreter start.",
477+
unit="{collection}",
478+
)
472479

473480
if "process.runtime.thread_count" in self._config:
474481
self._meter.create_observable_up_down_counter(
@@ -885,6 +892,16 @@ def _get_runtime_gc_count(
885892
self._runtime_gc_count_labels["count"] = str(index)
886893
yield Observation(count, self._runtime_gc_count_labels.copy())
887894

895+
def _get_runtime_gc_collections(
896+
self, options: CallbackOptions
897+
) -> Iterable[Observation]:
898+
"""Observer callback for garbage collection"""
899+
for index, count in enumerate(gc.get_count()):
900+
self._runtime_gc_collections_labels["generation"] = str(index)
901+
yield Observation(
902+
count, self._runtime_gc_collections_labels.copy()
903+
)
904+
888905
def _get_runtime_thread_count(
889906
self, options: CallbackOptions
890907
) -> Iterable[Observation]:

instrumentation/opentelemetry-instrumentation-system-metrics/tests/test_system_metrics.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ def test_system_metrics_instrument(self):
136136
observer_names.append(
137137
f"process.runtime.{self.implementation}.gc_count",
138138
)
139+
observer_names.append(
140+
f"process.runtime.{self.implementation}.gc_count",
141+
)
139142
if sys.platform != "darwin":
140143
observer_names.append("system.network.connections")
141144

@@ -939,6 +942,32 @@ def test_runtime_cpu_time(self, mock_process_cpu_times):
939942
f"process.runtime.{self.implementation}.cpu_time", expected
940943
)
941944

945+
@mock.patch("gc.get_count")
946+
@skipIf(
947+
python_implementation().lower() == "pypy", "not supported for pypy"
948+
)
949+
def test_runtime_get_count(self, mock_gc_get_count):
950+
mock_gc_get_count.configure_mock(**{"return_value": (1, 2, 3)})
951+
952+
expected_gc_count = [
953+
_SystemMetricsResult({"count": "0"}, 1),
954+
_SystemMetricsResult({"count": "1"}, 2),
955+
_SystemMetricsResult({"count": "2"}, 3),
956+
]
957+
self._test_metrics(
958+
f"process.runtime.{self.implementation}.gc_count",
959+
expected_gc_count,
960+
)
961+
expected_gc_collections = [
962+
_SystemMetricsResult({"generation": "0"}, 1),
963+
_SystemMetricsResult({"generation": "1"}, 2),
964+
_SystemMetricsResult({"generation": "2"}, 3),
965+
]
966+
self._test_metrics(
967+
f"process.runtime.{self.implementation}.gc_collections",
968+
expected_gc_collections,
969+
)
970+
942971
@mock.patch("gc.get_count")
943972
@skipIf(
944973
python_implementation().lower() == "pypy", "not supported for pypy"

0 commit comments

Comments
 (0)