logger-36 2023.4__tar.gz → 2023.6__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: logger-36
3
- Version: 2023.4
3
+ Version: 2023.6
4
4
  Summary: Simple logger using rich_
5
5
  Home-page: https://src.koda.cnrs.fr/eric.debreuve/logger-36/
6
6
  Author: Eric Debreuve
@@ -46,29 +46,27 @@ try:
46
46
  from psutil import Process as process_t
47
47
 
48
48
  _PROCESS = process_t()
49
- _GIGA_SCALING = 1.0 / (1024**3)
50
-
51
- def UsedMemoryInGb() -> float:
52
- """"""
53
- return round(_GIGA_SCALING * _PROCESS.memory_info().rss, 1)
54
-
49
+ _MEGA_SCALING = 1.0 / (1024.0**2)
50
+ _GIGA_SCALING = _MEGA_SCALING / 1024.0
55
51
  except ModuleNotFoundError:
56
52
  _PROCESS = None
57
-
58
- def UsedMemoryInGb() -> float:
59
- """"""
60
- return 0.0
53
+ _MEGA_SCALING = _GIGA_SCALING = 0.0
61
54
 
62
55
 
63
56
  # This module is certainly imported early. Therefore, the current time should be close enough to the real start time.
64
57
  _START_TIME = time.time()
65
58
 
59
+ _TERMINAL_WIDTH = 1000
60
+ _TAB_SIZE = 5
66
61
 
62
+ _WHERE_SEPARATOR = "@"
63
+ # Tab size is set by console_t so that the dash is aligned for all log levels (might not work for file handlers though)
67
64
  _MESSAGE_FORMAT = (
68
- "%(asctime)s[%(levelname)s]\t- "
69
- "%(message)s @ "
70
- "%(module)s:%(funcName)s:%(lineno)d"
65
+ f"%(asctime)s[%(levelname)s]\t- "
66
+ f"%(message)s {_WHERE_SEPARATOR} "
67
+ f"%(module)s:%(funcName)s:%(lineno)d"
71
68
  )
69
+ _NEXT_LINE_PROLOGUE = "\n" + (27 + _TAB_SIZE) * " "
72
70
  _DATE_FORMAT = "%Y-%m-%d@%H:%M:%S"
73
71
 
74
72
  _SYSTEM_DETAILS = (
@@ -93,15 +91,52 @@ _SYSTEM_DETAILS = {_dtl.capitalize(): getattr(pltf, _dtl)() for _dtl in _SYSTEM_
93
91
  _MAX_DETAIL_NAME_LENGTH = max(map(len, _SYSTEM_DETAILS.keys()))
94
92
 
95
93
 
96
- # TODO: might be simpler/better to use filters (https://devdocs.io/python~3.10/howto/logging-cookbook#context-info) or a
97
- # logging.LoggerAdapter
94
+ # Alternative implementations: using logging.Filter or logging.LoggerAdapter
95
+
96
+
98
97
  class _handler_extension:
99
- formatter: lggg.Formatter = None
100
- show_memory_usage: bool = False
98
+ __slots__ = ("formatter", "show_memory_usage")
99
+ formatter: lggg.Formatter
100
+ show_memory_usage: bool
101
101
 
102
102
  def __init__(self) -> None:
103
103
  """"""
104
104
  self.formatter = lggg.Formatter(fmt=_MESSAGE_FORMAT, datefmt=_DATE_FORMAT)
105
+ self.show_memory_usage = False
106
+
107
+ def FormattedMessage(
108
+ self, record: lggg.LogRecord, /
109
+ ) -> tuple[str, list[str] | None]:
110
+ """
111
+ Note: "message" is not yet an attribute of record (it will be set by format()); Use "msg" instead.
112
+ """
113
+ if not isinstance(record.msg, str):
114
+ record.msg = str(record.msg)
115
+ if "\n" in record.msg:
116
+ original_message = record.msg
117
+ lines = original_message.splitlines()
118
+ record.msg = lines[0]
119
+ else:
120
+ original_message = lines = None
121
+
122
+ formatted = self.formatter.format(record)
123
+
124
+ # Revert the record message to its original value for subsequent handlers
125
+ if original_message is not None:
126
+ record.msg = original_message
127
+
128
+ return formatted, lines
129
+
130
+ def MemoryUsage(self) -> str:
131
+ """"""
132
+ if self.show_memory_usage:
133
+ usage = _PROCESS.memory_info().rss
134
+ if usage > _GIGA_SCALING:
135
+ return f" :{round(_GIGA_SCALING * usage, 1)}GB"
136
+ else:
137
+ return f" :{round(_MEGA_SCALING * usage, 1)}MB"
138
+
139
+ return ""
105
140
 
106
141
 
107
142
  class console_handler_t(lggg.Handler, _handler_extension):
@@ -116,7 +151,7 @@ class console_handler_t(lggg.Handler, _handler_extension):
116
151
  _ACTUAL: ClassVar[str] = r" Actual=[^.]+\."
117
152
  _EXPECTED: ClassVar[str] = r" Expected([!<>]=|: )[^.]+\."
118
153
 
119
- console: console_t = None
154
+ console: console_t
120
155
 
121
156
  def __init__(self, /, *, level=lggg.NOTSET) -> None:
122
157
  """"""
@@ -125,33 +160,28 @@ class console_handler_t(lggg.Handler, _handler_extension):
125
160
 
126
161
  self.setFormatter(self.formatter)
127
162
  self.console = console_t(
128
- record=True, force_terminal=True, width=1000, tab_size=5
163
+ record=True, force_terminal=True, width=_TERMINAL_WIDTH, tab_size=_TAB_SIZE
129
164
  )
130
165
 
131
166
  def emit(self, record: lggg.LogRecord, /) -> None:
132
167
  """"""
133
168
  cls = self.__class__
134
169
 
135
- formatted = self.formatter.format(record)
136
- if self.show_memory_usage:
137
- memory_usage = f" :{UsedMemoryInGb()}Gb"
138
- else:
139
- memory_usage = ""
140
- if "\n" in formatted:
141
- lines = formatted.splitlines()
142
- highlighted = text_t(lines[0])
143
- highlighted.append(f" +{ElapsedTime()}{memory_usage}\n", style="green")
144
- highlighted.append(" " + "\n ".join(lines[1:]))
145
- else:
146
- highlighted = text_t(formatted)
147
- highlighted.append(f" +{ElapsedTime()}{memory_usage}", style="green")
170
+ formatted, lines = self.FormattedMessage(record)
171
+
172
+ highlighted = text_t(formatted)
173
+ highlighted.append(f" +{ElapsedTime()}{self.MemoryUsage()}", style="green")
174
+ if lines is not None:
175
+ highlighted.append(
176
+ _NEXT_LINE_PROLOGUE + _NEXT_LINE_PROLOGUE.join(lines[1:])
177
+ )
148
178
 
149
179
  highlighted.stylize("dodger_blue2", end=19)
150
180
  highlighted.highlight_words(
151
181
  (f"[{record.levelname}]",), style=cls._LEVEL_COLOR[record.levelno]
152
182
  )
153
183
  highlighted.highlight_regex(
154
- f"@ {record.module}:{record.funcName}:{record.lineno}",
184
+ f"{_WHERE_SEPARATOR} {record.module}:{record.funcName}:{record.lineno}",
155
185
  style=cls._GRAY_STYLE,
156
186
  )
157
187
  highlighted.highlight_regex(cls._ACTUAL, style="red")
@@ -161,26 +191,23 @@ class console_handler_t(lggg.Handler, _handler_extension):
161
191
 
162
192
 
163
193
  class file_handler_t(lggg.FileHandler, _handler_extension):
164
- def __init__(self, file: str, *args, **kwargs) -> None:
194
+ def __init__(self, file: str | path_t, *args, **kwargs) -> None:
165
195
  """"""
166
- lggg.FileHandler.__init__(self, file, *args, **kwargs)
196
+ lggg.FileHandler.__init__(self, str(file), *args, **kwargs)
167
197
  _handler_extension.__init__(self)
168
198
 
169
199
  self.setFormatter(self.formatter)
170
200
 
171
201
  def emit(self, record: lggg.LogRecord, /) -> None:
172
202
  """"""
173
- formatted = self.formatter.format(record)
174
- if self.show_memory_usage:
175
- memory_usage = f" :{UsedMemoryInGb()}Gb"
176
- else:
177
- memory_usage = ""
178
- if "\n" in formatted:
179
- lines = formatted.splitlines()
180
- next_lines = "\n ".join(lines[1:])
181
- message = f"{lines[0]} +{ElapsedTime()}{memory_usage}\n {next_lines}"
203
+ formatted, lines = self.FormattedMessage(record)
204
+ formatted = formatted.replace("\t", (9 - record.levelname.__len__()) * " ")
205
+
206
+ if lines is None:
207
+ message = f"{formatted} +{ElapsedTime()}{self.MemoryUsage()}"
182
208
  else:
183
- message = f"{formatted} +{ElapsedTime()}{memory_usage}"
209
+ next_lines = _NEXT_LINE_PROLOGUE.join(lines[1:])
210
+ message = f"{formatted} +{ElapsedTime()}{self.MemoryUsage()}{_NEXT_LINE_PROLOGUE}{next_lines}"
184
211
 
185
212
  print(message, file=self.stream)
186
213
  self.stream.flush()
@@ -213,7 +240,7 @@ def AddFileHandler(file: Union[str, path_t], /) -> None:
213
240
  def SaveLOGasHTML(file: Union[str, path_t], /) -> None:
214
241
  """"""
215
242
  if file.exists():
216
- raise ValueError(f"{file}: File already exists")
243
+ print(f'Cannot save logging record as HTML: File "{file}" already exists')
217
244
 
218
245
  console = None
219
246
  found = False
@@ -225,7 +252,7 @@ def SaveLOGasHTML(file: Union[str, path_t], /) -> None:
225
252
  with open(file, "w") as accessor:
226
253
  accessor.write(console.export_html())
227
254
 
228
- raise ValueError("Cannot save logging record as HTML: Handler has no RICH console")
255
+ print("Cannot save logging record as HTML: No handler has a RICH console")
229
256
 
230
257
 
231
258
  def WhereFunction(function: Any, /) -> str:
@@ -0,0 +1,50 @@
1
+ # Copyright CNRS/Inria/UCA
2
+ # Contributor(s): Eric Debreuve (since 2023)
3
+ #
4
+ # eric.debreuve@cnrs.fr
5
+ #
6
+ # This software is governed by the CeCILL license under French law and
7
+ # abiding by the rules of distribution of free software. You can use,
8
+ # modify and/ or redistribute the software under the terms of the CeCILL
9
+ # license as circulated by CEA, CNRS and INRIA at the following URL
10
+ # "http://www.cecill.info".
11
+ #
12
+ # As a counterpart to the access to the source code and rights to copy,
13
+ # modify and redistribute granted by the license, users are provided only
14
+ # with a limited warranty and the software's author, the holder of the
15
+ # economic rights, and the successive licensors have only limited
16
+ # liability.
17
+ #
18
+ # In this respect, the user's attention is drawn to the risks associated
19
+ # with loading, using, modifying and/or developing or reproducing the
20
+ # software by the user in light of its specific status of free software,
21
+ # that may mean that it is complicated to manipulate, and that also
22
+ # therefore means that it is reserved for developers and experienced
23
+ # professionals having in-depth computer knowledge. Users are therefore
24
+ # encouraged to load and test the software's suitability as regards their
25
+ # requirements in conditions enabling the security of their systems and/or
26
+ # data to be ensured and, more generally, to use and operate it in the
27
+ # same conditions as regards security.
28
+ #
29
+ # The fact that you are presently reading this means that you have had
30
+ # knowledge of the CeCILL license and that you accept its terms.
31
+
32
+ from pathlib import Path as path_t
33
+ from tempfile import TemporaryDirectory
34
+
35
+ from logger_36 import LOGGER, AddFileHandler
36
+
37
+
38
+ with TemporaryDirectory() as tmp_folder:
39
+ tmp_folder = path_t(tmp_folder)
40
+ tmp_file = tmp_folder / "log.txt"
41
+
42
+ AddFileHandler(tmp_file)
43
+
44
+ for level in ("debug", "info", "warning", "error", "critical"):
45
+ LogMessage = getattr(LOGGER, level)
46
+ LogMessage(f"{level.capitalize()} message")
47
+ LogMessage(f"Multi-line\n{level.capitalize()}\nmessage")
48
+
49
+ content = open(tmp_file, "r").read()
50
+ print(f"\n{content}")
@@ -29,4 +29,4 @@
29
29
  # The fact that you are presently reading this means that you have had
30
30
  # knowledge of the CeCILL license and that you accept its terms.
31
31
 
32
- __version__ = "2023.4"
32
+ __version__ = "2023.6"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: logger-36
3
- Version: 2023.4
3
+ Version: 2023.6
4
4
  Summary: Simple logger using rich_
5
5
  Home-page: https://src.koda.cnrs.fr/eric.debreuve/logger-36/
6
6
  Author: Eric Debreuve
@@ -7,6 +7,7 @@ setup.py
7
7
  documentation/wiki/description.asciidoc
8
8
  logger_36/__init__.py
9
9
  logger_36/main.py
10
+ logger_36/test.py
10
11
  logger_36/version.py
11
12
  logger_36.egg-info/PKG-INFO
12
13
  logger_36.egg-info/SOURCES.txt
File without changes
File without changes
File without changes
File without changes
File without changes