From patchwork Tue Nov 29 05:33:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 17903 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 946ADBE08B for ; Tue, 29 Nov 2022 05:33:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4F6B063340; Tue, 29 Nov 2022 06:33:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1669700022; bh=qPIrXBTslCt+3tRVlHHq45B+cuJZlab0foFAbM2+WG4=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=WwGHlSBEWtE5R0/GrxjX6IHs/N9G3F8Yvn5GPa6i1Q1HJbZ8pYeYuJlior/3qPOYm pWvWAyvdYNe1KOvTftl8DfS9ZgKdd79137HYkWhkSh/wJwDfv3ewiSBtImmRFW7A7U ZvarCZocmdRPtYzDUFaiMvJ5bH1VBCQ8NKDAqCx3aBaIArvAa3qXftmnV0L1DDfHXm dcq2ccLZ48ltaHCa+zk8DMZdLt8Ct/ikgAdsr4oiWPspMZh73u/bWXZn24PjHOdVTj wHb0RnACHP4MokVbLX2EXzHDSyk1/geLxgp5ToaOx5mB2OjEQnHPHKj+IAYEIPY2zn KROTp0FNI8EvQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9FA7A6333A for ; Tue, 29 Nov 2022 06:33:38 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="IUMGirjz"; dkim-atps=neutral Received: from pyrite.tail37cf.ts.net (h175-177-042-159.catv02.itscom.jp [175.177.42.159]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 583937F8; Tue, 29 Nov 2022 06:33:37 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1669700018; bh=qPIrXBTslCt+3tRVlHHq45B+cuJZlab0foFAbM2+WG4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IUMGirjzq85c9DF4fLmZg2KtComaQjaINFxDOlLeUdYiFoTj/+NQTsvZJ/BGPs9iW ylybGJsF50Vo9STYMT2Wu3ogS+px+jJPUdjYPLfTgQ1V0+zfLTNHEHRhf/nXkiUFR4 aVUsC7EGXlC4QvLWKsBFJ8MYZ8UhxNp0nt7vf++k= To: libcamera-devel@lists.libcamera.org Date: Tue, 29 Nov 2022 14:33:24 +0900 Message-Id: <20221129053326.2858347-2-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221129053326.2858347-1-paul.elder@ideasonboard.com> References: <20221129053326.2858347-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 1/3] utils: libtuning: Add logger X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Paul Elder via libcamera-devel From: Paul Elder Reply-To: Paul Elder Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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 --- 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 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 +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 +# +# 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) From patchwork Tue Nov 29 05:33:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 17904 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E2CEDBE08B for ; Tue, 29 Nov 2022 05:33:43 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5CDA163326; Tue, 29 Nov 2022 06:33:43 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1669700023; bh=shAWITXYnfjCp6AIytWBxVwOODCXOonvmVBZVd1MXR0=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=zCrMp0BwCHLV7f+lGDvZhfds+6seQCH+J84kMBnFcFqQipMV9RQ0uwF/uKaGfvMWq xLTXZbDFTsZh9AAsZDtFqZVKbRdCSKJBT5Ds+/S1TldG3nFga3goasG3iHbcm2racR NcheMe5oeFZCWYyBqJhAGMjF76kqIyQcl3D21YU50k+kFPVr39yJCYUXgy4yXVhSng OUqF+XGixA1/a1b7Fpt8GapWCSt2JFtXRd5mVWS7gvjzr8krKBtT+cGb4dAifwYSEw TCgvZCNi7LEuKippxZIj/21oNwB+aJ2qYdZMG+pZAiiHiLF8sy9Uey1cQQMv2qm8Q6 nGKKCaqZIPh9w== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2658161F23 for ; Tue, 29 Nov 2022 06:33:40 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Y40TfRGc"; dkim-atps=neutral Received: from pyrite.tail37cf.ts.net (h175-177-042-159.catv02.itscom.jp [175.177.42.159]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E23204E6; Tue, 29 Nov 2022 06:33:38 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1669700019; bh=shAWITXYnfjCp6AIytWBxVwOODCXOonvmVBZVd1MXR0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Y40TfRGc/DSj++wFoXlppaQdRabAaaVnlrYXf3vgOaG2dDKLOwmVaQ5Zcd5OAylnM Lz3i74i3LrZ/y+Frkuuv/JFX/kcPk0pJXwAJQnomvBfL6ntuji5xgOfz2nGDaBOtd3 H9HB0jLrx8GU4FbULVzevdiNN5Wb5AUBe9dWFrSg= To: libcamera-devel@lists.libcamera.org Date: Tue, 29 Nov 2022 14:33:25 +0900 Message-Id: <20221129053326.2858347-3-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221129053326.2858347-1-paul.elder@ideasonboard.com> References: <20221129053326.2858347-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 2/3] utils: libtuning: Replace eprint with Logger X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Paul Elder via libcamera-devel From: Paul Elder Reply-To: Paul Elder Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Replace all instances (including the definition) of eprint with Logger. Signed-off-by: Paul Elder --- .../libtuning/generators/yaml_output.py | 4 ++-- utils/tuning/libtuning/image.py | 6 +++--- utils/tuning/libtuning/libtuning.py | 20 +++++++++---------- utils/tuning/libtuning/macbeth.py | 12 ++++++----- .../libtuning/modules/lsc/raspberrypi.py | 12 +++++------ utils/tuning/libtuning/utils.py | 17 ++++++++-------- 6 files changed, 37 insertions(+), 34 deletions(-) diff --git a/utils/tuning/libtuning/generators/yaml_output.py b/utils/tuning/libtuning/generators/yaml_output.py index effb4fb3..9966cb4c 100644 --- a/utils/tuning/libtuning/generators/yaml_output.py +++ b/utils/tuning/libtuning/generators/yaml_output.py @@ -9,7 +9,7 @@ from .generator import Generator from numbers import Number from pathlib import Path -import libtuning.utils as utils +from libtuning.logger import Logger class YamlOutput(Generator): @@ -112,7 +112,7 @@ class YamlOutput(Generator): continue if not isinstance(output_dict[module], dict): - utils.eprint(f'Error: Output of {module.type} is not a dictionary') + Logger.log_error(self, f'Output of {module.type} is not a dictionary') continue lines = self._stringify_dict(output_dict[module]) diff --git a/utils/tuning/libtuning/image.py b/utils/tuning/libtuning/image.py index aa9d20b5..0a35f384 100644 --- a/utils/tuning/libtuning/image.py +++ b/utils/tuning/libtuning/image.py @@ -12,7 +12,7 @@ import rawpy as raw import re import libtuning as lt -import libtuning.utils as utils +from libtuning.logger import Logger class Image: @@ -25,13 +25,13 @@ class Image: try: self._load_metadata_exif() except Exception as e: - utils.eprint(f'Failed to load metadata from {self.path}: {e}') + Logger.log_error(self, f'Failed to load metadata from {self.path}: {e}') raise e try: self._read_image_dng() except Exception as e: - utils.eprint(f'Failed to load image data from {self.path}: {e}') + Logger.log_error(self, f'Failed to load image data from {self.path}: {e}') raise e @property diff --git a/utils/tuning/libtuning/libtuning.py b/utils/tuning/libtuning/libtuning.py index a1238bb1..d34d98ab 100644 --- a/utils/tuning/libtuning/libtuning.py +++ b/utils/tuning/libtuning/libtuning.py @@ -8,8 +8,8 @@ import argparse from pathlib import Path import libtuning as lt +from libtuning.logger import Logger import libtuning.utils as utils -from libtuning.utils import eprint from enum import Enum, IntEnum @@ -109,10 +109,10 @@ class Tuner(object): for module_type in output_order: modules = [module for module in self.modules if module.type == module_type.type] if len(modules) > 1: - eprint(f'Multiple modules found for module type "{module_type.type}"') + Logger.log_error(self, f'Multiple modules found for module type "{module_type.type}"') return False if len(modules) < 1: - eprint(f'No module found for module type "{module_type.type}"') + Logger.log_error(self, f'No module found for module type "{module_type.type}"') return False self.output_order.append(modules[0]) @@ -121,19 +121,19 @@ class Tuner(object): # \todo Validate parser and generator at Tuner construction time? def _validate_settings(self): if self.parser is None: - eprint('Missing parser') + Logger.log_error(self, 'Missing parser') return False if self.generator is None: - eprint('Missing generator') + Logger.log_error(self, 'Missing generator') return False if len(self.modules) == 0: - eprint('No modules added') + Logger.log_error(self, 'No modules added') return False if len(self.output_order) != len(self.modules): - eprint('Number of outputs does not match number of modules') + Logger.log_error(self, 'Number of outputs does not match number of modules') return False return True @@ -208,7 +208,7 @@ class Tuner(object): # Validate modules and set debug for module in self.modules: if not module.validate_config(self.config): - eprint(f'Config is invalid for module {module.type}') + Logger.log_error(self, f'Config is invalid for module {module.type}') return -1 if args.debug_dir is not None and \ @@ -224,14 +224,14 @@ class Tuner(object): images = utils.load_images(args.input, self.config, not has_only_lsc, has_lsc) if images is None or len(images) == 0: - eprint(f'No images were found, or able to load') + Logger.log_error(self, f'No images were found, or able to load') return -1 # Do the tuning for module in self.modules: out = module.process(self.config, images, self.output) if out is None: - eprint(f'Module {module.name} failed to process, aborting') + Logger.log_error(self, f'Module {module.name} failed to process, aborting') break self.output[module] = out diff --git a/utils/tuning/libtuning/macbeth.py b/utils/tuning/libtuning/macbeth.py index 5faddf66..df16e868 100644 --- a/utils/tuning/libtuning/macbeth.py +++ b/utils/tuning/libtuning/macbeth.py @@ -13,7 +13,9 @@ from pathlib import Path import numpy as np from libtuning.image import Image +from libtuning.logger import Logger +macbeth_log_str = 'Macbeth' # Reshape image to fixed width without distorting returns image and scale # factor @@ -369,7 +371,7 @@ def get_macbeth_chart(img, ref_data): # Catch macbeth errors and continue with code except MacbethError as error: - eprint(error) + Logger.log_error(macbeth_log_str, error) return (0, None, None, False) @@ -486,7 +488,7 @@ def find_macbeth(img, mac_config): coords_fit = coords if cor < 0.75: - eprint(f'Warning: Low confidence {cor:.3f} for macbeth chart in {img.path.name}') + Logger.log_warn(macbeth_log_str, f'Low confidence {cor:.3f} for macbeth chart in {img.path.name}') if show: draw_macbeth_results(img, coords_fit) @@ -499,18 +501,18 @@ def locate_macbeth(image: Image, config: dict): av_chan = (np.mean(np.array(image.channels), axis=0) / (2**16)) av_val = np.mean(av_chan) if av_val < image.blacklevel_16 / (2**16) + 1 / 64: - eprint(f'Image {image.path.name} too dark') + Logger.log_error(macbeth_log_str, f'Image {image.path.name} too dark') return None macbeth = find_macbeth(av_chan, config['general']['macbeth']) if macbeth is None: - eprint(f'No macbeth chart found in {image.path.name}') + Logger.log_error(macbeth_log_str, f'No macbeth chart found in {image.path.name}') return None mac_cen_coords = macbeth[1] if not image.get_patches(mac_cen_coords): - eprint(f'Macbeth patches have saturated in {image.path.name}') + Logger.log_error(macbeth_log_str, f'Macbeth patches have saturated in {image.path.name}') return None return macbeth diff --git a/utils/tuning/libtuning/modules/lsc/raspberrypi.py b/utils/tuning/libtuning/modules/lsc/raspberrypi.py index a0298348..91aa56e3 100644 --- a/utils/tuning/libtuning/modules/lsc/raspberrypi.py +++ b/utils/tuning/libtuning/modules/lsc/raspberrypi.py @@ -8,7 +8,7 @@ from .lsc import LSC import libtuning as lt -import libtuning.utils as utils +from libtuning.logger import Logger from numbers import Number import numpy as np @@ -35,7 +35,7 @@ class ALSCRaspberryPi(LSC): def validate_config(self, config: dict) -> bool: if self not in config: - utils.eprint(f'{self.type} not in config') + Logger.log_error(self, f'{self.type} not in config') return False valid = True @@ -46,14 +46,14 @@ class ALSCRaspberryPi(LSC): color_key = self.do_color.name if lum_key not in conf and self.luminance_strength.required: - utils.eprint(f'{lum_key} is not in config') + Logger.log_error(self, f'{lum_key} is not in config') valid = False if lum_key in conf and (conf[lum_key] < 0 or conf[lum_key] > 1): - utils.eprint(f'Warning: {lum_key} is not in range [0, 1]; defaulting to 0.5') + Logger.log_warn(self, f'Warning: {lum_key} is not in range [0, 1]; defaulting to 0.5') if color_key not in conf and self.do_color.required: - utils.eprint(f'{color_key} is not in config') + Logger.log_error(self, f'{color_key} is not in config') valid = False return valid @@ -236,7 +236,7 @@ class ALSCRaspberryPi(LSC): if count == 1: output['sigma'] = 0.005 output['sigma_Cb'] = 0.005 - utils.eprint('Warning: Only one alsc calibration found; standard sigmas used for adaptive algorithm.') + Logger.log_warn(self, 'Only one alsc calibration found; standard sigmas used for adaptive algorithm.') return output # Obtain worst-case scenario residual sigmas diff --git a/utils/tuning/libtuning/utils.py b/utils/tuning/libtuning/utils.py index b60f2c9b..d33b9294 100644 --- a/utils/tuning/libtuning/utils.py +++ b/utils/tuning/libtuning/utils.py @@ -6,6 +6,7 @@ # utils.py - Utilities for libtuning import decimal +from inspect import currentframe, getframeinfo import math import numpy as np import os @@ -15,13 +16,13 @@ import sys import libtuning as lt from libtuning.image import Image +from libtuning.logger import Logger from libtuning.macbeth import locate_macbeth -# Utility functions +utils_log_str = 'Utils' -def eprint(*args, **kwargs): - print(*args, file=sys.stderr, **kwargs) +# Utility functions def get_module_by_type_name(modules, name): @@ -45,7 +46,7 @@ def _list_image_files(directory): def _parse_image_filename(fn: Path): result = re.search(r'^(alsc_)?(\d+)[kK]_(\d+)?[lLuU]?.\w{3,4}$', fn.name) if result is None: - eprint(f'The file name of {fn.name} is incorrectly formatted') + Logger.log_error(utils_log_str, f'The file name of {fn.name} is incorrectly formatted') return None, None, None color = int(result.group(2)) @@ -72,7 +73,7 @@ def _validate_images(images): def load_images(input_dir: str, config: dict, load_nonlsc: bool, load_lsc: bool) -> list: files = _list_image_files(input_dir) if len(files) == 0: - eprint(f'No images found in {input_dir}') + Logger.log_error(utils_log_str, f'No images found in {input_dir}') return None images = [] @@ -83,19 +84,19 @@ def load_images(input_dir: str, config: dict, load_nonlsc: bool, load_lsc: bool) # Skip lsc image if we don't need it if lsc_only and not load_lsc: - eprint(f'Skipping {f.name} as this tuner has no LSC module') + Logger.log_info(utils_log_str, f'Skipping {f.name} as this tuner has no LSC module') continue # Skip non-lsc image if we don't need it if not lsc_only and not load_nonlsc: - eprint(f'Skipping {f.name} as this tuner only has an LSC module') + Logger.log_info(utils_log_str, f'Skipping {f.name} as this tuner only has an LSC module') continue # Load image try: image = Image(f) except Exception as e: - eprint(f'Failed to load image {f.name}: {e}') + Logger.log_warn(utils_log_str, f'Failed to load image {f.name}: {e}') continue # Populate simple fields From patchwork Tue Nov 29 05:33:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 17905 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 9C7F0BE08B for ; Tue, 29 Nov 2022 05:33:44 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DDCDD6333F; Tue, 29 Nov 2022 06:33:43 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1669700023; bh=86DQt6YHZKxFRsOn+dGB7Nmhmi3E0D7IfPCUkr8iS4g=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=HsIG+eZfmT0jDHPWhKcGv89uKhIbOlFNM2IPyN3euLw2QrOKfGtHt4rMLv+GMaDKK RgX24kLnk9aDglcKCudqt3gXayjXjEfWap0LbZh6bXd3zZy/GZWQs5OgEn8fDlVmzs XSnFSo+xu82xh/WRYxC+oKKNhm+BVYys4bTVG2o9AORyNW9Yunp6pcJeITC8f32twC YgOQRrghi1J71pk/JzJzrnRayFbQSscAcf7CpbIAYnW3MSZ8GHAzoemLeZqHzlhmxm +7WXEnRc6q8he4x433HmIG6PZ7iIDETDj5GVnNYif2ZvoFlsWtM1ActXQ3AxpoVBC1 M+g84TrWdQuEA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A810A63334 for ; Tue, 29 Nov 2022 06:33:41 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BDv4KKyt"; dkim-atps=neutral Received: from pyrite.tail37cf.ts.net (h175-177-042-159.catv02.itscom.jp [175.177.42.159]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 77C9E4E6; Tue, 29 Nov 2022 06:33:40 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1669700021; bh=86DQt6YHZKxFRsOn+dGB7Nmhmi3E0D7IfPCUkr8iS4g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BDv4KKytPlWg+SrjLy+Hc8K2O0lQshRmERCytxUrdD51Y4xo2LRMiOk/0xPqsjj6o /M9kxqAerm8wpEf7qCuALhwJjolnlFqtHGONSHVa6+O6dc7uOJilSsm2jD1pN17xIc aMVSDJE7YDVWotdd30aR3J8zDC1sO5ueSrZj9yCQ= To: libcamera-devel@lists.libcamera.org Date: Tue, 29 Nov 2022 14:33:26 +0900 Message-Id: <20221129053326.2858347-4-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221129053326.2858347-1-paul.elder@ideasonboard.com> References: <20221129053326.2858347-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/3] utils: libtuning: Add logging parameters to argparse X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Paul Elder via libcamera-devel From: Paul Elder Reply-To: Paul Elder Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add command line arguments for log levels and log output file. Signed-off-by: Paul Elder --- utils/tuning/libtuning/libtuning.py | 32 +++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/utils/tuning/libtuning/libtuning.py b/utils/tuning/libtuning/libtuning.py index d34d98ab..b2c40ba4 100644 --- a/utils/tuning/libtuning/libtuning.py +++ b/utils/tuning/libtuning/libtuning.py @@ -6,6 +6,7 @@ import argparse from pathlib import Path +import sys import libtuning as lt from libtuning.logger import Logger @@ -150,10 +151,24 @@ class Tuner(object): # options, so simply return an empty configuration if none is provided. parser.add_argument('-c', '--config', type=str, default='', help='Config file (optional)') - # \todo Check if we really need this or if stderr is good enough, or if - # we want a better logging infrastructure with log levels - parser.add_argument('-l', '--log', type=str, default=None, - help='Output log file (optional)') + parser.add_argument('-l', '--log', type=str, default=sys.stderr, + help='Output log file (optional). Default is stderr.') + parser.add_argument('-ll', '--log_levels', type=str, default='', + help='''Output log levels (optional). + A comma-separated list of module names and + their log levels (in integer form, where + debug=0, info=1, warn=2, error=3, and + fatal=4), in the format: "{module name}:{log + level},{module name}:{log_level}...", and so + on. Any module that is not specified will use the + default log level, or the default can be + specified with the log name "*". For the + purposes of logging, module names are the + same as class names, or the file name for + components that are not classes. This + parameter can also be simply set to a + single integer to set the log levels for + all components.''') parser.add_argument('-dd', '--debug_dir', type=str, default=None, help='''Debug output directory (optional). If the directory does not exist, it will be @@ -205,6 +220,12 @@ class Tuner(object): if not debug_dir.is_dir(): debug_dir.mkdir() + # Prepare logging + if args.log is not sys.stderr: + Logger.log_file = open(args.log, mode='a') + + Logger.set_log_levels(args.log_levels) + # Validate modules and set debug for module in self.modules: if not module.validate_config(self.config): @@ -237,4 +258,7 @@ class Tuner(object): self.generator.write(args.output, self.output, self.output_order) + if Logger.log_file is not sys.stderr: + Logger.log_file.close() + return 0