atomicshop 2.14.8__py3-none-any.whl → 2.14.10__py3-none-any.whl
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.
Potentially problematic release.
This version of atomicshop might be problematic. Click here for more details.
- atomicshop/__init__.py +1 -1
- atomicshop/mitm/initialize_mitm_server.py +1 -1
- atomicshop/wrappers/loggingw/filters.py +79 -0
- atomicshop/wrappers/loggingw/handlers.py +123 -134
- atomicshop/wrappers/loggingw/loggingw.py +23 -1
- {atomicshop-2.14.8.dist-info → atomicshop-2.14.10.dist-info}/METADATA +1 -1
- {atomicshop-2.14.8.dist-info → atomicshop-2.14.10.dist-info}/RECORD +10 -9
- {atomicshop-2.14.8.dist-info → atomicshop-2.14.10.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.14.8.dist-info → atomicshop-2.14.10.dist-info}/WHEEL +0 -0
- {atomicshop-2.14.8.dist-info → atomicshop-2.14.10.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
|
@@ -47,7 +47,7 @@ def initialize_mitm_server(config_static):
|
|
|
47
47
|
logger_name = "system"
|
|
48
48
|
system_logger = loggingw.create_logger(
|
|
49
49
|
logger_name=logger_name,
|
|
50
|
-
file_path=f
|
|
50
|
+
file_path=f"{config['log']['logs_path']}{os.sep}{logger_name}.txt",
|
|
51
51
|
add_stream=True,
|
|
52
52
|
add_timedfile=True,
|
|
53
53
|
formatter_streamhandler='DEFAULT',
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class HeaderFilter(logging.Filter):
|
|
6
|
+
"""
|
|
7
|
+
A logging.Filter that writes a header to a log file if the file is empty (
|
|
8
|
+
i.e., no log records have been written, i.e.2, on file rotation).
|
|
9
|
+
"""
|
|
10
|
+
def __init__(self, header, baseFilename):
|
|
11
|
+
super().__init__()
|
|
12
|
+
self.header = header
|
|
13
|
+
self.baseFilename = baseFilename
|
|
14
|
+
self._write_header_if_needed()
|
|
15
|
+
|
|
16
|
+
def _write_header_if_needed(self):
|
|
17
|
+
if not os.path.exists(self.baseFilename) or os.path.getsize(self.baseFilename) == 0:
|
|
18
|
+
self._write_header()
|
|
19
|
+
|
|
20
|
+
def _write_header(self):
|
|
21
|
+
if self.header:
|
|
22
|
+
with open(self.baseFilename, 'a') as f:
|
|
23
|
+
f.write(self.header + '\n')
|
|
24
|
+
|
|
25
|
+
def filter(self, record):
|
|
26
|
+
self._write_header_if_needed()
|
|
27
|
+
return True
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
A logging.Filter in Python's logging module is an object that provides a way to perform fine-grained
|
|
32
|
+
filtering of log records.
|
|
33
|
+
It allows you to control which log records are passed through and which are filtered out,
|
|
34
|
+
based on specific criteria you define.
|
|
35
|
+
|
|
36
|
+
Basic Concepts of logging.Filter
|
|
37
|
+
Purpose: Filters are used to allow or deny log records from being processed further.
|
|
38
|
+
This can be based on various criteria, such as the level of the log record, the source logger, or custom attributes.
|
|
39
|
+
Implementation: Filters are typically subclasses of logging.Filter,
|
|
40
|
+
but they can also be any callable that accepts a log record and returns a boolean value.
|
|
41
|
+
|
|
42
|
+
How logging.Filter Works
|
|
43
|
+
When a log record is emitted, it is passed through any filters attached to the logger or the handler.
|
|
44
|
+
If the filter returns True, the log record is processed. If the filter returns False, the log record is ignored.
|
|
45
|
+
|
|
46
|
+
Example of logging.Filter
|
|
47
|
+
Here’s a simple example to demonstrate the use of logging.Filter:
|
|
48
|
+
|
|
49
|
+
Create a Filter: Subclass logging.Filter and override the filter method.
|
|
50
|
+
import logging
|
|
51
|
+
|
|
52
|
+
class MyFilter(logging.Filter):
|
|
53
|
+
def filter(self, record):
|
|
54
|
+
# Example: Allow only log records with a level of WARNING or higher
|
|
55
|
+
return record.levelno >= logging.WARNING
|
|
56
|
+
|
|
57
|
+
Attach the Filter to a Handler or Logger:
|
|
58
|
+
# Create a logger
|
|
59
|
+
logger = logging.getLogger('my_logger')
|
|
60
|
+
logger.setLevel(logging.DEBUG)
|
|
61
|
+
|
|
62
|
+
# Create a console handler
|
|
63
|
+
console_handler = logging.StreamHandler()
|
|
64
|
+
|
|
65
|
+
# Create an instance of the custom filter
|
|
66
|
+
my_filter = MyFilter()
|
|
67
|
+
|
|
68
|
+
# Add the filter to the handler
|
|
69
|
+
console_handler.addFilter(my_filter)
|
|
70
|
+
|
|
71
|
+
# Add the handler to the logger
|
|
72
|
+
logger.addHandler(console_handler)
|
|
73
|
+
|
|
74
|
+
# Log some messages
|
|
75
|
+
logger.debug('This is a debug message') # Will be filtered out
|
|
76
|
+
logger.info('This is an info message') # Will be filtered out
|
|
77
|
+
logger.warning('This is a warning message') # Will be displayed
|
|
78
|
+
logger.error('This is an error message') # Will be displayed
|
|
79
|
+
"""
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from logging.handlers import TimedRotatingFileHandler, QueueListener, QueueHandler
|
|
3
|
-
from logging import FileHandler
|
|
4
3
|
import time
|
|
5
4
|
import re
|
|
6
5
|
import os
|
|
@@ -10,66 +9,15 @@ from typing import Literal, Union
|
|
|
10
9
|
import threading
|
|
11
10
|
from datetime import datetime
|
|
12
11
|
|
|
13
|
-
from . import loggers, formatters
|
|
12
|
+
from . import loggers, formatters, filters
|
|
14
13
|
from ... import datetimes, filesystem
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
"""
|
|
18
17
|
# Not used, only for the reference:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class ForceAtTimeRotationTimedRotatingFileHandler(TimedRotatingFileHandler):
|
|
23
|
-
def __init__(self, *args, **kwargs):
|
|
24
|
-
super().__init__(*args, **kwargs)
|
|
25
|
-
self._last_rotated_date = None
|
|
26
|
-
self._start_rotation_check()
|
|
27
|
-
|
|
28
|
-
def _start_rotation_check(self):
|
|
29
|
-
self._rotation_thread = threading.Thread(target=self._check_for_rotation)
|
|
30
|
-
self._rotation_thread.daemon = True
|
|
31
|
-
self._rotation_thread.start()
|
|
32
|
-
|
|
33
|
-
def _check_for_rotation(self):
|
|
34
|
-
while True:
|
|
35
|
-
now = datetime.now()
|
|
36
|
-
current_date = now.date()
|
|
37
|
-
# Check if it's midnight and the logs haven't been rotated today
|
|
38
|
-
if now.hour == 0 and now.minute == 0 and current_date != self._last_rotated_date:
|
|
39
|
-
self._last_rotated_date = current_date
|
|
40
|
-
self.doRollover()
|
|
41
|
-
time.sleep(0.1)
|
|
42
|
-
|
|
43
|
-
def doRollover(self):
|
|
44
|
-
self._last_rotated_date = datetime.now().date()
|
|
45
|
-
super().doRollover()
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class TimedRotatingFileHandlerWithHeader(ForceAtTimeRotationTimedRotatingFileHandler):
|
|
49
|
-
"""
|
|
50
|
-
Custom TimedRotatingFileHandler that writes a header to the log file each time there is a file rotation.
|
|
51
|
-
Useful for writing CSV files.
|
|
52
|
-
|
|
53
|
-
:param header: string, Header to write to the log file.
|
|
54
|
-
Example: "time,host,error"
|
|
55
|
-
"""
|
|
56
|
-
def __init__(self, *args, **kwargs):
|
|
57
|
-
self.header = kwargs.pop('header', None)
|
|
58
|
-
super().__init__(*args, **kwargs)
|
|
59
|
-
|
|
60
|
-
def doRollover(self):
|
|
61
|
-
super().doRollover()
|
|
62
|
-
self._write_header()
|
|
63
|
-
|
|
64
|
-
def _write_header(self):
|
|
65
|
-
if self.header:
|
|
66
|
-
with open(self.baseFilename, 'a') as f:
|
|
67
|
-
f.write(self.header + '\n')
|
|
68
|
-
|
|
69
|
-
def emit(self, record):
|
|
70
|
-
if not os.path.exists(self.baseFilename) or os.path.getsize(self.baseFilename) == 0:
|
|
71
|
-
self._write_header()
|
|
72
|
-
super().emit(record)
|
|
18
|
+
DEFAULT_DATE_STRING_FORMAT: str = "%Y_%m_%d"
|
|
19
|
+
DEFAULT_DATE_REGEX_PATTERN: str = r"^\d{4}_\d{2}_\d{2}$"
|
|
20
|
+
"""
|
|
73
21
|
|
|
74
22
|
|
|
75
23
|
def _process_formatter_attribute(
|
|
@@ -134,6 +82,48 @@ def add_stream_handler(
|
|
|
134
82
|
loggers.set_propagation(logger)
|
|
135
83
|
|
|
136
84
|
|
|
85
|
+
# Function to start the interval-based rotation check
|
|
86
|
+
def _start_interval_rotation(handler):
|
|
87
|
+
def check_rotation():
|
|
88
|
+
while True:
|
|
89
|
+
next_rollover = _calculate_next_rollover()
|
|
90
|
+
while datetime.now() < next_rollover:
|
|
91
|
+
time.sleep(0.1)
|
|
92
|
+
|
|
93
|
+
# Check if the next_rollover has changed (indicating a rollover by an event)
|
|
94
|
+
if _calculate_next_rollover() != next_rollover:
|
|
95
|
+
next_rollover = _calculate_next_rollover()
|
|
96
|
+
break
|
|
97
|
+
|
|
98
|
+
# Perform manual rollover if needed
|
|
99
|
+
if datetime.now() >= next_rollover:
|
|
100
|
+
_rotate_log()
|
|
101
|
+
|
|
102
|
+
def _calculate_next_rollover():
|
|
103
|
+
return datetime.fromtimestamp(handler.rolloverAt)
|
|
104
|
+
|
|
105
|
+
# Function to rotate logs
|
|
106
|
+
def _rotate_log():
|
|
107
|
+
handler.doRollover()
|
|
108
|
+
|
|
109
|
+
rotation_thread = threading.Thread(target=check_rotation)
|
|
110
|
+
rotation_thread.daemon = True
|
|
111
|
+
rotation_thread.start()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _wrap_do_rollover(handler, header):
|
|
115
|
+
original_do_rollover = handler.doRollover
|
|
116
|
+
|
|
117
|
+
def new_do_rollover():
|
|
118
|
+
original_do_rollover()
|
|
119
|
+
# After rollover, write the header
|
|
120
|
+
if header:
|
|
121
|
+
with open(handler.baseFilename, 'a') as f:
|
|
122
|
+
f.write(header + '\n')
|
|
123
|
+
|
|
124
|
+
handler.doRollover = new_do_rollover
|
|
125
|
+
|
|
126
|
+
|
|
137
127
|
def add_timedfilehandler_with_queuehandler(
|
|
138
128
|
logger: logging.Logger,
|
|
139
129
|
file_path: str,
|
|
@@ -147,6 +137,10 @@ def add_timedfilehandler_with_queuehandler(
|
|
|
147
137
|
str,
|
|
148
138
|
None] = None,
|
|
149
139
|
formatter_use_nanoseconds: bool = False,
|
|
140
|
+
rotate_at_rollover_time: bool = True,
|
|
141
|
+
rotation_date_format: str = None,
|
|
142
|
+
rotation_callback_namer_function: callable = None,
|
|
143
|
+
rotation_use_default_callback_namer_function: bool = True,
|
|
150
144
|
when: str = 'midnight',
|
|
151
145
|
interval: int = 1,
|
|
152
146
|
delay: bool = True,
|
|
@@ -159,10 +153,6 @@ def add_timedfilehandler_with_queuehandler(
|
|
|
159
153
|
This is needed, since TimedRotatingFileHandler is not thread-safe, though official docs say it is.
|
|
160
154
|
"""
|
|
161
155
|
|
|
162
|
-
# If file name wasn't provided we will use the logger name instead.
|
|
163
|
-
# if not file_name_no_extension:
|
|
164
|
-
# file_name_no_extension = logger.name
|
|
165
|
-
|
|
166
156
|
# Setting the TimedRotatingFileHandler, without adding it to the logger.
|
|
167
157
|
# It will be added to the QueueListener, which will use the TimedRotatingFileHandler to write logs.
|
|
168
158
|
# This is needed since there's a bug in TimedRotatingFileHandler, which won't let it be used with
|
|
@@ -173,15 +163,8 @@ def add_timedfilehandler_with_queuehandler(
|
|
|
173
163
|
|
|
174
164
|
filesystem.create_directory(os.path.dirname(file_path))
|
|
175
165
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
# This is needed since the CSV file will be rotated, and we'll need to set the header each time.
|
|
179
|
-
# We'll use the custom TimedRotatingFileHandlerWithHeader class.
|
|
180
|
-
file_handler = get_timed_rotating_file_handler_with_header(
|
|
181
|
-
file_path, when=when, interval=interval, delay=delay, encoding=encoding, header=header)
|
|
182
|
-
else:
|
|
183
|
-
file_handler = get_timed_rotating_file_handler(
|
|
184
|
-
file_path, when=when, interval=interval, delay=delay, encoding=encoding)
|
|
166
|
+
file_handler = get_timed_rotating_file_handler(
|
|
167
|
+
file_path, when=when, interval=interval, delay=delay, encoding=encoding)
|
|
185
168
|
|
|
186
169
|
loggers.set_logging_level(file_handler, logging_level)
|
|
187
170
|
|
|
@@ -196,7 +179,23 @@ def add_timedfilehandler_with_queuehandler(
|
|
|
196
179
|
set_formatter(file_handler, logging_formatter)
|
|
197
180
|
|
|
198
181
|
# This function will change the suffix behavior of the rotated file name.
|
|
199
|
-
change_rotated_filename(
|
|
182
|
+
change_rotated_filename(
|
|
183
|
+
file_handler=file_handler, date_format_string=rotation_date_format,
|
|
184
|
+
callback_namer_function=rotation_callback_namer_function,
|
|
185
|
+
use_default_callback_namer_function=rotation_use_default_callback_namer_function
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# If header is set, we'll add the filter to the handler that will create the header on file rotation.
|
|
189
|
+
if header:
|
|
190
|
+
# Filter is added to write header on logger startup.
|
|
191
|
+
add_filter_to_handler(file_handler, filters.HeaderFilter(header, file_handler.baseFilename))
|
|
192
|
+
# Wrap the doRollover method to write the header after each rotation, since adding the filter
|
|
193
|
+
# will only write the header on log file creation.
|
|
194
|
+
_wrap_do_rollover(file_handler, header)
|
|
195
|
+
|
|
196
|
+
# Start the interval-based rotation forcing.
|
|
197
|
+
if rotate_at_rollover_time:
|
|
198
|
+
_start_interval_rotation(file_handler)
|
|
200
199
|
|
|
201
200
|
queue_handler = start_queue_listener_for_file_handler_and_get_queue_handler(file_handler)
|
|
202
201
|
loggers.set_logging_level(queue_handler, logging_level)
|
|
@@ -243,7 +242,7 @@ def get_stream_handler() -> logging.StreamHandler:
|
|
|
243
242
|
|
|
244
243
|
def get_timed_rotating_file_handler(
|
|
245
244
|
log_file_path: str, when: str = "midnight", interval: int = 1, delay: bool = False, encoding=None
|
|
246
|
-
) ->
|
|
245
|
+
) -> TimedRotatingFileHandler:
|
|
247
246
|
"""
|
|
248
247
|
Function to get a TimedRotatingFileHandler.
|
|
249
248
|
This handler will output messages to a file, rotating the log file at certain timed intervals.
|
|
@@ -261,32 +260,10 @@ def get_timed_rotating_file_handler(
|
|
|
261
260
|
:return: TimedRotatingFileHandler.
|
|
262
261
|
"""
|
|
263
262
|
|
|
264
|
-
return
|
|
263
|
+
return TimedRotatingFileHandler(
|
|
265
264
|
filename=log_file_path, when=when, interval=interval, delay=delay, encoding=encoding)
|
|
266
265
|
|
|
267
266
|
|
|
268
|
-
def get_timed_rotating_file_handler_with_header(
|
|
269
|
-
log_file_path: str, when: str = "midnight", interval: int = 1, delay: bool = False, encoding=None,
|
|
270
|
-
header: str = None) -> TimedRotatingFileHandlerWithHeader:
|
|
271
|
-
"""
|
|
272
|
-
Function to get a TimedRotatingFileHandler with header.
|
|
273
|
-
This handler will output messages to a file, rotating the log file at certain timed intervals.
|
|
274
|
-
It will write a header to the log file each time there is a file rotation.
|
|
275
|
-
|
|
276
|
-
:param log_file_path: Path to the log file.
|
|
277
|
-
:param when: When to rotate the log file. Possible
|
|
278
|
-
:param interval: Interval to rotate the log file.
|
|
279
|
-
:param delay: bool, If set to True, the log file will be created only if there's something to write.
|
|
280
|
-
:param encoding: Encoding to use for the log file. Same as for the TimeRotatingFileHandler, which uses Default None.
|
|
281
|
-
:param header: Header to write to the log file.
|
|
282
|
-
Example: "time,host,error"
|
|
283
|
-
:return: TimedRotatingFileHandlerWithHeader.
|
|
284
|
-
"""
|
|
285
|
-
|
|
286
|
-
return TimedRotatingFileHandlerWithHeader(
|
|
287
|
-
filename=log_file_path, when=when, interval=interval, delay=delay, encoding=encoding, header=header)
|
|
288
|
-
|
|
289
|
-
|
|
290
267
|
def start_queue_listener_for_file_handler(
|
|
291
268
|
file_handler: logging.FileHandler, queue_object) -> logging.handlers.QueueListener:
|
|
292
269
|
"""
|
|
@@ -351,72 +328,74 @@ def get_handler_name(handler: logging.Handler) -> str:
|
|
|
351
328
|
|
|
352
329
|
def change_rotated_filename(
|
|
353
330
|
file_handler: logging.Handler,
|
|
354
|
-
date_format_string: str = None
|
|
331
|
+
date_format_string: str = None,
|
|
332
|
+
callback_namer_function: callable = None,
|
|
333
|
+
use_default_callback_namer_function: bool = True
|
|
355
334
|
):
|
|
356
335
|
"""
|
|
357
336
|
Function to change the way TimedRotatingFileHandler managing the rotating filename.
|
|
358
337
|
|
|
359
338
|
:param file_handler: FileHandler to change the rotating filename for.
|
|
360
|
-
:param date_format_string: Date format string to
|
|
361
|
-
|
|
339
|
+
:param date_format_string: Date format string to set to the handler's suffix.
|
|
340
|
+
:param callback_namer_function: Callback function to change the filename on rotation.
|
|
341
|
+
:param use_default_callback_namer_function: If set to True, the default callback namer function will be used
|
|
342
|
+
and the filename will be changed on rotation instead of using the default like this:
|
|
343
|
+
'file.log.2021-12-24' -> 'file_2021-12-24.log'.
|
|
344
|
+
|
|
345
|
+
---------------------
|
|
346
|
+
|
|
347
|
+
At this point, 'file_handler.suffix' is already '%Y-%m-%d' if 'when' is set to 'midnight'.
|
|
348
|
+
You can change it if you wish (example: '%Y_%m_%d'), the method is described below.
|
|
362
349
|
"""
|
|
363
|
-
# Changing the way TimedRotatingFileHandler managing the rotating filename
|
|
364
|
-
# Default file suffix is only "Year_Month_Day" with addition of the dot (".") character to the
|
|
365
|
-
# "file name + extension" that you provide it. Example: log file name:
|
|
366
|
-
# test.log
|
|
367
|
-
# After file is rotated at midnight, by default the old filename will be:
|
|
368
|
-
# test.log.2021_12_24
|
|
369
|
-
# And the log file of 25th, now will be "test.log".
|
|
370
|
-
# So, Changing the file suffix to include the extension to the suffix, so it will be:
|
|
371
|
-
# test.log.2021_12_24.log
|
|
372
|
-
# file_handler.suffix = logfile_suffix
|
|
373
|
-
# file_handler.suffix = "_%Y_%m_%d.txt"
|
|
374
|
-
# This step will remove the created ".log." above before the suffix and the filename will look like:
|
|
375
|
-
# test.2021_12_24.log
|
|
376
|
-
# file_handler.namer = lambda name: name.replace(log_file_extension + ".", "") + log_file_extension
|
|
377
|
-
# file_handler.namer = lambda name: name.replace(".txt.", "") + log_file_extension
|
|
378
|
-
# This will recompile the string to tell the handler the length of the suffix parts
|
|
379
|
-
# file_handler.extMatch = re.compile(r"^\d{4}_\d{2}_\d{2}" + re.escape(log_file_extension) + r"$")
|
|
380
|
-
# file_handler.extMatch = re.compile(r"^\d{4}_\d{2}_\d{2}.txt$")
|
|
381
350
|
|
|
382
351
|
def callback_namer(name):
|
|
383
352
|
"""
|
|
384
353
|
Callback function to change the filename of the rotated log file on file rotation.
|
|
385
354
|
"""
|
|
386
355
|
# Currently the 'name' is full file path + '.' + logfile_suffix.
|
|
387
|
-
# Example: 'C:\\path\\to\\file.log.
|
|
356
|
+
# Example: 'C:\\path\\to\\file.log.2021-12-24'
|
|
388
357
|
# Get the parent directory of the file: C:\path\to
|
|
389
358
|
parent_dir: str = str(Path(name).parent)
|
|
390
359
|
# Get the base filename without the extension: file.log
|
|
391
360
|
filename: str = Path(name).stem
|
|
392
|
-
# Get the date part of the filename:
|
|
361
|
+
# Get the date part of the filename: 2021-12-24
|
|
393
362
|
date_part: str = str(Path(name).suffix).replace(".", "")
|
|
394
363
|
# Get the file extension: log
|
|
395
364
|
file_extension: str = Path(filename).suffix
|
|
396
365
|
# Get the file name without the extension: file
|
|
397
366
|
file_stem: str = Path(filename).stem
|
|
398
367
|
|
|
399
|
-
return f"{parent_dir}{os.sep}{file_stem}{date_part}{file_extension}"
|
|
368
|
+
return f"{parent_dir}{os.sep}{file_stem}_{date_part}{file_extension}"
|
|
369
|
+
|
|
370
|
+
def change_file_handler_suffix():
|
|
371
|
+
# Get regex pattern from string format.
|
|
372
|
+
# Example: '%Y_%m_%d' -> r'\d{4}_\d{2}_\d{2}'
|
|
373
|
+
date_regex_pattern = datetimes.datetime_format_to_regex(date_format_string)
|
|
400
374
|
|
|
401
|
-
|
|
402
|
-
|
|
375
|
+
# Regex pattern to match the rotated log filenames
|
|
376
|
+
logfile_regex_suffix = re.compile(date_regex_pattern)
|
|
403
377
|
|
|
404
|
-
|
|
405
|
-
|
|
378
|
+
# Update the handler's suffix to include the date format
|
|
379
|
+
file_handler.suffix = date_format_string
|
|
406
380
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
date_regex_pattern = datetimes.datetime_format_to_regex(date_format_string)
|
|
381
|
+
# Update the handler's extMatch regex to match the new filename format
|
|
382
|
+
file_handler.extMatch = logfile_regex_suffix
|
|
410
383
|
|
|
411
|
-
|
|
412
|
-
|
|
384
|
+
if use_default_callback_namer_function and callback_namer_function:
|
|
385
|
+
raise ValueError("You can't use both default and custom callback namer function.")
|
|
386
|
+
elif not use_default_callback_namer_function and not callback_namer_function:
|
|
387
|
+
raise ValueError(
|
|
388
|
+
"You need to provide a 'callback_namer_function' or our 'use_default_callback_namer_function'.")
|
|
413
389
|
|
|
414
|
-
|
|
415
|
-
|
|
390
|
+
if date_format_string:
|
|
391
|
+
change_file_handler_suffix()
|
|
416
392
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
393
|
+
# Set the callback function to change the filename on rotation.
|
|
394
|
+
if use_default_callback_namer_function:
|
|
395
|
+
file_handler.namer = callback_namer
|
|
396
|
+
|
|
397
|
+
if callback_namer_function:
|
|
398
|
+
file_handler.namer = callback_namer_function
|
|
420
399
|
|
|
421
400
|
|
|
422
401
|
def has_handlers(logger: logging.Logger) -> bool:
|
|
@@ -438,7 +417,7 @@ def has_handlers(logger: logging.Logger) -> bool:
|
|
|
438
417
|
return True
|
|
439
418
|
|
|
440
419
|
|
|
441
|
-
def extract_datetime_format_from_file_handler(file_handler: FileHandler) -> Union[str, None]:
|
|
420
|
+
def extract_datetime_format_from_file_handler(file_handler: logging.FileHandler) -> Union[str, None]:
|
|
442
421
|
"""
|
|
443
422
|
Extract the datetime string formats from all TimedRotatingFileHandlers in the logger.
|
|
444
423
|
|
|
@@ -456,3 +435,13 @@ def extract_datetime_format_from_file_handler(file_handler: FileHandler) -> Unio
|
|
|
456
435
|
return datetime_format
|
|
457
436
|
|
|
458
437
|
return None
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def add_filter_to_handler(handler: logging.Handler, filter_object: logging.Filter):
|
|
441
|
+
"""
|
|
442
|
+
Function to add a filter to the handler.
|
|
443
|
+
:param handler: Handler to add the filter to.
|
|
444
|
+
:param filter_object: Filter object to add to the handler.
|
|
445
|
+
"""
|
|
446
|
+
|
|
447
|
+
handler.addFilter(filter_object)
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
from typing import Literal, Union
|
|
4
4
|
|
|
5
|
-
from . import loggers, handlers
|
|
5
|
+
from . import loggers, handlers
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def create_logger(
|
|
@@ -26,6 +26,10 @@ def create_logger(
|
|
|
26
26
|
None] = None,
|
|
27
27
|
formatter_streamhandler_use_nanoseconds: bool = True,
|
|
28
28
|
formatter_filehandler_use_nanoseconds: bool = True,
|
|
29
|
+
filehandler_rotate_at_rollover_time: bool = True,
|
|
30
|
+
filehandler_rotation_date_format: str = None,
|
|
31
|
+
filehandler_rotation_callback_namer_function: callable = None,
|
|
32
|
+
filehandler_rotation_use_default_namer_function: bool = True,
|
|
29
33
|
when: str = "midnight",
|
|
30
34
|
interval: int = 1,
|
|
31
35
|
delay: bool = False,
|
|
@@ -67,6 +71,20 @@ def create_logger(
|
|
|
67
71
|
in the formatter in case you provide 'asctime' element.
|
|
68
72
|
:param formatter_filehandler_use_nanoseconds: bool, If set to True, the nanoseconds will be used
|
|
69
73
|
in the formatter in case you provide 'asctime' element.
|
|
74
|
+
:param filehandler_rotate_at_rollover_time: bool,
|
|
75
|
+
If set to True, the log file will be rotated at the rollover time, even if there's nothing to write.
|
|
76
|
+
If set to False, the log file will be rotated after 'when' time, but only when event occurs.
|
|
77
|
+
:param filehandler_rotation_date_format: string, Date format to use for the log file rotation.
|
|
78
|
+
Example for 'when="midnight"': the default date format is '%Y-%m-%d', resulting in filename on rotation like:
|
|
79
|
+
"test.log.2021-11-25"
|
|
80
|
+
If you want to change the date format to '%Y_%m_%d', the filename will be:
|
|
81
|
+
"test.log.2021_11_25"
|
|
82
|
+
:param filehandler_rotation_callback_namer_function: callable, Callback function to use for the log file naming
|
|
83
|
+
on rotation. If set to None, logging module default function will be used. With "when='midnight'",
|
|
84
|
+
and filename: "test.log" this will name the file on rotation similar to: "test.log.2021-11-25".
|
|
85
|
+
:param filehandler_rotation_use_default_namer_function: bool, If set to True, the default namer function will be
|
|
86
|
+
used for the log file naming on rotation. With "when='midnight'" and filename: "test.log",
|
|
87
|
+
this will name the file on rotation similar to: "test_2021-11-25.log".
|
|
70
88
|
:param when: string, When to rotate the log file. Default is 'midnight'.
|
|
71
89
|
[when="midnight"] is set to rotate the filename at midnight. This means that the current file name will be
|
|
72
90
|
added Yesterday's date to the end of the file and today's file will continue to write at the same
|
|
@@ -159,6 +177,10 @@ def create_logger(
|
|
|
159
177
|
handlers.add_timedfilehandler_with_queuehandler(
|
|
160
178
|
logger=logger, file_path=file_path, logging_level=logging_level, formatter=formatter_filehandler,
|
|
161
179
|
formatter_use_nanoseconds=formatter_filehandler_use_nanoseconds, file_type=file_type,
|
|
180
|
+
rotate_at_rollover_time=filehandler_rotate_at_rollover_time,
|
|
181
|
+
rotation_date_format=filehandler_rotation_date_format,
|
|
182
|
+
rotation_callback_namer_function=filehandler_rotation_callback_namer_function,
|
|
183
|
+
rotation_use_default_callback_namer_function=filehandler_rotation_use_default_namer_function,
|
|
162
184
|
when=when, interval=interval, delay=delay, encoding=encoding, header=header)
|
|
163
185
|
|
|
164
186
|
return logger
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=PiVCLhabPmU2Q-C1NK2tGxsEvO3IhNNFDCDH5O9gVbY,124
|
|
2
2
|
atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
|
|
3
3
|
atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
|
|
4
4
|
atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
|
|
@@ -124,7 +124,7 @@ atomicshop/mitm/config_editor.py,sha256=9ZwD6NGqgsr1f85NyFwWwM7FDut2vGQ4xari3vS9
|
|
|
124
124
|
atomicshop/mitm/connection_thread_worker.py,sha256=PQ8bwOgrPudYP5oPnSi_DWaKXOi038M8TMImlLkxuPI,20486
|
|
125
125
|
atomicshop/mitm/import_config.py,sha256=_V-IVJ7a1L6E-VOR4CDfZj-S1odbsIlBe13ij0NlpqY,7974
|
|
126
126
|
atomicshop/mitm/initialize_engines.py,sha256=YnXPK1UKrmULnfL4zLo2LOpKWq-aGKzc9p3n8tfcYCM,8170
|
|
127
|
-
atomicshop/mitm/initialize_mitm_server.py,sha256=
|
|
127
|
+
atomicshop/mitm/initialize_mitm_server.py,sha256=j1yMUbHsnFh9l5rFiUgBQA0mRZqREOKviP0frRzYikM,14611
|
|
128
128
|
atomicshop/mitm/message.py,sha256=u2U2f2SOHdBNU-6r1Ik2W14ai2EOwxUV4wVfGZA098k,1732
|
|
129
129
|
atomicshop/mitm/shared_functions.py,sha256=PaK_sbnEA5zo9k2ktEOKLmvo-6wRUunxzSNRr41uXIQ,1924
|
|
130
130
|
atomicshop/mitm/statistic_analyzer.py,sha256=ctsf-MBIUvG4-R0K4gFQyi_b42-VCq-5s7hgO9jMOes,38415
|
|
@@ -234,10 +234,11 @@ atomicshop/wrappers/factw/rest/statistics.py,sha256=vznwzKP1gEF7uXz3HsuV66BU9wrp
|
|
|
234
234
|
atomicshop/wrappers/factw/rest/status.py,sha256=4O3xS1poafwyUiLDkhyx4oMMe4PBwABuRPpOMnMKgIU,641
|
|
235
235
|
atomicshop/wrappers/fibratusw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
236
236
|
atomicshop/wrappers/fibratusw/install.py,sha256=PLVymDe0HuOvU0r2lje8BkQAgtiOWEeRO7n-1zKuL7A,3287
|
|
237
|
+
atomicshop/wrappers/loggingw/filters.py,sha256=CMs5PAMb68zxJgBcQobaOFDG5kLJBOVYnoBHjDgksO8,2859
|
|
237
238
|
atomicshop/wrappers/loggingw/formatters.py,sha256=808R7K3e3ZJD2BXfqI6UMOyXGrCgt9SYh2Uv7sL_1KQ,7432
|
|
238
|
-
atomicshop/wrappers/loggingw/handlers.py,sha256=
|
|
239
|
+
atomicshop/wrappers/loggingw/handlers.py,sha256=bv3oCm_P0JdXaJKYjhyfFNMNong6Nc9LE4JGFxLN2As,16940
|
|
239
240
|
atomicshop/wrappers/loggingw/loggers.py,sha256=DHOOTAtqkwn1xgvLHSkOiBm6yFGNuQy1kvbhG-TDog8,2374
|
|
240
|
-
atomicshop/wrappers/loggingw/loggingw.py,sha256=
|
|
241
|
+
atomicshop/wrappers/loggingw/loggingw.py,sha256=lo4OZPXCbYZi3GqpaaJSs9SOGFfqD2EgHzzTK7f5IR4,11275
|
|
241
242
|
atomicshop/wrappers/loggingw/reading.py,sha256=yh7uNPxEdn6KsxSKrYny2C57XdI25F5gaByz77CO_pw,17038
|
|
242
243
|
atomicshop/wrappers/nodejsw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
243
244
|
atomicshop/wrappers/nodejsw/install_nodejs.py,sha256=QZg-R2iTQt7kFb8wNtnTmwraSGwvUs34JIasdbNa7ZU,5154
|
|
@@ -283,8 +284,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
|
|
|
283
284
|
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
|
|
284
285
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
|
|
285
286
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
|
|
286
|
-
atomicshop-2.14.
|
|
287
|
-
atomicshop-2.14.
|
|
288
|
-
atomicshop-2.14.
|
|
289
|
-
atomicshop-2.14.
|
|
290
|
-
atomicshop-2.14.
|
|
287
|
+
atomicshop-2.14.10.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
288
|
+
atomicshop-2.14.10.dist-info/METADATA,sha256=K3bZy35OYR2tRgusU9gHTZPUKKkqVe2En2EzXuNjO2U,10479
|
|
289
|
+
atomicshop-2.14.10.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
290
|
+
atomicshop-2.14.10.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
291
|
+
atomicshop-2.14.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|