[libcamera-devel,1/3] utils: libtuning: Add logger
diff mbox series

Message ID 20221129053326.2858347-2-paul.elder@ideasonboard.com
State New
Headers show
Series
  • utils: tuning: Add logging infrastructure
Related show

Commit Message

Paul Elder Nov. 29, 2022, 5:33 a.m. UTC
Add logging infrastructure, so that log levels and files can be set, and
so that information can be logged from anywhere in libtuning easily and
concicely.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
---
 utils/tuning/libtuning/__init__.py |   1 +
 utils/tuning/libtuning/logger.py   | 105 +++++++++++++++++++++++++++++
 2 files changed, 106 insertions(+)
 create mode 100644 utils/tuning/libtuning/logger.py

Patch
diff mbox series

diff --git a/utils/tuning/libtuning/__init__.py b/utils/tuning/libtuning/__init__.py
index 93049976..5f0478ae 100644
--- a/utils/tuning/libtuning/__init__.py
+++ b/utils/tuning/libtuning/__init__.py
@@ -2,6 +2,7 @@ 
 #
 # Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com>
 
+from libtuning.logger import *
 from libtuning.utils import *
 from libtuning.libtuning import *
 
diff --git a/utils/tuning/libtuning/logger.py b/utils/tuning/libtuning/logger.py
new file mode 100644
index 00000000..03b5e1e6
--- /dev/null
+++ b/utils/tuning/libtuning/logger.py
@@ -0,0 +1,105 @@ 
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com>
+#
+# logger.py - Logging for libtuning
+
+
+import datetime
+from enum import IntEnum
+from inspect import currentframe, getframeinfo
+import math
+from pathlib import Path
+import psutil
+import sys
+import time
+
+
+class Logger(object):
+    class Level(IntEnum):
+        Debug = 0
+        Info = 1
+        Warn = 2
+        Error = 3
+        Fatal = 4
+
+    level_map = {
+        Level.Debug: 'DEBUG',
+        Level.Info: 'INFO',
+        Level.Warn: 'WARN',
+        Level.Error: 'ERROR',
+        Level.Fatal: 'FATAL',
+    }
+
+    log_levels = {}
+    log_level = Level.Info
+    log_file = sys.stderr
+
+    # @brief Set the log levels from the command line argument
+    # @param argstr String of log levels from cli argument, may be empty
+    def set_log_levels(argstr):
+        if argstr == '':
+            return
+
+        strings = argstr.split(',')
+        if len(strings) == 1 and strings[0].isnumeric():
+            Logger.log_level = int(strings[0])
+            return
+
+        pairs = [pair.split('=') for pair in strings]
+        Logger.log_levels = {pair[0]: int(pair[1]) for pair in pairs}
+
+        if '*' in Logger.log_levels:
+            Logger.log_level = Logger.log_levels['*']
+
+    # @brief Get the time since boot in the format HH:MM:SS.SSSSSSSSS
+    def get_and_convert_timestamp():
+        day_mult = 24 * 60 * 60
+        hour_mult = 60 * 60
+
+        seconds = time.time() - psutil.boot_time()
+        days = seconds // day_mult
+        hours = (seconds - (days * day_mult)) // hour_mult
+        hours += days * 24
+        mins = (seconds - (hours * hour_mult)) // 60
+        secs = (seconds - (hours * hour_mult)) % 60
+        ns, s = math.modf(secs)
+
+        return f'{int(hours)}:{int(mins):02}:{int(s):02}.{int(ns * 10**9):09}'
+
+    # @brief Log a message
+    # @param obj The object instance that wants to log, or a string to use as
+    #        component name if the caller is not an object instance
+    # @param level Log level
+    # @param msg String to log
+    # @param from_helper True if called from Logger's log_* helpers, False otherwise
+    def log(obj, level: Level, msg: str, from_helper=False):
+        if from_helper:
+            frameinfo = getframeinfo(currentframe().f_back.f_back)
+        else:
+            frameinfo = getframeinfo(currentframe().f_back)
+
+        ts = Logger.get_and_convert_timestamp()
+        if isinstance(obj, str):
+            name = obj
+        else:
+            name = obj.__class__.__name__
+
+        if (name in Logger.log_levels and level >= Logger.log_levels[name]) or \
+           level >= Logger.log_level:
+            print(f'[{ts}] {Logger.level_map[level]} {name} {Path(frameinfo.filename).name}:{frameinfo.lineno} {msg}', file=Logger.log_file)
+
+    def log_debug(obj, msg: str):
+        Logger.log(obj, Logger.Level.Debug, msg, True)
+
+    def log_info(obj, msg: str):
+        Logger.log(obj, Logger.Level.Info, msg, True)
+
+    def log_warn(obj, msg: str):
+        Logger.log(obj, Logger.Level.Warn, msg, True)
+
+    def log_error(obj, msg: str):
+        Logger.log(obj, Logger.Level.Error, msg, True)
+
+    def log_fatal(obj, msg: str):
+        Logger.log(obj, Logger.Level.Fatal, msg, True)