diff --git a/docs/parsers/mpstat.md b/docs/parsers/mpstat.md index a6653e40..c16f5ab0 100644 --- a/docs/parsers/mpstat.md +++ b/docs/parsers/mpstat.md @@ -27,6 +27,7 @@ Schema: "type": string, "time": string, "cpu": string, + "node": string, "average": boolean, "percent_usr": float, "percent_nice": float, @@ -64,6 +65,7 @@ Schema: "net_tx_s": float, "net_rx_s": float, "block_s": float, + "irq_poll_s": float, "block_iopoll_s": float, "tasklet_s": float, "sched_s": float, diff --git a/docs/parsers/mpstat_s.md b/docs/parsers/mpstat_s.md index 25fe3b03..1762010e 100644 --- a/docs/parsers/mpstat_s.md +++ b/docs/parsers/mpstat_s.md @@ -28,6 +28,7 @@ Schema: "type": string, "time": string, "cpu": string, + "node": string, "average": boolean, "percent_usr": float, "percent_nice": float, @@ -65,6 +66,7 @@ Schema: "net_tx_s": float, "net_rx_s": float, "block_s": float, + "irq_poll_s": float, "block_iopoll_s": float, "tasklet_s": float, "sched_s": float, diff --git a/jc/parsers/mpstat.py b/jc/parsers/mpstat.py index 93764713..1e5116e3 100644 --- a/jc/parsers/mpstat.py +++ b/jc/parsers/mpstat.py @@ -22,6 +22,7 @@ Schema: "type": string, "time": string, "cpu": string, + "node": string, "average": boolean, "percent_usr": float, "percent_nice": float, @@ -59,6 +60,7 @@ Schema: "net_tx_s": float, "net_rx_s": float, "block_s": float, + "irq_poll_s": float, "block_iopoll_s": float, "tasklet_s": float, "sched_s": float, @@ -142,8 +144,8 @@ def _process(proc_data: List[Dict]) -> List[Dict]: "percent_soft", "percent_steal", "percent_guest", "percent_gnice", "percent_idle", "intr_s", "nmi_s", "loc_s", "spu_s", "pmi_s", "iwi_s", "rtr_s", "res_s", "cal_s", "tlb_s", "trm_s", "thr_s", "dfr_s", "mce_s", "mcp_s", "err_s", "mis_s", "pin_s", "npi_s", "piw_s", "hi_s", - "timer_s", "net_tx_s", "net_rx_s", "block_s", "block_iopoll_s", "tasklet_s", "sched_s", - "hrtimer_s", "rcu_s" + "timer_s", "net_tx_s", "net_rx_s", "block_s", "irq_poll_s", "block_iopoll_s", "tasklet_s", + "sched_s", "hrtimer_s", "rcu_s" ] for entry in proc_data: for key in entry: @@ -185,7 +187,7 @@ def parse( for line in filter(None, data.splitlines()): # check for header, normalize it, and fix the time column - if ' CPU ' in line: + if ' CPU ' in line or ' NODE ' in line: header_found = True if '%usr' in line: stat_type = 'cpu' @@ -196,6 +198,10 @@ def parse( .replace('%', 'percent_')\ .lower() header_start = line.find('CPU ') + + if header_start == -1: + header_start = line.find('NODE ') + header_text = header_text[header_start:] continue diff --git a/jc/parsers/mpstat_s.py b/jc/parsers/mpstat_s.py index 9c5d7c0c..6b192439 100644 --- a/jc/parsers/mpstat_s.py +++ b/jc/parsers/mpstat_s.py @@ -23,6 +23,7 @@ Schema: "type": string, "time": string, "cpu": string, + "node": string, "average": boolean, "percent_usr": float, "percent_nice": float, @@ -60,6 +61,7 @@ Schema: "net_tx_s": float, "net_rx_s": float, "block_s": float, + "irq_poll_s": float, "block_iopoll_s": float, "tasklet_s": float, "sched_s": float, @@ -127,8 +129,8 @@ def _process(proc_data: Dict) -> Dict: "percent_soft", "percent_steal", "percent_guest", "percent_gnice", "percent_idle", "intr_s", "nmi_s", "loc_s", "spu_s", "pmi_s", "iwi_s", "rtr_s", "res_s", "cal_s", "tlb_s", "trm_s", "thr_s", "dfr_s", "mce_s", "mcp_s", "err_s", "mis_s", "pin_s", "npi_s", "piw_s", "hi_s", - "timer_s", "net_tx_s", "net_rx_s", "block_s", "block_iopoll_s", "tasklet_s", "sched_s", - "hrtimer_s", "rcu_s" + "timer_s", "net_tx_s", "net_rx_s", "block_s", "irq_poll_s", "block_iopoll_s", "tasklet_s", + "sched_s", "hrtimer_s", "rcu_s" ] for key in proc_data: if (key in float_list or (key[0].isdigit() and key.endswith('_s'))): @@ -180,7 +182,7 @@ def parse( output_line: Dict = {} # check for header, normalize it, and fix the time column - if ' CPU ' in line: + if ' CPU ' in line or ' NODE ' in line: header_found = True if '%usr' in line: stat_type = 'cpu' @@ -191,6 +193,10 @@ def parse( .replace('%', 'percent_')\ .lower() header_start = line.find('CPU ') + + if header_start == -1: + header_start = line.find('NODE ') + header_text = header_text[header_start:] continue diff --git a/tests/fixtures/ubuntu-18.04/mpstat-A-streaming.json b/tests/fixtures/ubuntu-18.04/mpstat-A-streaming.json new file mode 100644 index 00000000..e781d158 --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/mpstat-A-streaming.json @@ -0,0 +1 @@ +[{"cpu":"all","percent_usr":26.15,"percent_nice":8.92,"percent_sys":32.36,"percent_iowait":1.39,"percent_irq":0.0,"percent_soft":2.09,"percent_steal":0.0,"percent_guest":0.0,"percent_gnice":0.0,"percent_idle":29.09,"type":"cpu","time":"08:50:55 AM"},{"cpu":"0","percent_usr":26.15,"percent_nice":8.92,"percent_sys":32.36,"percent_iowait":1.39,"percent_irq":0.0,"percent_soft":2.09,"percent_steal":0.0,"percent_guest":0.0,"percent_gnice":0.0,"percent_idle":29.09,"type":"cpu","time":"08:50:55 AM"},{"node":"all","percent_usr":26.15,"percent_nice":8.92,"percent_sys":32.36,"percent_iowait":1.39,"percent_irq":0.0,"percent_soft":2.09,"percent_steal":0.0,"percent_guest":0.0,"percent_gnice":0.0,"percent_idle":29.09,"type":"cpu","time":"08:50:55 AM"},{"node":"0","percent_usr":26.15,"percent_nice":8.92,"percent_sys":32.36,"percent_iowait":1.39,"percent_irq":0.0,"percent_soft":2.09,"percent_steal":0.0,"percent_guest":0.0,"percent_gnice":0.0,"percent_idle":29.09,"type":"cpu","time":"08:50:55 AM"},{"cpu":"all","intr_s":1301.92,"type":"interrupts","time":"08:50:55 AM"},{"cpu":"0","intr_s":1973.0,"type":"interrupts","time":"08:50:55 AM"},{"cpu":"0","0_s":0.12,"1_s":0.69,"4_s":1.08,"6_s":0.06,"8_s":0.01,"9_s":0.0,"12_s":0.97,"14_s":0.0,"15_s":0.0,"16_s":0.0,"17_s":160.05,"18_s":2.56,"19_s":469.15,"24_s":0.0,"25_s":0.0,"26_s":0.0,"27_s":0.0,"28_s":0.0,"29_s":0.0,"30_s":0.0,"31_s":0.0,"32_s":0.0,"33_s":0.0,"34_s":0.0,"35_s":0.0,"36_s":0.0,"37_s":0.0,"38_s":0.0,"39_s":0.0,"40_s":0.0,"41_s":0.0,"42_s":0.0,"43_s":0.0,"44_s":0.0,"45_s":0.0,"46_s":0.0,"47_s":0.0,"48_s":0.0,"49_s":0.0,"50_s":0.0,"51_s":0.0,"52_s":0.0,"53_s":0.0,"54_s":0.0,"55_s":0.0,"56_s":27.16,"57_s":0.47,"58_s":0.0,"nmi_s":0.0,"loc_s":639.59,"spu_s":0.0,"pmi_s":0.0,"iwi_s":0.0,"rtr_s":0.0,"res_s":0.0,"cal_s":0.0,"tlb_s":0.0,"trm_s":0.0,"thr_s":0.0,"dfr_s":0.0,"mce_s":0.0,"mcp_s":0.01,"err_s":0.0,"mis_s":0.0,"pin_s":0.0,"npi_s":0.0,"piw_s":0.0,"type":"interrupts","time":"08:50:55 AM"},{"cpu":"0","hi_s":0.01,"timer_s":189.73,"net_tx_s":0.23,"net_rx_s":470.58,"block_s":176.49,"irq_poll_s":0.0,"tasklet_s":1.73,"sched_s":0.0,"hrtimer_s":0.0,"rcu_s":1134.22,"type":"interrupts","time":"08:50:55 AM"}] diff --git a/tests/fixtures/ubuntu-18.04/mpstat-A.json b/tests/fixtures/ubuntu-18.04/mpstat-A.json new file mode 100644 index 00000000..e781d158 --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/mpstat-A.json @@ -0,0 +1 @@ +[{"cpu":"all","percent_usr":26.15,"percent_nice":8.92,"percent_sys":32.36,"percent_iowait":1.39,"percent_irq":0.0,"percent_soft":2.09,"percent_steal":0.0,"percent_guest":0.0,"percent_gnice":0.0,"percent_idle":29.09,"type":"cpu","time":"08:50:55 AM"},{"cpu":"0","percent_usr":26.15,"percent_nice":8.92,"percent_sys":32.36,"percent_iowait":1.39,"percent_irq":0.0,"percent_soft":2.09,"percent_steal":0.0,"percent_guest":0.0,"percent_gnice":0.0,"percent_idle":29.09,"type":"cpu","time":"08:50:55 AM"},{"node":"all","percent_usr":26.15,"percent_nice":8.92,"percent_sys":32.36,"percent_iowait":1.39,"percent_irq":0.0,"percent_soft":2.09,"percent_steal":0.0,"percent_guest":0.0,"percent_gnice":0.0,"percent_idle":29.09,"type":"cpu","time":"08:50:55 AM"},{"node":"0","percent_usr":26.15,"percent_nice":8.92,"percent_sys":32.36,"percent_iowait":1.39,"percent_irq":0.0,"percent_soft":2.09,"percent_steal":0.0,"percent_guest":0.0,"percent_gnice":0.0,"percent_idle":29.09,"type":"cpu","time":"08:50:55 AM"},{"cpu":"all","intr_s":1301.92,"type":"interrupts","time":"08:50:55 AM"},{"cpu":"0","intr_s":1973.0,"type":"interrupts","time":"08:50:55 AM"},{"cpu":"0","0_s":0.12,"1_s":0.69,"4_s":1.08,"6_s":0.06,"8_s":0.01,"9_s":0.0,"12_s":0.97,"14_s":0.0,"15_s":0.0,"16_s":0.0,"17_s":160.05,"18_s":2.56,"19_s":469.15,"24_s":0.0,"25_s":0.0,"26_s":0.0,"27_s":0.0,"28_s":0.0,"29_s":0.0,"30_s":0.0,"31_s":0.0,"32_s":0.0,"33_s":0.0,"34_s":0.0,"35_s":0.0,"36_s":0.0,"37_s":0.0,"38_s":0.0,"39_s":0.0,"40_s":0.0,"41_s":0.0,"42_s":0.0,"43_s":0.0,"44_s":0.0,"45_s":0.0,"46_s":0.0,"47_s":0.0,"48_s":0.0,"49_s":0.0,"50_s":0.0,"51_s":0.0,"52_s":0.0,"53_s":0.0,"54_s":0.0,"55_s":0.0,"56_s":27.16,"57_s":0.47,"58_s":0.0,"nmi_s":0.0,"loc_s":639.59,"spu_s":0.0,"pmi_s":0.0,"iwi_s":0.0,"rtr_s":0.0,"res_s":0.0,"cal_s":0.0,"tlb_s":0.0,"trm_s":0.0,"thr_s":0.0,"dfr_s":0.0,"mce_s":0.0,"mcp_s":0.01,"err_s":0.0,"mis_s":0.0,"pin_s":0.0,"npi_s":0.0,"piw_s":0.0,"type":"interrupts","time":"08:50:55 AM"},{"cpu":"0","hi_s":0.01,"timer_s":189.73,"net_tx_s":0.23,"net_rx_s":470.58,"block_s":176.49,"irq_poll_s":0.0,"tasklet_s":1.73,"sched_s":0.0,"hrtimer_s":0.0,"rcu_s":1134.22,"type":"interrupts","time":"08:50:55 AM"}] diff --git a/tests/fixtures/ubuntu-18.04/mpstat-A.out b/tests/fixtures/ubuntu-18.04/mpstat-A.out new file mode 100644 index 00000000..d8b36aa1 --- /dev/null +++ b/tests/fixtures/ubuntu-18.04/mpstat-A.out @@ -0,0 +1,19 @@ +Linux 4.15.0-169-generic (kbrazil-ubuntu) 03/14/2022 _x86_64_ (1 CPU) + +08:50:55 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle +08:50:55 AM all 26.15 8.92 32.36 1.39 0.00 2.09 0.00 0.00 0.00 29.09 +08:50:55 AM 0 26.15 8.92 32.36 1.39 0.00 2.09 0.00 0.00 0.00 29.09 + +08:50:55 AM NODE %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle +08:50:55 AM all 26.15 8.92 32.36 1.39 0.00 2.09 0.00 0.00 0.00 29.09 +08:50:55 AM 0 26.15 8.92 32.36 1.39 0.00 2.09 0.00 0.00 0.00 29.09 + +08:50:55 AM CPU intr/s +08:50:55 AM all 1301.92 +08:50:55 AM 0 1973.00 + +08:50:55 AM CPU 0/s 1/s 4/s 6/s 8/s 9/s 12/s 14/s 15/s 16/s 17/s 18/s 19/s 24/s 25/s 26/s 27/s 28/s 29/s 30/s 31/s 32/s 33/s 34/s 35/s 36/s 37/s 38/s 39/s 40/s 41/s 42/s 43/s 44/s 45/s 46/s 47/s 48/s 49/s 50/s 51/s 52/s 53/s 54/s 55/s 56/s 57/s 58/s NMI/s LOC/s SPU/s PMI/s IWI/s RTR/s RES/s CAL/s TLB/s TRM/s THR/s DFR/s MCE/s MCP/s ERR/s MIS/s PIN/s NPI/s PIW/s +08:50:55 AM 0 0.12 0.69 1.08 0.06 0.01 0.00 0.97 0.00 0.00 0.00 160.05 2.56 469.15 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 27.16 0.47 0.00 0.00 639.59 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.01 0.00 0.00 0.00 0.00 0.00 + +08:50:55 AM CPU HI/s TIMER/s NET_TX/s NET_RX/s BLOCK/s IRQ_POLL/s TASKLET/s SCHED/s HRTIMER/s RCU/s +08:50:55 AM 0 0.01 189.73 0.23 470.58 176.49 0.00 1.73 0.00 0.00 1134.22 diff --git a/tests/test_mpstat.py b/tests/test_mpstat.py index de22950e..389562e9 100644 --- a/tests/test_mpstat.py +++ b/tests/test_mpstat.py @@ -19,6 +19,9 @@ class MyTests(unittest.TestCase): with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/mpstat-A-2-5.out'), 'r', encoding='utf-8') as f: self.centos_7_7_mpstat_A_2_5 = f.read() + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/mpstat-A.out'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_mpstat_A = f.read() + # output with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/mpstat.json'), 'r', encoding='utf-8') as f: self.centos_7_7_mpstat_json = json.loads(f.read()) @@ -29,6 +32,9 @@ class MyTests(unittest.TestCase): with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/mpstat-A-2-5.json'), 'r', encoding='utf-8') as f: self.centos_7_7_mpstat_A_2_5_json = json.loads(f.read()) + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/mpstat-A.json'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_mpstat_A_json = json.loads(f.read()) + def test_mpstat_nodata(self): """ @@ -54,6 +60,12 @@ class MyTests(unittest.TestCase): """ self.assertEqual(jc.parsers.mpstat.parse(self.centos_7_7_mpstat_A_2_5, quiet=True), self.centos_7_7_mpstat_A_2_5_json) + def test_mpstat_A_ubuntu_18_4(self): + """ + Test 'mpstat -A' on Ubuntu 18.4 + """ + self.assertEqual(jc.parsers.mpstat.parse(self.ubuntu_18_4_mpstat_A, quiet=True), self.ubuntu_18_4_mpstat_A_json) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_mpstat_s.py b/tests/test_mpstat_s.py index 39de208d..8d097f39 100644 --- a/tests/test_mpstat_s.py +++ b/tests/test_mpstat_s.py @@ -23,6 +23,9 @@ class MyTests(unittest.TestCase): with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/mpstat-A-2-5.out'), 'r', encoding='utf-8') as f: self.centos_7_7_mpstat_A_2_5 = f.read() + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/mpstat-A.out'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_mpstat_A = f.read() + # output with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/mpstat-streaming.json'), 'r', encoding='utf-8') as f: self.centos_7_7_mpstat_streaming_json = json.loads(f.read()) @@ -33,6 +36,9 @@ class MyTests(unittest.TestCase): with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/mpstat-A-2-5-streaming.json'), 'r', encoding='utf-8') as f: self.centos_7_7_mpstat_A_2_5_streaming_json = json.loads(f.read()) + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/ubuntu-18.04/mpstat-A-streaming.json'), 'r', encoding='utf-8') as f: + self.ubuntu_18_4_mpstat_A_streaming_json = json.loads(f.read()) + def test_mpstat_s_nodata(self): """ Test 'mpstat' with no data @@ -57,6 +63,12 @@ class MyTests(unittest.TestCase): """ self.assertEqual(list(jc.parsers.mpstat_s.parse(self.centos_7_7_mpstat_A_2_5.splitlines(), quiet=True)), self.centos_7_7_mpstat_A_2_5_streaming_json) + def test_mpstat_s_A_ubuntu_18_4(self): + """ + Test 'mpstat -A' on Ubuntu 18.4 + """ + self.assertEqual(list(jc.parsers.mpstat_s.parse(self.ubuntu_18_4_mpstat_A.splitlines(), quiet=True)), self.ubuntu_18_4_mpstat_A_streaming_json) + if __name__ == '__main__': unittest.main()