@@ -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 *
new file mode 100644
@@ -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)
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