scripts: sysmon: add thread count metric

BUG=b:255782067
TEST=Ran the unit test.

Change-Id: If961c0beca90df44f0342af5c4b45bc1c43b6066
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/4242243
Auto-Submit: Congbin Guo <guocb@chromium.org>
Commit-Queue: Sergey Fetisov <sfetisov@google.com>
Reviewed-by: Sergey Fetisov <sfetisov@google.com>
Tested-by: Congbin Guo <guocb@chromium.org>
diff --git a/scripts/sysmon/proc_metrics.py b/scripts/sysmon/proc_metrics.py
index 6f5e0c5..25719db 100644
--- a/scripts/sysmon/proc_metrics.py
+++ b/scripts/sysmon/proc_metrics.py
@@ -19,6 +19,9 @@
 _count_metric = metrics.GaugeMetric(
     "proc/count", description="Number of processes currently running."
 )
+_thread_count_metric = metrics.GaugeMetric(
+    "proc/thread_count", description="Number of threads currently running."
+)
 _cpu_percent_metric = metrics.GaugeMetric(
     "proc/cpu_percent", description="CPU usage percent of processes."
 )
@@ -121,6 +124,7 @@
         }
         self._test_func = test_func
         self._count = 0
+        self._thread_count = 0
         self._cpu_percent = 0
 
     def add(self, proc):
@@ -131,6 +135,7 @@
         if not self._test_func(proc):
             return False
         self._count += 1
+        self._thread_count += proc.num_threads()
         self._cpu_percent += proc.cpu_percent()
         return True
 
@@ -138,6 +143,10 @@
         """Finish collection and send metrics."""
         _count_metric.set(self._count, fields=self._fields)
         self._count = 0
+
+        _thread_count_metric.set(self._thread_count, fields=self._fields)
+        self._thread_count = 0
+
         _cpu_percent_metric.set(
             int(round(self._cpu_percent)), fields=self._fields
         )
diff --git a/scripts/sysmon/proc_metrics_unittest.py b/scripts/sysmon/proc_metrics_unittest.py
index 5b45462..f5bdbbe 100644
--- a/scripts/sysmon/proc_metrics_unittest.py
+++ b/scripts/sysmon/proc_metrics_unittest.py
@@ -16,10 +16,11 @@
 from chromite.scripts.sysmon import proc_metrics
 
 
-def _mock_process(name, cmdline, parent=None):
+def _mock_process(name, cmdline, parent=None, num_threads=10):
     proc = mock.Mock(dir(psutil.Process))
     proc.name.return_value = name
     proc.cmdline.return_value = cmdline
+    proc.num_threads.return_value = num_threads
     proc.cpu_percent.return_value = 2
     if parent is not None:
         proc.parent.return_value = parent
@@ -35,6 +36,7 @@
     """Return expected calls for a process metric."""
     return [
         mock.call("proc/count", (name,), None, 1, enforce_ge=mock.ANY),
+        mock.call("proc/thread_count", (name,), None, 10, enforce_ge=mock.ANY),
         mock.call("proc/cpu_percent", (name,), None, 2, enforce_ge=mock.ANY),
     ]