Coverage for python / lsst / dax / apdb / cli / logging_cli.py: 23%

25 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-25 08:20 +0000

1# This file is part of dax_apdb 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22from __future__ import annotations 

23 

24__all__ = ["LoggingCli"] 

25 

26import argparse 

27import logging 

28 

29_log_format = "%(asctime)s %(levelname)s %(name)s - %(message)s" 

30 

31 

32class LoggingCli: 

33 """Class that handles CLI logging options and logging configuration. 

34 

35 Parameters 

36 ---------- 

37 parser : `argparse.ArgumentParser` 

38 Parser for which to define logging options. 

39 """ 

40 

41 def __init__(self, parser: argparse.ArgumentParser): 

42 self._parser = parser 

43 parser.add_argument( 

44 "-l", 

45 "--log-level", 

46 dest="log_level", 

47 action="append", 

48 metavar="LEVEL|LOGGER=LEVEL[,...]", 

49 help="Global or per-logger logging level, comma-separated and can be specified multiple times", 

50 default=[], 

51 ) 

52 

53 def process_args(self, args: argparse.Namespace) -> None: 

54 """Configure Python logging based on command line options.""" 

55 global_level = logging.INFO 

56 # Suppress chatty cassandra.cluster logger by default. 

57 logger_levels: dict[str, int] = { 

58 "cassandra.cluster": logging.WARNING, 

59 "botocore": logging.WARNING, 

60 "felis": logging.INFO, # felis is chatty too at debug level 

61 } 

62 for level_str in args.log_level: 

63 for spec in level_str.split(","): 

64 logger_name, sep, level_name = spec.rpartition("=") 

65 level = logging.getLevelNamesMapping().get(level_name.upper()) 

66 if level is None: 

67 self._parser.error(f"Unknown logging level {level_name!r} in {level_str!r}") 

68 if logger_name: 

69 logger_levels[logger_name] = level 

70 else: 

71 global_level = level 

72 

73 logging.basicConfig(level=global_level, format=_log_format) 

74 for logger_name, level in logger_levels.items(): 

75 logging.getLogger(logger_name).setLevel(level) 

76 

77 # We want to remove `log_level` so that namespace can be converted to 

78 # a dict and passed as kwargs to scripts. 

79 del args.log_level