Skip to content

Commit bf3c90d

Browse files
committed
opentelemetry-instrumentation-system-metrics: fix running on Google Cloud Run
psutil fails reading context switches fails on Google Cloud Run, so before setting up the observable counter trying to read the values check we are actually being able to do so.
1 parent 71bfc95 commit bf3c90d

File tree

3 files changed

+57
-2
lines changed

3 files changed

+57
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Fixed
1515

16+
- `opentelemetry-instrumentation-system-metrics`: fix loading on Google Cloud Run
17+
([#3533](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3533))
1618
- `opentelemetry-instrumentation-fastapi`: fix wrapping of middlewares
1719
([#3012](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3012))
1820

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,10 @@ def _instrument(self, **kwargs: Any):
395395
self._meter, callbacks=[self._get_cpu_utilization]
396396
)
397397

398-
if "process.context_switches" in self._config:
398+
if (
399+
"process.context_switches" in self._config
400+
and self._can_read_context_switches()
401+
):
399402
self._meter.create_observable_counter(
400403
name="process.context_switches",
401404
callbacks=[self._get_context_switches],
@@ -482,7 +485,10 @@ def _instrument(self, **kwargs: Any):
482485
unit="1",
483486
)
484487

485-
if "process.runtime.context_switches" in self._config:
488+
if (
489+
"process.runtime.context_switches" in self._config
490+
and self._can_read_context_switches()
491+
):
486492
self._meter.create_observable_counter(
487493
name=f"process.runtime.{self._python_implementation}.context_switches",
488494
callbacks=[self._get_runtime_context_switches],
@@ -493,6 +499,14 @@ def _instrument(self, **kwargs: Any):
493499
def _uninstrument(self, **kwargs: Any):
494500
pass
495501

502+
def _can_read_context_switches(self) -> bool:
503+
"""On Google Cloud Run psutil is not able to read context switches, catch it before creating the observable instrument"""
504+
try:
505+
self._proc.num_ctx_switches()
506+
return True
507+
except NotImplementedError:
508+
return False
509+
496510
def _get_open_file_descriptors(
497511
self, options: CallbackOptions
498512
) -> Iterable[Observation]:

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,24 @@ def test_context_switches(self, mock_process_num_ctx_switches):
855855
]
856856
self._test_metrics("process.context_switches", expected)
857857

858+
@mock.patch("psutil.Process.num_ctx_switches")
859+
def test_context_switches_not_implemented_error(
860+
self, mock_process_num_ctx_switches
861+
):
862+
mock_process_num_ctx_switches.side_effect = NotImplementedError
863+
864+
reader = InMemoryMetricReader()
865+
meter_provider = MeterProvider(metric_readers=[reader])
866+
system_metrics = SystemMetricsInstrumentor()
867+
system_metrics.instrument(meter_provider=meter_provider)
868+
869+
seen_metrics = set()
870+
for resource_metrics in reader.get_metrics_data().resource_metrics:
871+
for scope_metrics in resource_metrics.scope_metrics:
872+
for metric in scope_metrics.metrics:
873+
seen_metrics.add(metric.name)
874+
self.assertNotIn("process.context_switches", seen_metrics)
875+
858876
@mock.patch("psutil.Process.num_threads")
859877
def test_thread_count(self, mock_process_thread_num):
860878
mock_process_thread_num.configure_mock(**{"return_value": 42})
@@ -947,6 +965,27 @@ def test_runtime_context_switches(self, mock_process_num_ctx_switches):
947965
f"process.runtime.{self.implementation}.context_switches", expected
948966
)
949967

968+
@mock.patch("psutil.Process.num_ctx_switches")
969+
def test_runtime_context_switches_not_implemented_error(
970+
self, mock_process_num_ctx_switches
971+
):
972+
mock_process_num_ctx_switches.side_effect = NotImplementedError
973+
974+
reader = InMemoryMetricReader()
975+
meter_provider = MeterProvider(metric_readers=[reader])
976+
system_metrics = SystemMetricsInstrumentor()
977+
system_metrics.instrument(meter_provider=meter_provider)
978+
979+
seen_metrics = set()
980+
for resource_metrics in reader.get_metrics_data().resource_metrics:
981+
for scope_metrics in resource_metrics.scope_metrics:
982+
for metric in scope_metrics.metrics:
983+
seen_metrics.add(metric.name)
984+
self.assertNotIn(
985+
f"process.runtime.{self.implementation}.context_switches",
986+
seen_metrics,
987+
)
988+
950989
@mock.patch("psutil.Process.num_threads")
951990
def test_runtime_thread_count(self, mock_process_thread_num):
952991
mock_process_thread_num.configure_mock(**{"return_value": 42})

0 commit comments

Comments
 (0)