From f7d293aad8919605050d9c051c91cb1b9818a3a1 Mon Sep 17 00:00:00 2001 From: Didi Hoffmann Date: Wed, 25 Sep 2024 14:55:17 +0200 Subject: [PATCH 1/2] Removes NaN values --- power_logger.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/power_logger.py b/power_logger.py index 5c18fcd..612f747 100755 --- a/power_logger.py +++ b/power_logger.py @@ -22,6 +22,7 @@ import threading import logging import select +import math from datetime import timezone from pathlib import Path @@ -260,6 +261,19 @@ def find_top_processes(data: list, elapsed_ns:int): 'cputime_ns': ((p['cputime_ms_per_s'] * 1_000_000) / 1_000_000_000) * elapsed_ns, } +class RemoveNaNEncoder(json.JSONEncoder): + def encode(self, obj): + def remove_nan(o): + if isinstance(o, dict): + return {k: remove_nan(v) for k, v in o.items() + if not (isinstance(v, float) and math.isnan(v))} + elif isinstance(o, list): + return [remove_nan(v) for v in o + if not (isinstance(v, float) and math.isnan(v))] + else: + return o + cleaned_obj = remove_nan(obj) + return super(RemoveNaNEncoder, self).encode(cleaned_obj) def parse_powermetrics_output(output: str): global stats @@ -278,7 +292,7 @@ def parse_powermetrics_output(output: str): logging.error(f"XML Error:\n{data}") raise exc - compressed_data = zlib.compress(str(json.dumps(data)).encode()) + compressed_data = zlib.compress(str(json.dumps(data, cls=RemoveNaNEncoder)).encode()) compressed_data_str = base64.b64encode(compressed_data).decode() c.execute('INSERT INTO measurements (time, data, uploaded) VALUES (?, ?, 0)', From db8d740b61011470ada58feccc5ffba7ce35d4fb Mon Sep 17 00:00:00 2001 From: Didi Hoffmann Date: Thu, 26 Sep 2024 12:04:37 +0200 Subject: [PATCH 2/2] Now also checks the key --- power_logger.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/power_logger.py b/power_logger.py index 612f747..d9b7f49 100755 --- a/power_logger.py +++ b/power_logger.py @@ -265,8 +265,9 @@ class RemoveNaNEncoder(json.JSONEncoder): def encode(self, obj): def remove_nan(o): if isinstance(o, dict): - return {k: remove_nan(v) for k, v in o.items() - if not (isinstance(v, float) and math.isnan(v))} + return {remove_nan(k): remove_nan(v) for k, v in o.items() + if not ((isinstance(k, float) and math.isnan(k)) or + (isinstance(v, float) and math.isnan(v)))} elif isinstance(o, list): return [remove_nan(v) for v in o if not (isinstance(v, float) and math.isnan(v))] @@ -275,6 +276,8 @@ def remove_nan(o): cleaned_obj = remove_nan(obj) return super(RemoveNaNEncoder, self).encode(cleaned_obj) + + def parse_powermetrics_output(output: str): global stats