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 +21 -0
- RFL.log-1.0.0/README.md +3 -0
- RFL.log-1.0.0/RFL.log.egg-info/PKG-INFO +21 -0
- RFL.log-1.0.0/RFL.log.egg-info/SOURCES.txt +8 -0
- RFL.log-1.0.0/RFL.log.egg-info/dependency_links.txt +1 -0
- RFL.log-1.0.0/RFL.log.egg-info/top_level.txt +1 -0
- RFL.log-1.0.0/pyproject.toml +31 -0
- RFL.log-1.0.0/rfl/log/__init__.py +83 -0
- RFL.log-1.0.0/rfl/log/formatters.py +75 -0
- RFL.log-1.0.0/setup.cfg +4 -0
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.
|
RFL.log-1.0.0/README.md
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 @@
|
|
|
1
|
+
|
|
@@ -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)
|
RFL.log-1.0.0/setup.cfg
ADDED