]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/munet/mulog.py
1 # -*- coding: utf-8 eval: (blacken-mode 1) -*-
2 # SPDX-License-Identifier: GPL-2.0-or-later
4 # December 4 2022, Christian Hopps <chopps@labn.net>
6 # Copyright (c) 2022, LabN Consulting, L.L.C.
8 """Utilities for logging in munet."""
12 from pathlib
import Path
15 class MultiFileHandler(logging
.FileHandler
):
16 """A logging handler that logs to new files based on the logger name.
18 The MultiFileHandler operates as a FileHandler with additional functionality. In
19 addition to logging to the specified logging file MultiFileHandler also creates new
20 FileHandlers for child loggers based on a root logging name path.
22 The ``root_path`` determines when to create a new FileHandler. For each received log
23 record, ``root_path`` is removed from the logger name of the record if present, and
24 the resulting channel path (if any) determines the directory for a new log file to
25 also emit the record to. The new file path is constructed by starting with the
26 directory ``filename`` resides in, then joining the path determined above after
27 converting "." to "/" and finally by adding back the basename of ``filename``.
29 record logger path => mutest.output.testingfoo
30 root_path => mutest.output
31 base filename => /tmp/mutest/mutest-exec.log
32 new logfile => /tmp/mutest/testingfoo/mutest-exec.log
34 All messages are also emitted to the common FileLogger for ``filename``.
36 If a log record is from a logger that does not start with ``root_path`` no file is
37 created and the normal emit occurs.
40 root_path: the logging path of the root level for this handler.
41 new_handler_level: logging level for newly created handlers
42 log_dir: the log directory to put log files in.
43 filename: the base log file.
46 def __init__(self
, root_path
, filename
=None, **kwargs
):
47 self
.__root
_path
= root_path
48 self
.__basename
= Path(filename
).name
49 if root_path
[-1] != ".":
50 self
.__root
_path
+= "."
51 self
.__root
_pathlen
= len(self
.__root
_path
)
52 self
.__kwargs
= kwargs
53 self
.__log
_dir
= Path(filename
).absolute().parent
54 self
.__log
_dir
.mkdir(parents
=True, exist_ok
=True)
58 if "new_handler_level" not in kwargs
:
59 self
.__new
_handler
_level
= logging
.NOTSET
61 new_handler_level
= kwargs
["new_handler_level"]
62 del kwargs
["new_handler_level"]
63 self
.__new
_handler
_level
= new_handler_level
65 super().__init
__(filename
=filename
, **kwargs
)
67 if self
.__new
_handler
_level
is None:
68 self
.__new
_handler
_level
= self
.level
70 def __log_filename(self
, name
):
71 if name
in self
.__filenames
:
72 return self
.__filenames
[name
]
74 if not name
.startswith(self
.__root
_path
):
77 newname
= name
[self
.__root
_pathlen
:]
78 newname
= Path(newname
.replace(".", "/"))
79 newname
= self
.__log
_dir
.joinpath(newname
)
80 newname
= newname
.joinpath(self
.__basename
)
81 self
.__filenames
[name
] = newname
83 self
.__filenames
[name
] = newname
86 def emit(self
, record
):
87 newname
= self
.__log
_filename
(record
.name
)
89 if newname
not in self
.__added
:
90 self
.__added
.add(newname
)
91 h
= logging
.FileHandler(filename
=newname
, **self
.__kwargs
)
92 h
.setLevel(self
.__new
_handler
_level
)
93 h
.setFormatter(self
.formatter
)
94 logging
.getLogger(record
.name
).addHandler(h
)
99 class ColorFormatter(logging
.Formatter
):
100 """A formatter that adds color sequences based on level."""
102 def __init__(self
, fmt
=None, datefmt
=None, style
="%", **kwargs
):
106 bold_red
= "\x1b[31;1m"
108 # basefmt = " ------| %(message)s "
111 logging
.DEBUG
: logging
.Formatter(grey
+ fmt
+ reset
),
112 logging
.INFO
: logging
.Formatter(grey
+ fmt
+ reset
),
113 logging
.WARNING
: logging
.Formatter(yellow
+ fmt
+ reset
),
114 logging
.ERROR
: logging
.Formatter(red
+ fmt
+ reset
),
115 logging
.CRITICAL
: logging
.Formatter(bold_red
+ fmt
+ reset
),
117 # Why are we even bothering?
118 super().__init
__(fmt
, datefmt
, style
, **kwargs
)
120 def format(self
, record
):
121 formatter
= self
.formatters
.get(record
.levelno
)
122 return formatter
.format(record
)