RFL.log 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
RFL.log-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.1
2
+ Name: RFL.log
3
+ Version: 1.0.0
4
+ Summary: Rackslab Foundation Library: log package
5
+ Author-email: Rémi Palancher <remi@rackslab.io>
6
+ License: GPLv3+
7
+ Project-URL: Homepage, https://github.com/rackslab/RFL
8
+ Project-URL: Bug Tracker, https://github.com/rackslab/RFL/issues
9
+ Keywords: utility,basic
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: System :: Systems Administration
16
+ Requires-Python: >=3.6
17
+ Description-Content-Type: text/markdown
18
+
19
+ # RFL: log package
20
+
21
+ Logging utility.
@@ -0,0 +1,3 @@
1
+ # RFL: log package
2
+
3
+ Logging utility.
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.1
2
+ Name: RFL.log
3
+ Version: 1.0.0
4
+ Summary: Rackslab Foundation Library: log package
5
+ Author-email: Rémi Palancher <remi@rackslab.io>
6
+ License: GPLv3+
7
+ Project-URL: Homepage, https://github.com/rackslab/RFL
8
+ Project-URL: Bug Tracker, https://github.com/rackslab/RFL/issues
9
+ Keywords: utility,basic
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: System :: Systems Administration
16
+ Requires-Python: >=3.6
17
+ Description-Content-Type: text/markdown
18
+
19
+ # RFL: log package
20
+
21
+ Logging utility.
@@ -0,0 +1,8 @@
1
+ README.md
2
+ pyproject.toml
3
+ RFL.log.egg-info/PKG-INFO
4
+ RFL.log.egg-info/SOURCES.txt
5
+ RFL.log.egg-info/dependency_links.txt
6
+ RFL.log.egg-info/top_level.txt
7
+ rfl/log/__init__.py
8
+ rfl/log/formatters.py
@@ -0,0 +1 @@
1
+ rfl
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "RFL.log"
7
+ version = "1.0.0"
8
+ description = "Rackslab Foundation Library: log package"
9
+ license = {text = "GPLv3+"}
10
+ requires-python = ">=3.6"
11
+ keywords = ["utility", "basic"]
12
+ authors = [
13
+ {name = "Rémi Palancher", email = "remi@rackslab.io"},
14
+ ]
15
+ dependencies = []
16
+ classifiers = [
17
+ "Development Status :: 5 - Production/Stable",
18
+ "Environment :: Console",
19
+ "Intended Audience :: System Administrators",
20
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: System :: Systems Administration",
23
+ ]
24
+ readme = "README.md"
25
+
26
+ [project.urls]
27
+ "Homepage" = "https://github.com/rackslab/RFL"
28
+ "Bug Tracker" = "https://github.com/rackslab/RFL/issues"
29
+
30
+ [tool.setuptools.packages.find]
31
+ include = ["rfl.log*"]
@@ -0,0 +1,83 @@
1
+ # Copyright (c) 2023 Rackslab
2
+ #
3
+ # This file is part of RFL.
4
+ #
5
+ # SPDX-License-Identifier: GPL-3.0-or-later
6
+
7
+ from typing import Optional, List
8
+ import logging
9
+
10
+ from .formatters import TTYFormatter, DaemonFormatter, auto_formatter
11
+
12
+ __all__ = [TTYFormatter, DaemonFormatter, auto_formatter]
13
+
14
+
15
+ def setup_logger(
16
+ debug: bool = False,
17
+ log_flags: Optional[List[str]] = None,
18
+ debug_flags: Optional[List[str]] = None,
19
+ formatter: logging.Formatter = auto_formatter(),
20
+ ) -> None:
21
+ """Setup root logger debug level, debug flags and formatter."""
22
+ if debug:
23
+ logging_level = logging.DEBUG
24
+ else:
25
+ logging_level = logging.INFO
26
+
27
+ if log_flags is None:
28
+ log_flags = []
29
+ if debug_flags is None:
30
+ debug_flags = []
31
+
32
+ root_logger = logging.getLogger()
33
+ root_logger.setLevel(logging_level)
34
+ handler = logging.StreamHandler()
35
+ handler.setLevel(logging_level)
36
+ formatter = formatter(debug)
37
+ handler.setFormatter(formatter)
38
+ # filter out all libs logs not enabled in flags
39
+ def custom_filter(record):
40
+ component = record.name.split(".")[0]
41
+ if record.levelno == logging.DEBUG:
42
+ if "ALL" in debug_flags or component in debug_flags:
43
+ return 1
44
+ return 0
45
+ if "ALL" in log_flags or component in log_flags:
46
+ return 1
47
+ return 0
48
+
49
+ handler.addFilter(custom_filter)
50
+ root_logger.addHandler(handler)
51
+
52
+
53
+ def enforce_debug(
54
+ log_flags: Optional[List[str]] = None,
55
+ debug_flags: Optional[List[str]] = None,
56
+ ) -> None:
57
+ """Enforce root logger debug level and debug flags."""
58
+ root_logger = logging.getLogger()
59
+ root_logger.setLevel(level=logging.DEBUG)
60
+
61
+ if log_flags is None:
62
+ log_flags = []
63
+ if debug_flags is None:
64
+ debug_flags = []
65
+
66
+ # filter out all libs logs not enabled in flags
67
+ def custom_filter(record):
68
+ component = record.name.split(".")[0]
69
+ if record.levelno == logging.DEBUG:
70
+ if "ALL" in debug_flags or component in debug_flags:
71
+ return 1
72
+ return 0
73
+ if "ALL" in log_flags or component in log_flags:
74
+ return 1
75
+ return 0
76
+
77
+ # For all handlers, set log level, enable debug in formatter and replace filter.
78
+ for handler in root_logger.handlers:
79
+ handler.setLevel(logging.DEBUG)
80
+ handler.formatter.debug = True
81
+ for filter in handler.filters:
82
+ handler.removeFilter(filter)
83
+ handler.addFilter(custom_filter)
@@ -0,0 +1,75 @@
1
+ # Copyright (c) 2023 Rackslab
2
+ #
3
+ # This file is part of RFL.
4
+ #
5
+ # SPDX-License-Identifier: GPL-3.0-or-later
6
+
7
+ import sys
8
+ import logging
9
+
10
+
11
+ def auto_formatter():
12
+ """Automatically select the most appropriate formatter class by checking if stdout
13
+ is connected to a TTY."""
14
+ if sys.stdout.isatty():
15
+ return TTYFormatter
16
+ else:
17
+ return DaemonFormatter
18
+
19
+
20
+ class ANSIStyle:
21
+ def __init__(self, fg, bg=None):
22
+ self.fg = fg
23
+ self.bg = bg
24
+
25
+ @property
26
+ def start(self):
27
+ bg_s = ""
28
+ if self.bg is not None:
29
+ bg_s = f"\033[48;5;{self.bg}m"
30
+ return bg_s + f"\033[38;5;{self.fg}m"
31
+
32
+ @property
33
+ def end(self):
34
+ return "\033[0;0m"
35
+
36
+
37
+ LOG_LEVEL_ANSI_STYLES = {
38
+ logging.CRITICAL: ANSIStyle(fg=15, bg=160), # white on red
39
+ logging.ERROR: ANSIStyle(fg=160), # red
40
+ logging.WARNING: ANSIStyle(fg=208), # orange
41
+ logging.INFO: ANSIStyle(fg=28), # dark green
42
+ logging.DEBUG: ANSIStyle(fg=62), # light mauve
43
+ logging.NOTSET: ANSIStyle(fg=8), # grey
44
+ }
45
+
46
+
47
+ class TTYFormatter(logging.Formatter):
48
+ def __init__(self, debug=False):
49
+ super().__init__("%(message)s")
50
+ self.debug = debug
51
+
52
+ def format(self, record):
53
+
54
+ _msg = record.getMessage()
55
+ style = LOG_LEVEL_ANSI_STYLES[record.levelno]
56
+ prefix = ""
57
+ if self.debug:
58
+ prefix = "{level:8s}⸬{where:30s} ↦ ".format(
59
+ level="[" + record.levelname + "]",
60
+ where=record.name + ":" + str(record.lineno),
61
+ )
62
+ elif record.levelno >= logging.INFO:
63
+ # prefix with level if over info
64
+ prefix = "{level} ⸬ ".format(level=record.levelname)
65
+
66
+ return style.start + prefix + _msg + style.end
67
+
68
+
69
+ class DaemonFormatter(logging.Formatter):
70
+ def __init__(self, debug=True):
71
+ if debug:
72
+ _fmt = "%(threadName)s: [%(levelname)s] %(name)s %(message)s"
73
+ else:
74
+ _fmt = "%(threadName)s: [%(levelname)s] %(message)s"
75
+ super().__init__(_fmt)
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+