atomicshop 2.16.31__py3-none-any.whl → 2.16.33__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/basics/booleans.py +28 -40
- atomicshop/config_init.py +4 -4
- atomicshop/file_io/csvs.py +2 -3
- atomicshop/file_io/file_io.py +5 -3
- atomicshop/mitm/engines/__parent/recorder___parent.py +2 -18
- atomicshop/mitm/import_config.py +10 -9
- atomicshop/mitm/mitm_main.py +7 -0
- atomicshop/mitm/recs_files.py +4 -2
- atomicshop/mitm/shared_functions.py +0 -6
- atomicshop/mitm/statistic_analyzer.py +15 -3
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +82 -50
- atomicshop/print_api.py +1 -2
- atomicshop/system_resource_monitor.py +41 -40
- atomicshop/wrappers/ctyping/win_console.py +39 -0
- atomicshop/wrappers/loggingw/loggingw.py +1 -1
- atomicshop/wrappers/loggingw/reading.py +28 -11
- atomicshop/wrappers/mongodbw/mongodbw.py +50 -31
- atomicshop/wrappers/nodejsw/install_nodejs.py +7 -4
- atomicshop/wrappers/socketw/dns_server.py +8 -5
- atomicshop/wrappers/socketw/socket_wrapper.py +9 -5
- {atomicshop-2.16.31.dist-info → atomicshop-2.16.33.dist-info}/METADATA +1 -1
- {atomicshop-2.16.31.dist-info → atomicshop-2.16.33.dist-info}/RECORD +26 -25
- {atomicshop-2.16.31.dist-info → atomicshop-2.16.33.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.16.31.dist-info → atomicshop-2.16.33.dist-info}/WHEEL +0 -0
- {atomicshop-2.16.31.dist-info → atomicshop-2.16.33.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
atomicshop/basics/booleans.py
CHANGED
|
@@ -1,47 +1,35 @@
|
|
|
1
|
-
def
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
boolean3: tuple
|
|
1
|
+
def is_only_1_true_in_list(
|
|
2
|
+
booleans_list_of_tuples: list[tuple],
|
|
3
|
+
raise_if_all_false: bool = True
|
|
5
4
|
) -> None:
|
|
6
5
|
"""
|
|
7
|
-
Check if only one boolean can be 'True' from
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
:param
|
|
11
|
-
:
|
|
12
|
-
:return:
|
|
13
|
-
|
|
14
|
-
------------------------------------------------
|
|
15
|
-
|
|
16
|
-
Example:
|
|
17
|
-
check_3_booleans_when_only_1_can_be_true(
|
|
18
|
-
(self.config['section']['default_usage'], 'default_usage'),
|
|
19
|
-
(self.config['section']['create_usage'], 'create_usage'),
|
|
20
|
-
(self.config['section']['custom_usage'], 'custom_usage'))
|
|
6
|
+
Check if only one boolean can be 'True' from a list of booleans
|
|
7
|
+
:param booleans_list_of_tuples: list of tuples, Structure:
|
|
8
|
+
[(value, string name of the setting you want to print to the user to be aware of), ...]
|
|
9
|
+
:param raise_if_all_false: bool, If True, exception will be raised if all booleans are False.
|
|
10
|
+
:return: None
|
|
21
11
|
"""
|
|
22
12
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
f"{boolean2[1]}={boolean2[0]}\n"
|
|
44
|
-
raise ValueError(message)
|
|
13
|
+
# Filter to get all the `True` conditions and their associated names
|
|
14
|
+
true_conditions = [name for value, name in booleans_list_of_tuples if value]
|
|
15
|
+
|
|
16
|
+
# Count the number of True values
|
|
17
|
+
true_count = len(true_conditions)
|
|
18
|
+
|
|
19
|
+
if true_count == 1:
|
|
20
|
+
# Only one value is True, which is acceptable
|
|
21
|
+
# print(f"Only one condition is True: {true_conditions[0]}.")
|
|
22
|
+
pass
|
|
23
|
+
elif true_count > 1:
|
|
24
|
+
# More than one value is True, raise an exception
|
|
25
|
+
raise ValueError(f"Multiple conditions are True: {', '.join(true_conditions)}.")
|
|
26
|
+
elif true_count == 0 and raise_if_all_false:
|
|
27
|
+
# None of the values are True, and the user does not want to ignore this case
|
|
28
|
+
raise ValueError("No conditions are True, and raise_if_all_false is set to True.")
|
|
29
|
+
else:
|
|
30
|
+
# If no True values and no_raise_if_all_false is True, just pass silently
|
|
31
|
+
# print("No conditions are True (but raise_if_all_false is set to False).")
|
|
32
|
+
pass
|
|
45
33
|
|
|
46
34
|
|
|
47
35
|
def convert_string_to_bool(string: str) -> bool:
|
atomicshop/config_init.py
CHANGED
|
@@ -2,7 +2,7 @@ import os
|
|
|
2
2
|
|
|
3
3
|
from .file_io import tomls
|
|
4
4
|
from . import filesystem
|
|
5
|
-
from .
|
|
5
|
+
from . import print_api
|
|
6
6
|
|
|
7
7
|
CONFIG_FILE_NAME = 'config.toml'
|
|
8
8
|
CONFIG: dict = dict()
|
|
@@ -45,7 +45,7 @@ def write_config(
|
|
|
45
45
|
'CONFIG_FILE_NAME'.
|
|
46
46
|
:param print_message: boolean, if True, the function will print the message about the created config file.
|
|
47
47
|
Also, it will wait for the user to press Enter to exit the script.
|
|
48
|
-
If False, the function will not print anything and will not exit
|
|
48
|
+
If False, the function will not print anything and will not exit.
|
|
49
49
|
:return:
|
|
50
50
|
"""
|
|
51
51
|
|
|
@@ -62,7 +62,7 @@ def write_config(
|
|
|
62
62
|
tomls.write_toml_file(config, f'{script_directory}{os.sep}{config_file_name}')
|
|
63
63
|
|
|
64
64
|
if print_message:
|
|
65
|
-
print_api(f"Created config file: {config_file_path}", color="yellow")
|
|
66
|
-
print_api(f"You need to fill it with details.", color="yellow")
|
|
65
|
+
print_api.print_api(f"Created config file: {config_file_path}", color="yellow")
|
|
66
|
+
print_api.print_api(f"You need to fill it with details.", color="yellow")
|
|
67
67
|
input("Press Enter to exit.")
|
|
68
68
|
exit()
|
atomicshop/file_io/csvs.py
CHANGED
|
@@ -2,11 +2,10 @@ import csv
|
|
|
2
2
|
import io
|
|
3
3
|
from typing import Tuple, List
|
|
4
4
|
|
|
5
|
-
from .file_io import read_file_decorator
|
|
6
5
|
from . import file_io
|
|
7
6
|
|
|
8
7
|
|
|
9
|
-
@read_file_decorator
|
|
8
|
+
@file_io.read_file_decorator
|
|
10
9
|
def read_csv_to_list_of_dicts_by_header(
|
|
11
10
|
file_path: str,
|
|
12
11
|
file_mode: str = 'r',
|
|
@@ -53,7 +52,7 @@ def read_csv_to_list_of_dicts_by_header(
|
|
|
53
52
|
return csv_list, header
|
|
54
53
|
|
|
55
54
|
|
|
56
|
-
@read_file_decorator
|
|
55
|
+
@file_io.read_file_decorator
|
|
57
56
|
def read_csv_to_list_of_lists(
|
|
58
57
|
file_path: str,
|
|
59
58
|
file_mode: str = 'r',
|
atomicshop/file_io/file_io.py
CHANGED
|
@@ -2,7 +2,7 @@ from typing import Union
|
|
|
2
2
|
import functools
|
|
3
3
|
|
|
4
4
|
from .. import print_api
|
|
5
|
-
from ..
|
|
5
|
+
from .. import inspect_wrapper
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def get_write_file_mode_string_from_overwrite_bool(overwrite: bool) -> str:
|
|
@@ -17,7 +17,8 @@ def write_file_decorator(function_name):
|
|
|
17
17
|
def wrapper_write_file_decorator(*args, **kwargs):
|
|
18
18
|
# Put 'args' into 'kwargs' with appropriate key.
|
|
19
19
|
# args, kwargs = put_args_to_kwargs(function_name, *args, **kwargs)
|
|
20
|
-
args, kwargs = get_target_function_default_args_and_combine_with_current(
|
|
20
|
+
args, kwargs = inspect_wrapper.get_target_function_default_args_and_combine_with_current(
|
|
21
|
+
function_name, *args, **kwargs)
|
|
21
22
|
|
|
22
23
|
print_api.print_api(message=f"Writing file: {kwargs['file_path']}", **kwargs)
|
|
23
24
|
|
|
@@ -51,7 +52,8 @@ def read_file_decorator(function_name):
|
|
|
51
52
|
def wrapper_read_file_decorator(*args, **kwargs):
|
|
52
53
|
# Put 'args' into 'kwargs' with appropriate key.
|
|
53
54
|
# args, kwargs = put_args_to_kwargs(function_name, *args, **kwargs)
|
|
54
|
-
args, kwargs = get_target_function_default_args_and_combine_with_current(
|
|
55
|
+
args, kwargs = inspect_wrapper.get_target_function_default_args_and_combine_with_current(
|
|
56
|
+
function_name, *args, **kwargs)
|
|
55
57
|
|
|
56
58
|
continue_loop: bool = True
|
|
57
59
|
while continue_loop:
|
|
@@ -2,9 +2,9 @@ import os
|
|
|
2
2
|
from datetime import datetime
|
|
3
3
|
import json
|
|
4
4
|
|
|
5
|
-
from ...shared_functions import build_module_names, create_custom_logger
|
|
5
|
+
from ...shared_functions import build_module_names, create_custom_logger
|
|
6
6
|
from ... import message, recs_files
|
|
7
|
-
from .... import filesystem
|
|
7
|
+
from .... import filesystem
|
|
8
8
|
from ....file_io import file_io
|
|
9
9
|
|
|
10
10
|
|
|
@@ -46,21 +46,6 @@ class RecorderParent:
|
|
|
46
46
|
# Build the record path with file name
|
|
47
47
|
self.build_record_path_to_engine()
|
|
48
48
|
|
|
49
|
-
# Define empty 'http_path'.
|
|
50
|
-
http_path: str = str()
|
|
51
|
-
# If 'self.class_client_message.request_raw_decoded.path' will be undefined, exception will raise.
|
|
52
|
-
# This will happen if the message is not HTTP.
|
|
53
|
-
try:
|
|
54
|
-
# Parse the url to components.
|
|
55
|
-
http_path_parsed = urls.url_parser(self.class_client_message.request_raw_decoded.path)
|
|
56
|
-
# Get only directories.
|
|
57
|
-
http_path_directories_string = '-'.join(http_path_parsed['directories'])
|
|
58
|
-
# Add '_' character before 'http_path' to look better on the file name.
|
|
59
|
-
http_path = f'_{http_path_directories_string}'
|
|
60
|
-
# If 'self.class_client_message.request_raw_decoded.path' is not defined, we'll pass the exception.
|
|
61
|
-
except Exception:
|
|
62
|
-
pass
|
|
63
|
-
|
|
64
49
|
# If HTTP Path is not defined, 'http_path' will be empty, and it will not interfere with file name.
|
|
65
50
|
self.record_file_path: str = \
|
|
66
51
|
self.engine_record_path + os.sep + \
|
|
@@ -88,7 +73,6 @@ class RecorderParent:
|
|
|
88
73
|
# Convert the requests and responses to hex.
|
|
89
74
|
self.convert_messages()
|
|
90
75
|
# Get the message in dict / JSON format
|
|
91
|
-
# record_message = get_json(self.class_client_message)
|
|
92
76
|
record_message_dict: dict = dict(self.class_client_message)
|
|
93
77
|
recorded_message_json_string = json.dumps(record_message_dict)
|
|
94
78
|
|
atomicshop/mitm/import_config.py
CHANGED
|
@@ -93,19 +93,20 @@ def check_configurations() -> int:
|
|
|
93
93
|
print_api(message, color='red')
|
|
94
94
|
return 1
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
try:
|
|
100
|
-
booleans.check_3_booleans_when_only_1_can_be_true(
|
|
96
|
+
try:
|
|
97
|
+
booleans.is_only_1_true_in_list(
|
|
98
|
+
booleans_list_of_tuples=[
|
|
101
99
|
(config_static.DNSServer.set_default_dns_gateway, '[dns][set_default_dns_gateway]'),
|
|
102
100
|
(config_static.DNSServer.set_default_dns_gateway_to_localhost,
|
|
103
101
|
'[dns][set_default_dns_gateway_to_localhost]'),
|
|
104
102
|
(config_static.DNSServer.set_default_dns_gateway_to_default_interface_ipv4,
|
|
105
|
-
'[dns][set_default_dns_gateway_to_default_interface_ipv4]')
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
'[dns][set_default_dns_gateway_to_default_interface_ipv4]')
|
|
104
|
+
],
|
|
105
|
+
raise_if_all_false=False
|
|
106
|
+
)
|
|
107
|
+
except ValueError as e:
|
|
108
|
+
print_api(str(e), color='red')
|
|
109
|
+
return 1
|
|
109
110
|
|
|
110
111
|
if (config_static.DNSServer.set_default_dns_gateway or
|
|
111
112
|
config_static.DNSServer.set_default_dns_gateway_to_localhost or
|
atomicshop/mitm/mitm_main.py
CHANGED
|
@@ -10,6 +10,7 @@ from ..permissions import permissions
|
|
|
10
10
|
from ..python_functions import get_current_python_version_string, check_python_version_compliance
|
|
11
11
|
from ..wrappers.socketw import socket_wrapper, dns_server, base
|
|
12
12
|
from ..wrappers.loggingw import loggingw
|
|
13
|
+
from ..wrappers.ctyping import win_console
|
|
13
14
|
|
|
14
15
|
from .initialize_engines import ModuleCategory
|
|
15
16
|
from .connection_thread_worker import thread_worker_main
|
|
@@ -28,6 +29,12 @@ EXCEPTIONS_CSV_LOGGER_HEADER: str = 'time,exception'
|
|
|
28
29
|
MITM_ERROR_LOGGER: loggingw.ExceptionCsvLogger = None
|
|
29
30
|
|
|
30
31
|
|
|
32
|
+
try:
|
|
33
|
+
win_console.disable_quick_edit()
|
|
34
|
+
except win_console.NotWindowsConsoleError:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
31
38
|
def exit_cleanup():
|
|
32
39
|
if permissions.is_admin():
|
|
33
40
|
is_dns_dynamic, current_dns_gateway = dns.get_default_dns_gateway()
|
atomicshop/mitm/recs_files.py
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
import os
|
|
3
3
|
import multiprocessing
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
from ..archiver import zips
|
|
6
7
|
from .. import filesystem
|
|
8
|
+
from .. wrappers.loggingw import consts
|
|
7
9
|
|
|
8
10
|
|
|
9
|
-
REC_FILE_DATE_TIME_FORMAT: str = "%
|
|
10
|
-
REC_FILE_DATE_FORMAT: str = REC_FILE_DATE_TIME_FORMAT.split('
|
|
11
|
+
REC_FILE_DATE_TIME_FORMAT: str = f'{consts.DEFAULT_ROTATING_SUFFIXES_FROM_WHEN["S"]}_%f'
|
|
12
|
+
REC_FILE_DATE_FORMAT: str = REC_FILE_DATE_TIME_FORMAT.split('_')[0]
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
def recs_archiver(recs_directory: str) -> list:
|
|
@@ -38,9 +38,3 @@ def create_custom_logger():
|
|
|
38
38
|
logger_name = f'{config_static.MainConfig.LOGGER_NAME}.{engine_logger_part}'
|
|
39
39
|
|
|
40
40
|
return loggingw.get_logger_with_level(logger_name)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def get_json(obj):
|
|
44
|
-
""" Convert any nested object to json / dict and values to string as is """
|
|
45
|
-
|
|
46
|
-
return json.dumps(obj, default=dicts.convert_complex_object_to_dict)
|
|
@@ -354,7 +354,8 @@ def deviation_calculator_by_moving_average(
|
|
|
354
354
|
summary: bool = False,
|
|
355
355
|
output_file_path: str = None,
|
|
356
356
|
output_file_type: Literal['json', 'csv'] = 'json',
|
|
357
|
-
convert_sizes_lists_and_ma_data_to_string: bool = False
|
|
357
|
+
convert_sizes_lists_and_ma_data_to_string: bool = False,
|
|
358
|
+
skip_total_count_less_than: int = None
|
|
358
359
|
) -> Union[list, None]:
|
|
359
360
|
"""
|
|
360
361
|
This function is the main function for the moving average calculator.
|
|
@@ -386,6 +387,12 @@ def deviation_calculator_by_moving_average(
|
|
|
386
387
|
:param output_file_type: string, the type of the output file. 'json' or 'csv'.
|
|
387
388
|
:param convert_sizes_lists_and_ma_data_to_string: bool, if True, the 'request_sizes', 'response_sizes' and 'ma_data'
|
|
388
389
|
will be converted to string. This is useful when writing to files, so the view will be more readable.
|
|
390
|
+
:param skip_total_count_less_than: integer, if specified, the deviation calculation will be skipped
|
|
391
|
+
if the total count is less than this number.
|
|
392
|
+
This means that if we have moving average window of 7 days, on the 8th day, the deviation will be calculated
|
|
393
|
+
only if the total count of the checked type
|
|
394
|
+
(request average size, response average, request count, response count)
|
|
395
|
+
is greater or equal to this number.
|
|
389
396
|
-----------------------------
|
|
390
397
|
:return: the deviation list of dicts.
|
|
391
398
|
|
|
@@ -427,7 +434,8 @@ def deviation_calculator_by_moving_average(
|
|
|
427
434
|
by_type,
|
|
428
435
|
moving_average_window_days,
|
|
429
436
|
top_bottom_deviation_percentage,
|
|
430
|
-
get_deviation_for_last_day_only
|
|
437
|
+
get_deviation_for_last_day_only,
|
|
438
|
+
skip_total_count_less_than
|
|
431
439
|
)
|
|
432
440
|
|
|
433
441
|
if deviation_list:
|
|
@@ -484,6 +492,9 @@ def deviation_calculator_by_moving_average_main():
|
|
|
484
492
|
parser.add_argument(
|
|
485
493
|
'-p', '--percentage', type=float, required=True,
|
|
486
494
|
help='Percentage of deviation from moving average. Example: 0.1 for 10%%.')
|
|
495
|
+
parser.add_argument(
|
|
496
|
+
'-slt', '--skip_total_count_less_than', type=int, required=False,
|
|
497
|
+
help='An integer to skip the deviation calculation if the total count is less than this number.')
|
|
487
498
|
|
|
488
499
|
return parser.parse_args()
|
|
489
500
|
|
|
@@ -517,7 +528,8 @@ def deviation_calculator_by_moving_average_main():
|
|
|
517
528
|
summary=summary,
|
|
518
529
|
output_file_path=args.output_file,
|
|
519
530
|
output_file_type=args.output_type,
|
|
520
|
-
convert_sizes_lists_and_ma_data_to_string=convert_sizes_lists_and_ma_data_to_string
|
|
531
|
+
convert_sizes_lists_and_ma_data_to_string=convert_sizes_lists_and_ma_data_to_string,
|
|
532
|
+
skip_total_count_less_than=args.skip_total_count_less_than
|
|
521
533
|
)
|
|
522
534
|
|
|
523
535
|
return 0
|
|
@@ -14,6 +14,7 @@ def calculate_moving_average(
|
|
|
14
14
|
moving_average_window_days,
|
|
15
15
|
top_bottom_deviation_percentage: float,
|
|
16
16
|
get_deviation_for_last_day_only: bool = False,
|
|
17
|
+
skip_total_count_less_than: int = None,
|
|
17
18
|
print_kwargs: dict = None
|
|
18
19
|
) -> list:
|
|
19
20
|
"""
|
|
@@ -37,6 +38,7 @@ def calculate_moving_average(
|
|
|
37
38
|
Files 01 to 05 will be used for moving average and the file 06 for deviation.
|
|
38
39
|
Meaning the average calculated for 2021-01-06 will be compared to the values moving average of 2021-01-01
|
|
39
40
|
to 2021-01-05.
|
|
41
|
+
:param skip_total_count_less_than: integer, if the total count is less than this number, skip the deviation.
|
|
40
42
|
:param print_kwargs: dict, the print_api arguments.
|
|
41
43
|
"""
|
|
42
44
|
|
|
@@ -55,7 +57,7 @@ def calculate_moving_average(
|
|
|
55
57
|
statistics_content: dict = {}
|
|
56
58
|
# Read each file to its day.
|
|
57
59
|
for log_atomic_path in logs_paths:
|
|
58
|
-
date_string = log_atomic_path.datetime_string
|
|
60
|
+
date_string: str = log_atomic_path.datetime_string
|
|
59
61
|
statistics_content[date_string] = {}
|
|
60
62
|
|
|
61
63
|
statistics_content[date_string]['file'] = log_atomic_path
|
|
@@ -65,11 +67,11 @@ def calculate_moving_average(
|
|
|
65
67
|
statistics_content[date_string]['content'] = log_file_content
|
|
66
68
|
statistics_content[date_string]['header'] = log_file_header
|
|
67
69
|
|
|
68
|
-
statistics_content[date_string]['
|
|
70
|
+
statistics_content[date_string]['content_no_useless'] = get_content_without_useless(log_file_content)
|
|
69
71
|
|
|
70
72
|
# Get the data dictionary from the statistics content.
|
|
71
73
|
statistics_content[date_string]['statistics_daily'] = compute_statistics_from_content(
|
|
72
|
-
statistics_content[date_string]['
|
|
74
|
+
statistics_content[date_string]['content_no_useless'], by_type)
|
|
73
75
|
|
|
74
76
|
moving_average_dict: dict = compute_moving_averages_from_average_statistics(
|
|
75
77
|
statistics_content,
|
|
@@ -85,12 +87,12 @@ def calculate_moving_average(
|
|
|
85
87
|
|
|
86
88
|
# Find deviation from the moving average to the bottom or top by specified percentage.
|
|
87
89
|
deviation_list: list = find_deviation_from_moving_average(
|
|
88
|
-
statistics_content, top_bottom_deviation_percentage)
|
|
90
|
+
statistics_content, top_bottom_deviation_percentage, skip_total_count_less_than)
|
|
89
91
|
|
|
90
92
|
return deviation_list
|
|
91
93
|
|
|
92
94
|
|
|
93
|
-
def
|
|
95
|
+
def get_content_without_useless(content: list) -> list:
|
|
94
96
|
"""
|
|
95
97
|
This function gets the 'statistics.csv' file content without errors from the 'content' list.
|
|
96
98
|
|
|
@@ -101,7 +103,7 @@ def get_content_without_errors(content: list) -> list:
|
|
|
101
103
|
traffic_statistics_without_errors: list = []
|
|
102
104
|
for line in content:
|
|
103
105
|
# Skip empty lines, headers and errors.
|
|
104
|
-
if line['host'] == 'host' or line['
|
|
106
|
+
if line['host'] == 'host' or (line['request_size_bytes'] == '' and line['response_size_bytes'] == ''):
|
|
105
107
|
continue
|
|
106
108
|
|
|
107
109
|
traffic_statistics_without_errors.append(line)
|
|
@@ -152,16 +154,13 @@ def get_data_dict_from_statistics_content(
|
|
|
152
154
|
try:
|
|
153
155
|
request_size_bytes = line['request_size_bytes']
|
|
154
156
|
response_size_bytes = line['response_size_bytes']
|
|
155
|
-
if request_size_bytes
|
|
156
|
-
|
|
157
|
-
if response_size_bytes
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
hosts_requests_responses[type_to_check]['request_sizes'].append(int(request_size_bytes))
|
|
161
|
-
hosts_requests_responses[type_to_check]['response_sizes'].append(int(response_size_bytes))
|
|
162
|
-
except ValueError:
|
|
157
|
+
if request_size_bytes != '':
|
|
158
|
+
hosts_requests_responses[type_to_check]['request_sizes'].append(int(request_size_bytes))
|
|
159
|
+
if response_size_bytes != '':
|
|
160
|
+
hosts_requests_responses[type_to_check]['response_sizes'].append(int(response_size_bytes))
|
|
161
|
+
except ValueError as e:
|
|
163
162
|
print_api(line, color='yellow')
|
|
164
|
-
raise
|
|
163
|
+
raise e
|
|
165
164
|
|
|
166
165
|
return hosts_requests_responses
|
|
167
166
|
|
|
@@ -175,13 +174,15 @@ def compute_statistics_from_data_dict(data_dict: dict):
|
|
|
175
174
|
"""
|
|
176
175
|
|
|
177
176
|
for host, host_dict in data_dict.items():
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
177
|
+
count_requests = len(host_dict['request_sizes'])
|
|
178
|
+
count_responses = len(host_dict['response_sizes'])
|
|
179
|
+
avg_request_size = statistics.mean(host_dict['request_sizes']) if count_requests > 0 else 0
|
|
180
|
+
median_request_size = statistics.median(host_dict['request_sizes']) if count_requests > 0 else 0
|
|
181
|
+
avg_response_size = statistics.mean(host_dict['response_sizes']) if count_responses > 0 else 0
|
|
182
|
+
median_response_size = statistics.median(host_dict['response_sizes']) if count_responses > 0 else 0
|
|
183
|
+
|
|
184
|
+
data_dict[host]['count_requests'] = count_requests
|
|
185
|
+
data_dict[host]['count_responses'] = count_responses
|
|
185
186
|
data_dict[host]['avg_request_size'] = avg_request_size
|
|
186
187
|
data_dict[host]['median_request_size'] = median_request_size
|
|
187
188
|
data_dict[host]['avg_response_size'] = avg_response_size
|
|
@@ -251,14 +252,16 @@ def compute_average_for_current_day_from_past_x_days(
|
|
|
251
252
|
for host, host_dict in statistics_daily.items():
|
|
252
253
|
if host not in moving_average:
|
|
253
254
|
moving_average[host] = {
|
|
254
|
-
'
|
|
255
|
+
'all_request_counts': [],
|
|
256
|
+
'all_response_counts': [],
|
|
255
257
|
'avg_request_sizes': [],
|
|
256
258
|
'avg_response_sizes': [],
|
|
257
259
|
'median_request_sizes': [],
|
|
258
260
|
'median_response_sizes': []
|
|
259
261
|
}
|
|
260
262
|
|
|
261
|
-
moving_average[host]['
|
|
263
|
+
moving_average[host]['all_request_counts'].append(int(host_dict['count_requests']))
|
|
264
|
+
moving_average[host]['all_response_counts'].append(int(host_dict['count_responses']))
|
|
262
265
|
moving_average[host]['avg_request_sizes'].append(float(host_dict['avg_request_size']))
|
|
263
266
|
moving_average[host]['avg_response_sizes'].append(float(host_dict['avg_response_size']))
|
|
264
267
|
moving_average[host]['median_request_sizes'].append(float(host_dict['median_request_size']))
|
|
@@ -267,21 +270,26 @@ def compute_average_for_current_day_from_past_x_days(
|
|
|
267
270
|
# Compute the moving average.
|
|
268
271
|
moving_average_results: dict = {}
|
|
269
272
|
for host, host_dict in moving_average.items():
|
|
270
|
-
|
|
273
|
+
ma_request_count = statistics.mean(host_dict['all_request_counts'])
|
|
274
|
+
ma_response_count = statistics.mean(host_dict['all_response_counts'])
|
|
271
275
|
ma_request_size = statistics.mean(host_dict['avg_request_sizes'])
|
|
272
276
|
ma_response_size = statistics.mean(host_dict['avg_response_sizes'])
|
|
273
|
-
|
|
277
|
+
mm_request_count = statistics.median(host_dict['all_request_counts'])
|
|
278
|
+
mm_response_count = statistics.median(host_dict['all_response_counts'])
|
|
274
279
|
mm_request_size = statistics.median(host_dict['median_request_sizes'])
|
|
275
280
|
mm_response_size = statistics.median(host_dict['median_response_sizes'])
|
|
276
281
|
|
|
277
282
|
moving_average_results[host] = {
|
|
278
|
-
'
|
|
283
|
+
'ma_request_count': ma_request_count,
|
|
284
|
+
'ma_response_count': ma_response_count,
|
|
279
285
|
'ma_request_size': ma_request_size,
|
|
280
286
|
'ma_response_size': ma_response_size,
|
|
281
|
-
'
|
|
287
|
+
'mm_request_count': mm_request_count,
|
|
288
|
+
'mm_response_count': mm_response_count,
|
|
282
289
|
'mm_request_size': mm_request_size,
|
|
283
290
|
'mm_response_size': mm_response_size,
|
|
284
|
-
'
|
|
291
|
+
'all_request_counts': host_dict['all_request_counts'],
|
|
292
|
+
'all_response_counts': host_dict['all_response_counts'],
|
|
285
293
|
'avg_request_sizes': host_dict['avg_request_sizes'],
|
|
286
294
|
'avg_response_sizes': host_dict['avg_response_sizes'],
|
|
287
295
|
'median_request_sizes': host_dict['median_request_sizes'],
|
|
@@ -293,7 +301,8 @@ def compute_average_for_current_day_from_past_x_days(
|
|
|
293
301
|
|
|
294
302
|
def find_deviation_from_moving_average(
|
|
295
303
|
statistics_content: dict,
|
|
296
|
-
top_bottom_deviation_percentage: float
|
|
304
|
+
top_bottom_deviation_percentage: float,
|
|
305
|
+
skip_total_count_less_than: int = None
|
|
297
306
|
) -> list:
|
|
298
307
|
"""
|
|
299
308
|
This function finds the deviation from the moving average to the bottom or top by specified percentage.
|
|
@@ -301,12 +310,13 @@ def find_deviation_from_moving_average(
|
|
|
301
310
|
:param statistics_content: dict, the statistics content dictionary.
|
|
302
311
|
:param top_bottom_deviation_percentage: float, the percentage of deviation from the moving average to the top or
|
|
303
312
|
bottom.
|
|
313
|
+
:param skip_total_count_less_than: integer, if the total count is less than this number, skip the deviation.
|
|
304
314
|
:return: list, the deviation list.
|
|
305
315
|
"""
|
|
306
316
|
|
|
307
317
|
def _check_deviation(
|
|
308
|
-
|
|
309
|
-
|
|
318
|
+
check: Literal['count', 'avg'],
|
|
319
|
+
traffic_direction: Literal['request', 'response'],
|
|
310
320
|
day_statistics_content_dict: dict,
|
|
311
321
|
moving_averages_dict: dict
|
|
312
322
|
):
|
|
@@ -316,6 +326,19 @@ def find_deviation_from_moving_average(
|
|
|
316
326
|
|
|
317
327
|
nonlocal message
|
|
318
328
|
|
|
329
|
+
if check == 'count':
|
|
330
|
+
check_type = f'{check}_{traffic_direction}s'
|
|
331
|
+
ma_check_type = f'ma_{traffic_direction}_{check}'
|
|
332
|
+
median_type_string = check_type
|
|
333
|
+
moving_median_type_string = f'mm_{traffic_direction}_{check}'
|
|
334
|
+
elif check == 'avg':
|
|
335
|
+
check_type = f'{check}_{traffic_direction}_size'
|
|
336
|
+
ma_check_type = f'ma_{traffic_direction}_size'
|
|
337
|
+
median_type_string = f'median_{traffic_direction}_size'
|
|
338
|
+
moving_median_type_string = f'mm_{traffic_direction}_size'
|
|
339
|
+
else:
|
|
340
|
+
raise ValueError(f'Invalid check: {check}')
|
|
341
|
+
|
|
319
342
|
host_moving_average_by_type = moving_averages_dict[host][ma_check_type]
|
|
320
343
|
check_type_moving_by_percent = (
|
|
321
344
|
host_moving_average_by_type * top_bottom_deviation_percentage)
|
|
@@ -324,11 +347,15 @@ def find_deviation_from_moving_average(
|
|
|
324
347
|
|
|
325
348
|
deviation_type = None
|
|
326
349
|
deviation_percentage = None
|
|
350
|
+
error_message: str = str()
|
|
327
351
|
if day_statistics_content_dict[check_type] > check_type_moving_above:
|
|
328
352
|
deviation_type = 'above'
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
353
|
+
try:
|
|
354
|
+
deviation_percentage = (
|
|
355
|
+
(day_statistics_content_dict[check_type] - host_moving_average_by_type) /
|
|
356
|
+
host_moving_average_by_type)
|
|
357
|
+
except ZeroDivisionError as e:
|
|
358
|
+
error_message = f' | Error: Division by 0, host_moving_average_by_type: {host_moving_average_by_type}'
|
|
332
359
|
elif day_statistics_content_dict[check_type] < check_type_moving_below:
|
|
333
360
|
deviation_type = 'below'
|
|
334
361
|
deviation_percentage = (
|
|
@@ -336,31 +363,34 @@ def find_deviation_from_moving_average(
|
|
|
336
363
|
host_moving_average_by_type)
|
|
337
364
|
|
|
338
365
|
if deviation_type:
|
|
339
|
-
message = f'[{check_type}] is [{deviation_type}] the moving average.'
|
|
340
|
-
|
|
341
|
-
# Get the right moving median.
|
|
342
|
-
if check_type == 'count':
|
|
343
|
-
median_type_string: str = 'count'
|
|
344
|
-
moving_median_type_string: str = 'mm_count'
|
|
345
|
-
else:
|
|
346
|
-
median_type_string: str = check_type.replace('avg', 'median')
|
|
347
|
-
moving_median_type_string: str = check_type.replace('avg', 'mm')
|
|
366
|
+
message = f'[{check_type}] is [{deviation_type}] the moving average.' + error_message
|
|
348
367
|
|
|
349
368
|
# The median and the total count are None for the count, Since they are the count.
|
|
350
|
-
if
|
|
369
|
+
if 'count' in check_type:
|
|
351
370
|
total_entries_averaged = None
|
|
352
371
|
median_size = None
|
|
353
372
|
else:
|
|
354
|
-
total_entries_averaged = day_statistics_content_dict['
|
|
373
|
+
total_entries_averaged = day_statistics_content_dict[f'count_{traffic_direction}s']
|
|
355
374
|
median_size = day_statistics_content_dict[median_type_string]
|
|
356
375
|
|
|
376
|
+
value = day_statistics_content_dict[check_type]
|
|
377
|
+
|
|
378
|
+
# If the total count is less than the specified number, skip the deviation.
|
|
379
|
+
if skip_total_count_less_than:
|
|
380
|
+
if total_entries_averaged:
|
|
381
|
+
if total_entries_averaged < skip_total_count_less_than:
|
|
382
|
+
return
|
|
383
|
+
else:
|
|
384
|
+
if value < skip_total_count_less_than:
|
|
385
|
+
return
|
|
386
|
+
|
|
357
387
|
moving_median_size = moving_averages_dict[host][moving_median_type_string]
|
|
358
388
|
|
|
359
389
|
deviation_list.append({
|
|
360
390
|
'day': day,
|
|
361
391
|
'host': host,
|
|
362
392
|
'message': message,
|
|
363
|
-
'value':
|
|
393
|
+
'value': value,
|
|
364
394
|
'ma_value': host_moving_average_by_type,
|
|
365
395
|
'check_type': check_type,
|
|
366
396
|
'percentage': top_bottom_deviation_percentage,
|
|
@@ -411,10 +441,12 @@ def find_deviation_from_moving_average(
|
|
|
411
441
|
continue
|
|
412
442
|
|
|
413
443
|
_check_deviation(
|
|
414
|
-
'count', '
|
|
444
|
+
'count', 'request', host_dict, previous_day_moving_average_dict)
|
|
445
|
+
_check_deviation(
|
|
446
|
+
'count', 'response', host_dict, previous_day_moving_average_dict)
|
|
415
447
|
_check_deviation(
|
|
416
|
-
'
|
|
448
|
+
'avg', 'request', host_dict, previous_day_moving_average_dict)
|
|
417
449
|
_check_deviation(
|
|
418
|
-
'
|
|
450
|
+
'avg', 'response', host_dict, previous_day_moving_average_dict)
|
|
419
451
|
|
|
420
452
|
return deviation_list
|
atomicshop/print_api.py
CHANGED
|
@@ -2,7 +2,6 @@ import sys
|
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
4
|
from .basics import ansi_escape_codes
|
|
5
|
-
from .wrappers.loggingw import loggingw
|
|
6
5
|
from .basics import tracebacks
|
|
7
6
|
|
|
8
7
|
|
|
@@ -74,6 +73,7 @@ def print_api(
|
|
|
74
73
|
|
|
75
74
|
# Inner functions already get all the local variables of the main function.
|
|
76
75
|
def print_or_logger():
|
|
76
|
+
from .wrappers.loggingw import loggingw
|
|
77
77
|
nonlocal message
|
|
78
78
|
nonlocal color
|
|
79
79
|
nonlocal traceback_string
|
|
@@ -128,7 +128,6 @@ def print_api(
|
|
|
128
128
|
if print_end == '\n':
|
|
129
129
|
if stdcolor and color is not None:
|
|
130
130
|
# Use logger to output message.
|
|
131
|
-
# with loggingw.temporary_change_logger_stream_handler_color(logger, color=color):
|
|
132
131
|
with loggingw.temporary_change_logger_stream_handler_emit_color(logger, color):
|
|
133
132
|
getattr(logger, logger_method)(message)
|
|
134
133
|
else:
|
|
@@ -118,51 +118,12 @@ class SystemResourceMonitor:
|
|
|
118
118
|
:return:
|
|
119
119
|
"""
|
|
120
120
|
|
|
121
|
-
def run_check_system_resources(
|
|
122
|
-
interval, get_cpu, get_memory, get_disk_io_bytes, get_disk_files_count, get_disk_busy_time,
|
|
123
|
-
get_disk_used_percent, calculate_maximum_changed_disk_io, maximum_disk_io, queue_list, manager_dict):
|
|
124
|
-
"""
|
|
125
|
-
Continuously update the system resources in the shared results dictionary.
|
|
126
|
-
This function runs in a separate process.
|
|
127
|
-
"""
|
|
128
|
-
|
|
129
|
-
while self.running:
|
|
130
|
-
# Get the results of the system resources check function and store them in
|
|
131
|
-
# temporary results' dictionary.
|
|
132
|
-
results = system_resources.check_system_resources(
|
|
133
|
-
interval=interval, get_cpu=get_cpu, get_memory=get_memory,
|
|
134
|
-
get_disk_io_bytes=get_disk_io_bytes, get_disk_files_count=get_disk_files_count,
|
|
135
|
-
get_disk_busy_time=get_disk_busy_time, get_disk_used_percent=get_disk_used_percent)
|
|
136
|
-
|
|
137
|
-
if calculate_maximum_changed_disk_io:
|
|
138
|
-
if results['disk_io_read'] > maximum_disk_io['read_bytes_per_sec']:
|
|
139
|
-
maximum_disk_io['read_bytes_per_sec'] = results['disk_io_read']
|
|
140
|
-
if results['disk_io_write'] > maximum_disk_io['write_bytes_per_sec']:
|
|
141
|
-
maximum_disk_io['write_bytes_per_sec'] = results['disk_io_write']
|
|
142
|
-
if results['disk_files_count_read'] > maximum_disk_io['read_files_count_per_sec']:
|
|
143
|
-
maximum_disk_io['read_files_count_per_sec'] = results['disk_files_count_read']
|
|
144
|
-
if results['disk_files_count_write'] > maximum_disk_io['write_files_count_per_sec']:
|
|
145
|
-
maximum_disk_io['write_files_count_per_sec'] = results['disk_files_count_write']
|
|
146
|
-
results['maximum_disk_io'] = maximum_disk_io
|
|
147
|
-
|
|
148
|
-
if queue_list is not None:
|
|
149
|
-
for queue in queue_list:
|
|
150
|
-
queue.put(results)
|
|
151
|
-
|
|
152
|
-
# Update the shared results dictionary with the temporary results' dictionary.
|
|
153
|
-
# This is done in separate steps to avoid overwriting the special 'multiprocessing.Manager.dict' object.
|
|
154
|
-
# So we update the shared results dictionary with the temporary results' dictionary.
|
|
155
|
-
if manager_dict is not None:
|
|
156
|
-
manager_dict.update(results)
|
|
157
|
-
|
|
158
|
-
self.results = results
|
|
159
|
-
|
|
160
121
|
if print_kwargs is None:
|
|
161
122
|
print_kwargs = {}
|
|
162
123
|
|
|
163
124
|
if self.thread is None:
|
|
164
125
|
self.running = True
|
|
165
|
-
self.thread = threading.Thread(target=run_check_system_resources, args=(
|
|
126
|
+
self.thread = threading.Thread(target=self.run_check_system_resources, args=(
|
|
166
127
|
self.interval, self.get_cpu, self.get_memory, self.get_disk_io_bytes, self.get_disk_files_count,
|
|
167
128
|
self.get_disk_busy_time, self.get_disk_used_percent, self.calculate_maximum_changed_disk_io,
|
|
168
129
|
self.maximum_disk_io, self.queue_list, self.manager_dict))
|
|
@@ -171,6 +132,46 @@ class SystemResourceMonitor:
|
|
|
171
132
|
else:
|
|
172
133
|
print_api.print_api("Monitoring is already running.", color='yellow', **print_kwargs)
|
|
173
134
|
|
|
135
|
+
def run_check_system_resources(
|
|
136
|
+
self,
|
|
137
|
+
interval, get_cpu, get_memory, get_disk_io_bytes, get_disk_files_count, get_disk_busy_time,
|
|
138
|
+
get_disk_used_percent, calculate_maximum_changed_disk_io, maximum_disk_io, queue_list, manager_dict):
|
|
139
|
+
"""
|
|
140
|
+
Continuously update the system resources in the shared results dictionary.
|
|
141
|
+
This function runs in a separate process.
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
while self.running:
|
|
145
|
+
# Get the results of the system resources check function and store them in
|
|
146
|
+
# temporary results' dictionary.
|
|
147
|
+
results = system_resources.check_system_resources(
|
|
148
|
+
interval=interval, get_cpu=get_cpu, get_memory=get_memory,
|
|
149
|
+
get_disk_io_bytes=get_disk_io_bytes, get_disk_files_count=get_disk_files_count,
|
|
150
|
+
get_disk_busy_time=get_disk_busy_time, get_disk_used_percent=get_disk_used_percent)
|
|
151
|
+
|
|
152
|
+
if calculate_maximum_changed_disk_io:
|
|
153
|
+
if results['disk_io_read'] > maximum_disk_io['read_bytes_per_sec']:
|
|
154
|
+
maximum_disk_io['read_bytes_per_sec'] = results['disk_io_read']
|
|
155
|
+
if results['disk_io_write'] > maximum_disk_io['write_bytes_per_sec']:
|
|
156
|
+
maximum_disk_io['write_bytes_per_sec'] = results['disk_io_write']
|
|
157
|
+
if results['disk_files_count_read'] > maximum_disk_io['read_files_count_per_sec']:
|
|
158
|
+
maximum_disk_io['read_files_count_per_sec'] = results['disk_files_count_read']
|
|
159
|
+
if results['disk_files_count_write'] > maximum_disk_io['write_files_count_per_sec']:
|
|
160
|
+
maximum_disk_io['write_files_count_per_sec'] = results['disk_files_count_write']
|
|
161
|
+
results['maximum_disk_io'] = maximum_disk_io
|
|
162
|
+
|
|
163
|
+
if queue_list is not None:
|
|
164
|
+
for queue in queue_list:
|
|
165
|
+
queue.put(results)
|
|
166
|
+
|
|
167
|
+
# Update the shared results dictionary with the temporary results' dictionary.
|
|
168
|
+
# This is done in separate steps to avoid overwriting the special 'multiprocessing.Manager.dict' object.
|
|
169
|
+
# So we update the shared results dictionary with the temporary results' dictionary.
|
|
170
|
+
if manager_dict is not None:
|
|
171
|
+
manager_dict.update(results)
|
|
172
|
+
|
|
173
|
+
self.results = results
|
|
174
|
+
|
|
174
175
|
def get_results(self) -> dict:
|
|
175
176
|
"""
|
|
176
177
|
Retrieve the latest results.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import ctypes
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class NotWindowsConsoleError(Exception):
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Define QuickEdit mode bit (0x0040)
|
|
9
|
+
ENABLE_QUICK_EDIT = 0x0040
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def disable_quick_edit():
|
|
13
|
+
"""
|
|
14
|
+
Disables QuickEdit mode in the Windows Command Prompt.
|
|
15
|
+
This prevents the console from being paused when the user selects text.
|
|
16
|
+
NO ADMIN REQUIRED
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
kernel32 = ctypes.windll.kernel32
|
|
20
|
+
h_stdin = kernel32.GetStdHandle(-10) # -10 is STD_INPUT_HANDLE
|
|
21
|
+
|
|
22
|
+
# Get current console mode
|
|
23
|
+
mode = ctypes.c_uint()
|
|
24
|
+
if kernel32.GetConsoleMode(h_stdin, ctypes.byref(mode)) == 0:
|
|
25
|
+
try:
|
|
26
|
+
raise ctypes.WinError()
|
|
27
|
+
except OSError as e:
|
|
28
|
+
# This means that the code is not running in console window.
|
|
29
|
+
if e.errno == 9 and e.winerror == 6:
|
|
30
|
+
raise NotWindowsConsoleError("This code is not running in a Windows console.")
|
|
31
|
+
else:
|
|
32
|
+
raise e
|
|
33
|
+
|
|
34
|
+
# Disable QuickEdit Mode by clearing the corresponding bit
|
|
35
|
+
mode.value &= ~ENABLE_QUICK_EDIT
|
|
36
|
+
|
|
37
|
+
# Set the new console mode
|
|
38
|
+
if kernel32.SetConsoleMode(h_stdin, mode) == 0:
|
|
39
|
+
raise ctypes.WinError()
|
|
@@ -13,6 +13,7 @@ def get_logs_paths(
|
|
|
13
13
|
date_format: str = None,
|
|
14
14
|
latest_only: bool = False,
|
|
15
15
|
previous_day_only: bool = False,
|
|
16
|
+
yesterday_only: bool = False,
|
|
16
17
|
specific_date: str = None
|
|
17
18
|
) -> list[filesystem.AtomicPath]:
|
|
18
19
|
"""
|
|
@@ -37,24 +38,37 @@ def get_logs_paths(
|
|
|
37
38
|
date_format = '%Y-%m-%d'
|
|
38
39
|
:param latest_only: Boolean, if True, only the latest log file path will be returned.
|
|
39
40
|
:param previous_day_only: Boolean, if True, only the log file path from the previous day will be returned.
|
|
41
|
+
:param yesterday_only: Boolean, if True, only the log file path from yesterday will be returned.
|
|
42
|
+
There's a difference between 'previous_day_only' and 'yesterday_only'.
|
|
43
|
+
'previous_day_only' will get the log file from the previous day in the list of files that were found.
|
|
44
|
+
Since that doesn't guarantee that the log file from the previous day is yesterday, we have 'yesterday_only'.
|
|
40
45
|
:param specific_date: Specific date to get the log file path.
|
|
41
46
|
If specified, the function will get the log file by the specific date.
|
|
42
47
|
Meaning that 'date_format' must be specified.
|
|
43
|
-
|
|
44
48
|
"""
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
booleans.is_only_1_true_in_list(
|
|
51
|
+
booleans_list_of_tuples=[
|
|
52
|
+
(latest_only, 'latest_only'),
|
|
53
|
+
(previous_day_only, 'previous_day_only'),
|
|
54
|
+
(yesterday_only, 'yesterday_only'),
|
|
55
|
+
(specific_date, 'specific_date'),
|
|
56
|
+
],
|
|
57
|
+
raise_if_all_false=False
|
|
58
|
+
)
|
|
51
59
|
|
|
52
60
|
if not date_format and specific_date:
|
|
53
61
|
raise ValueError('If "specific_date" is specified, "date_format" must be specified.')
|
|
54
62
|
|
|
55
63
|
# Get the file_name_pattern from the file name. Build the file_name_pattern.
|
|
64
|
+
# For some reason if the file name will be '.zip', then the file stem will be '.zip' and the extension will be ''.
|
|
56
65
|
log_file_name: str = Path(log_file_path).stem
|
|
57
66
|
log_file_extension: str = Path(log_file_path).suffix
|
|
67
|
+
|
|
68
|
+
if not log_file_extension and '.' in log_file_name:
|
|
69
|
+
log_file_name, log_file_extension = log_file_name.rsplit('.')
|
|
70
|
+
log_file_extension = f'.{log_file_extension}'
|
|
71
|
+
|
|
58
72
|
file_name_pattern: str = f'{log_file_name}*{log_file_extension}'
|
|
59
73
|
|
|
60
74
|
# Get the directory path from the file path.
|
|
@@ -111,15 +125,18 @@ def get_logs_paths(
|
|
|
111
125
|
if logs_files:
|
|
112
126
|
if latest_only:
|
|
113
127
|
logs_files = [logs_files[-1]]
|
|
114
|
-
|
|
115
|
-
if previous_day_only:
|
|
116
|
-
# Check if there is a previous day log file.
|
|
128
|
+
elif previous_day_only:
|
|
117
129
|
if len(logs_files) == 1:
|
|
118
130
|
logs_files = []
|
|
119
131
|
else:
|
|
120
132
|
logs_files = [logs_files[-2]]
|
|
121
|
-
|
|
122
|
-
|
|
133
|
+
elif yesterday_only:
|
|
134
|
+
# Get yesterday's date.
|
|
135
|
+
yesterday_date_string = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime(date_format)
|
|
136
|
+
# Check if there is a yesterday log file.
|
|
137
|
+
logs_files = [single_file
|
|
138
|
+
for single_file in logs_files if single_file.datetime_string == yesterday_date_string]
|
|
139
|
+
elif specific_date:
|
|
123
140
|
# Check if there is a specific date log file.
|
|
124
141
|
logs_files = [single_file for single_file in logs_files if single_file.datetime_string == specific_date]
|
|
125
142
|
|
|
@@ -394,9 +394,14 @@ def find(
|
|
|
394
394
|
query: dict = None,
|
|
395
395
|
page: int = None,
|
|
396
396
|
items: int = None,
|
|
397
|
-
sorting:
|
|
398
|
-
|
|
399
|
-
|
|
397
|
+
sorting: Union[
|
|
398
|
+
dict[str, Literal[
|
|
399
|
+
'asc', 'desc',
|
|
400
|
+
'ASC', 'DESC',
|
|
401
|
+
1, -1]],
|
|
402
|
+
list[tuple[
|
|
403
|
+
str, Literal[1, -1]]],
|
|
404
|
+
None] = None,
|
|
400
405
|
convert_object_id_to_str: bool = False,
|
|
401
406
|
key_convert_to_dict: list[str] = None,
|
|
402
407
|
mongo_client: pymongo.MongoClient = None,
|
|
@@ -445,29 +450,40 @@ def find(
|
|
|
445
450
|
$nin: Will search for a value not in a list of values.
|
|
446
451
|
Example for searching for a value that is not in a list of values:
|
|
447
452
|
query = {'field_name': {'$nin': ['value1', 'value2', 'value3']}}
|
|
448
|
-
|
|
453
|
+
$exists: Will search for entries where the field exists or not.
|
|
454
|
+
Example for searching for entries where the field exists:
|
|
455
|
+
query = {'field_name': {'$exists': True}}
|
|
456
|
+
Example for searching for entries where the field does not exist:
|
|
457
|
+
query = {'field_name': {'$exists': False}}
|
|
458
|
+
$ne: Will search for entries where the field is not equal to the value.
|
|
459
|
+
Example for searching for entries where the field is not equal to the value:
|
|
460
|
+
query = {'field_name': {'$ne': 'value'}}
|
|
449
461
|
|
|
450
462
|
:param page: int, the page number (Optional).
|
|
451
463
|
:param items: int, the number of results per page (Optional).
|
|
452
|
-
:param sorting: dict
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
464
|
+
:param sorting: dict or list of tuples:
|
|
465
|
+
dict, the name of the field and the order to sort the containers by.
|
|
466
|
+
You can use several fields to sort the containers by several fields.
|
|
467
|
+
In this case the containers will be sorted by the first field, then by the second field, etc.
|
|
468
|
+
You can also use only singular field to sort the containers by only one field.
|
|
469
|
+
Usage:
|
|
470
|
+
{
|
|
471
|
+
field_name: order
|
|
472
|
+
}
|
|
473
|
+
Example:
|
|
474
|
+
{
|
|
475
|
+
'vendor': 'asc',
|
|
476
|
+
'model': 'desc'
|
|
477
|
+
}
|
|
465
478
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
479
|
+
Or example using integers:
|
|
480
|
+
{
|
|
481
|
+
'vendor': 1,
|
|
482
|
+
'model': -1
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
list of tuples, each tuple will contain [0] string of the field name and [1] the integer value of the order
|
|
486
|
+
to sort by, this is pymongo default, 1 for ascending and -1 for descending.
|
|
471
487
|
:param convert_object_id_to_str: bool, if True, the '_id' field will be converted to a string.
|
|
472
488
|
The '_id' field is an ObjectId type, which is a complex object, it can be converted to a string for simpler
|
|
473
489
|
processing.
|
|
@@ -486,9 +502,9 @@ def find(
|
|
|
486
502
|
elif items and not page:
|
|
487
503
|
page = 1
|
|
488
504
|
|
|
489
|
-
if sorting:
|
|
505
|
+
if sorting and isinstance(sorting, dict):
|
|
490
506
|
for key_to_sort_by, order in sorting.items():
|
|
491
|
-
if order not in ['asc', 'desc', 1, -1]:
|
|
507
|
+
if order.lower() not in ['asc', 'desc', 1, -1]:
|
|
492
508
|
raise ValueError("The order must be 'asc', 'desc', 1 or -1.")
|
|
493
509
|
|
|
494
510
|
if not mongo_client:
|
|
@@ -510,13 +526,16 @@ def find(
|
|
|
510
526
|
|
|
511
527
|
if sorting:
|
|
512
528
|
sorting_list_of_tuples: list[tuple[str, int]] = []
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
order
|
|
516
|
-
|
|
517
|
-
order
|
|
518
|
-
|
|
519
|
-
|
|
529
|
+
if isinstance(sorting, dict):
|
|
530
|
+
for key_to_sort_by, order in sorting.items():
|
|
531
|
+
if order.lower() == 'asc':
|
|
532
|
+
order = pymongo.ASCENDING
|
|
533
|
+
elif order.lower() == 'desc':
|
|
534
|
+
order = pymongo.DESCENDING
|
|
535
|
+
|
|
536
|
+
sorting_list_of_tuples.append((key_to_sort_by, order))
|
|
537
|
+
elif sorting and isinstance(sorting, list):
|
|
538
|
+
sorting_list_of_tuples = sorting
|
|
520
539
|
|
|
521
540
|
collection_items = collection_items.sort(sorting_list_of_tuples)
|
|
522
541
|
|
|
@@ -84,10 +84,13 @@ def install_nodejs_ubuntu(
|
|
|
84
84
|
:return:
|
|
85
85
|
"""
|
|
86
86
|
|
|
87
|
-
booleans.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
booleans.is_only_1_true_in_list(
|
|
88
|
+
booleans_list_of_tuples=[
|
|
89
|
+
(install_latest_version, 'install_latest_version'),
|
|
90
|
+
(install_lts, 'install_lts'),
|
|
91
|
+
(install_by_version_number, 'install_by_version_number')
|
|
92
|
+
],
|
|
93
|
+
raise_if_all_false=True
|
|
91
94
|
)
|
|
92
95
|
|
|
93
96
|
# Check if Node.js is already installed.
|
|
@@ -261,11 +261,14 @@ class DnsServer:
|
|
|
261
261
|
|
|
262
262
|
def test_config(self):
|
|
263
263
|
try:
|
|
264
|
-
booleans.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
264
|
+
booleans.is_only_1_true_in_list(
|
|
265
|
+
booleans_list_of_tuples=[
|
|
266
|
+
(self.resolve_to_tcp_server_only_tcp_resolve_domains,
|
|
267
|
+
'resolve_to_tcp_server_only_tcp_resolve_domains'),
|
|
268
|
+
(self.resolve_to_tcp_server_all_domains, 'resolve_to_tcp_server_all_domains'),
|
|
269
|
+
(self.resolve_regular, 'resolve_regular')
|
|
270
|
+
],
|
|
271
|
+
raise_if_all_false=True
|
|
269
272
|
)
|
|
270
273
|
except ValueError as e:
|
|
271
274
|
raise DnsConfigurationValuesError(e)
|
|
@@ -263,11 +263,15 @@ class SocketWrapper:
|
|
|
263
263
|
raise SocketWrapperConfigurationValuesError(message)
|
|
264
264
|
|
|
265
265
|
try:
|
|
266
|
-
booleans.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
266
|
+
booleans.is_only_1_true_in_list(
|
|
267
|
+
booleans_list_of_tuples=[
|
|
268
|
+
(self.default_server_certificate_usage, 'default_server_certificate_usage'),
|
|
269
|
+
(self.sni_create_server_certificate_for_each_domain,
|
|
270
|
+
'sni_create_server_certificate_for_each_domain'),
|
|
271
|
+
(self.custom_server_certificate_usage, 'custom_server_certificate_usage')
|
|
272
|
+
],
|
|
273
|
+
raise_if_all_false=True
|
|
274
|
+
)
|
|
271
275
|
except ValueError as e:
|
|
272
276
|
raise SocketWrapperConfigurationValuesError(str(e))
|
|
273
277
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=Q8UxOCNLGPrZ4zmxZygiIYY6-S1LBodk2crxUcbd0aQ,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
|
|
5
5
|
atomicshop/appointment_management.py,sha256=BsYH_PClTGLVazcuNjt30--hpXKYjSmHp1R1iQbM4Hc,7330
|
|
6
6
|
atomicshop/certificates.py,sha256=MEGj7t3Nt2CHE7yzXrvFTLCOKZG9tJ6Ok5JC2BsFRis,7603
|
|
7
7
|
atomicshop/command_line_processing.py,sha256=u5yT9Ger_cu7ni5ID0VFlRbVD46ARHeNC9tRM-_YXrQ,1038
|
|
8
|
-
atomicshop/config_init.py,sha256=
|
|
8
|
+
atomicshop/config_init.py,sha256=50kD2lXP8sgwPekcmAbfADcY46YvXkF-6XIdA7W_638,2501
|
|
9
9
|
atomicshop/console_output.py,sha256=AOSJjrRryE97PAGtgDL03IBtWSi02aNol8noDnW3k6M,4667
|
|
10
10
|
atomicshop/console_user_response.py,sha256=31HIy9QGXa7f-GVR8MzJauQ79E_ZqAeagF3Ks4GGdDU,3234
|
|
11
11
|
atomicshop/datetimes.py,sha256=IQZ66lmta-ZqxYbyHzm_9eugbJFSilXK1e0kfMgoXGg,18371
|
|
@@ -25,7 +25,7 @@ atomicshop/ip_addresses.py,sha256=Hvi4TumEFoTEpKWaq5WNF-YzcRzt24IxmNgv-Mgax1s,11
|
|
|
25
25
|
atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,452
|
|
26
26
|
atomicshop/on_exit.py,sha256=Rpg2SaF0aginuO7JYwA49YJYnS8F6K2jUqhjH65WzuU,6889
|
|
27
27
|
atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erXXdjwtS4,4574
|
|
28
|
-
atomicshop/print_api.py,sha256=
|
|
28
|
+
atomicshop/print_api.py,sha256=REkd1W3--g1Av4_nH3M2CvQCIEDecfsT7spMXgIRUJE,11158
|
|
29
29
|
atomicshop/process.py,sha256=PeLvyixXaCfftdUF3oMbohI1L4MdLtvQVDx2V1Tz_Rk,16662
|
|
30
30
|
atomicshop/python_file_patcher.py,sha256=-uhbUX-um5k-If_XXuOfCr8wMzZ3QE6h9N8xGWw6W_o,5486
|
|
31
31
|
atomicshop/python_functions.py,sha256=zJg4ogUwECxrDD7xdDN5JikIUctITM5lsyabr_ZNsRw,4435
|
|
@@ -37,7 +37,7 @@ atomicshop/sound.py,sha256=tHiQQbFBk7EYN3pAfGNcxfF9oNsoYnZgu9z9iq8hxQE,24352
|
|
|
37
37
|
atomicshop/speech_recognize.py,sha256=55-dIjgkpF93mvJnJuxSFuft5H5eRvGNlUj9BeIOZxk,5903
|
|
38
38
|
atomicshop/ssh_remote.py,sha256=Mxixqs2-xGy1bhbcP0LKqjxKTNPz1Gmzz8PzO8aLB4c,17345
|
|
39
39
|
atomicshop/sys_functions.py,sha256=MTBxRve5bh58SPvhX3gMiGqHlSBuI_rdNN1NnnBBWqI,906
|
|
40
|
-
atomicshop/system_resource_monitor.py,sha256=
|
|
40
|
+
atomicshop/system_resource_monitor.py,sha256=5sM3Ad4IZI8ahpKM3Wu4B0a3TD-N2Y795_kSkIv94lk,13632
|
|
41
41
|
atomicshop/system_resources.py,sha256=iKUvVSaXR47inmr3cTYsgNfclT38dRia2oupnlhIpK4,9290
|
|
42
42
|
atomicshop/tempfiles.py,sha256=uq1ve2WlWehZ3NOTXJnpBBMt6HyCdBufqedF0HyzA6k,2517
|
|
43
43
|
atomicshop/timer.py,sha256=7Zw1KRV0acHCRATMnanyX2MLBb63Hc-6us3rCZ9dNlY,2345
|
|
@@ -82,7 +82,7 @@ atomicshop/archiver/zips.py,sha256=0Z_1MWs7YRiCBVpyaG8llnzRguHSO4R51KDMN3FJZt8,1
|
|
|
82
82
|
atomicshop/basics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
83
|
atomicshop/basics/ansi_escape_codes.py,sha256=WtIkm-BjSZS5J5irDUdAMBNvdX-qXFZcTX98jcBMpJE,3140
|
|
84
84
|
atomicshop/basics/argparse_template.py,sha256=horwgSf3MX1ZgRnYxtmmQuz9OU_vKrKggF65gmjlmfg,5836
|
|
85
|
-
atomicshop/basics/booleans.py,sha256=
|
|
85
|
+
atomicshop/basics/booleans.py,sha256=V36NaMf8AffhCom_ovQeOZlYcdtGyIcQwWKki6h7O0M,1745
|
|
86
86
|
atomicshop/basics/bytes_arrays.py,sha256=WvSRDhIGt1ywF95t-yNgpxLm1nlZUbM1Dz6QckcyE8Y,5915
|
|
87
87
|
atomicshop/basics/classes.py,sha256=T0Bm13hKvkXG3med68ptL7XuoWiCi3TE-K5TMINDlrY,10655
|
|
88
88
|
atomicshop/basics/dicts.py,sha256=DeYHIh940pMMBrFhpXt4dsigFVYzTrlqWymNo4Pq_Js,14049
|
|
@@ -114,9 +114,9 @@ atomicshop/etws/traces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
114
114
|
atomicshop/etws/traces/trace_dns.py,sha256=WvOZm7KNdP4r6ofkZhUGi9WjtYlkV3mUp_yxita3Qg4,6399
|
|
115
115
|
atomicshop/etws/traces/trace_sysmon_process_creation.py,sha256=OM-bkK38uYMwWLZKNOTDa0Xdk3sO6sqsxoMUIiPvm5g,4656
|
|
116
116
|
atomicshop/file_io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
117
|
-
atomicshop/file_io/csvs.py,sha256=
|
|
117
|
+
atomicshop/file_io/csvs.py,sha256=jBdm3_z5cMyvxLxJnGcybUAptHAbyL0r0tlLqY0sdTQ,9327
|
|
118
118
|
atomicshop/file_io/docxs.py,sha256=ffJhnmM_WyD8mCoq2dGdpfahdIrGTPy96QVlH5EWjeI,5754
|
|
119
|
-
atomicshop/file_io/file_io.py,sha256=
|
|
119
|
+
atomicshop/file_io/file_io.py,sha256=5Kl0P6vF4GQVdwew1lzHLb-db9qiMvDjTgccbi5P-zk,7167
|
|
120
120
|
atomicshop/file_io/jsons.py,sha256=q9ZU8slBKnHLrtn3TnbK1qxrRpj5ZvCm6AlsFzoANjo,5303
|
|
121
121
|
atomicshop/file_io/tomls.py,sha256=ol8EvQPf9sryTmZUf1v55BYSUQ6ml7HVVBHpNKbsIlA,9768
|
|
122
122
|
atomicshop/file_io/xlsxs.py,sha256=v_dyg9GD4LqgWi6wA1QuWRZ8zG4ZwB6Dz52ytdcmmmI,2184
|
|
@@ -125,19 +125,19 @@ atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
125
125
|
atomicshop/mitm/config_static.py,sha256=ROAtbibSWSsF3BraUbhu-QO3MPIFqYY5KUKgsQbiSkk,7813
|
|
126
126
|
atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
|
|
127
127
|
atomicshop/mitm/connection_thread_worker.py,sha256=fybUBcZckgF7TC_P1z2yIYGH6ATX7jQEfsQSBuddt2s,16531
|
|
128
|
-
atomicshop/mitm/import_config.py,sha256=
|
|
128
|
+
atomicshop/mitm/import_config.py,sha256=ZKQXxbtjVqzN9fpRrMwPNQREecH06RG8F_nXZAKTUJM,8182
|
|
129
129
|
atomicshop/mitm/initialize_engines.py,sha256=VyJE8QnzlgD3QbX5inz5o6rC3zQ3is9CeTL7-B10g1w,8292
|
|
130
130
|
atomicshop/mitm/message.py,sha256=URR5JKSuAT8XmGIkyprEjlPW2GW4ef_gfUz_GgcFseE,2184
|
|
131
|
-
atomicshop/mitm/mitm_main.py,sha256=
|
|
132
|
-
atomicshop/mitm/recs_files.py,sha256=
|
|
133
|
-
atomicshop/mitm/shared_functions.py,sha256=
|
|
134
|
-
atomicshop/mitm/statistic_analyzer.py,sha256=
|
|
131
|
+
atomicshop/mitm/mitm_main.py,sha256=ICQS8-4-owDhPUIQohymLShzgCZwgq7jUocZHX1J3Zo,22592
|
|
132
|
+
atomicshop/mitm/recs_files.py,sha256=mMyO1kPB-VkS_pbWCDhZHKdbWzlPbYSout61QuzHOao,3077
|
|
133
|
+
atomicshop/mitm/shared_functions.py,sha256=l6oEyv4ug5D_03V3QLADYoocbcL2Ml_dYVW2WKM21l4,1818
|
|
134
|
+
atomicshop/mitm/statistic_analyzer.py,sha256=5_sAYGX2Xunzo_pS2W5WijNCwr_BlGJbbOO462y_wN4,27533
|
|
135
135
|
atomicshop/mitm/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
136
136
|
atomicshop/mitm/engines/create_module_template.py,sha256=tRjVSm1sD6FzML71Qbuwvita0qsusdFGm8NZLsZ-XMs,4853
|
|
137
137
|
atomicshop/mitm/engines/create_module_template_example.py,sha256=X5xhvbV6-g9jU_bQVhf_crZmaH50LRWz3bS-faQ18ds,489
|
|
138
138
|
atomicshop/mitm/engines/__parent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
139
139
|
atomicshop/mitm/engines/__parent/parser___parent.py,sha256=RK2wviepP0oeq7zuLpgkvqvTJtc0r0a7hDGWdV0dGc4,657
|
|
140
|
-
atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=
|
|
140
|
+
atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=xJ3YVa8XYwcKqCwUIEXf6_UGnCbpRsvoicUNe0WxMfs,3782
|
|
141
141
|
atomicshop/mitm/engines/__parent/responder___parent.py,sha256=7WQeR3UmMnN74bDwn-0nz2OfhXJ3-ClXpNGUFZ7wJUE,12004
|
|
142
142
|
atomicshop/mitm/engines/__reference_general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
143
143
|
atomicshop/mitm/engines/__reference_general/parser___reference_general.py,sha256=57MEPZMAjTO6xBDZ-yt6lgGJyqRrP0Do5Gk_cgCiPns,2998
|
|
@@ -145,7 +145,7 @@ atomicshop/mitm/engines/__reference_general/recorder___reference_general.py,sha2
|
|
|
145
145
|
atomicshop/mitm/engines/__reference_general/responder___reference_general.py,sha256=IUyQYMPeEhIARfALWiKPFeXagSQD6lRzAxUdi4ZIT88,7010
|
|
146
146
|
atomicshop/mitm/statistic_analyzer_helper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
147
147
|
atomicshop/mitm/statistic_analyzer_helper/analyzer_helper.py,sha256=pk6L1t1ea1kvlBoR9QEJptOmaX-mumhwLsP2GCKukbk,5920
|
|
148
|
-
atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py,sha256=
|
|
148
|
+
atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py,sha256=UnnY_FSTiXEfZ8SkDKU2s2qpgPYu1oOT99ghmY-zzas,19992
|
|
149
149
|
atomicshop/monitor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
150
150
|
atomicshop/monitor/change_monitor.py,sha256=K5NlVp99XIDDPnQQMdru4BDmua_DtcDIhVAzkTOvD5s,7673
|
|
151
151
|
atomicshop/monitor/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -194,6 +194,7 @@ atomicshop/wrappers/certauthw/certauth.py,sha256=hKedW0DOWlEigSNm8wu4SqHkCQsGJ1t
|
|
|
194
194
|
atomicshop/wrappers/certauthw/certauthw.py,sha256=4WvhjANI7Kzqrr_nKmtA8Kf7B6rute_5wfP65gwQrjw,8082
|
|
195
195
|
atomicshop/wrappers/ctyping/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
196
196
|
atomicshop/wrappers/ctyping/process_winapi.py,sha256=QcXL-ETtlSSkoT8F7pYle97ubGWsjYp8cx8HxkVMgAc,2762
|
|
197
|
+
atomicshop/wrappers/ctyping/win_console.py,sha256=uTtjkz9rY559AaV0dhyZYUSSEe9cn6Du2DgurdMtX-M,1158
|
|
197
198
|
atomicshop/wrappers/ctyping/etw_winapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
198
199
|
atomicshop/wrappers/ctyping/etw_winapi/const.py,sha256=stZHZ7tSiSAs04ikr7uH-Td_yBXxsF-bp2Q0F3K2fsM,9543
|
|
199
200
|
atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py,sha256=Iwd0wIuoxpjMaaOfZZtT1bPtDTsMO8jjItBE5bvkocM,11546
|
|
@@ -249,14 +250,14 @@ atomicshop/wrappers/loggingw/filters.py,sha256=48UVhJHemCS0agXmQP8dHvAHM8r9DFphJ
|
|
|
249
250
|
atomicshop/wrappers/loggingw/formatters.py,sha256=ZY12IokVY1G_Wzn2Zlv9qjK-e8CtIK6yUgUfPHvH2BU,5802
|
|
250
251
|
atomicshop/wrappers/loggingw/handlers.py,sha256=vxaSSnlJGs9NKJvYROKtNjaFTqePdHy0sz-GwN5aNPw,19035
|
|
251
252
|
atomicshop/wrappers/loggingw/loggers.py,sha256=mmM__XR3W4QC82wbsDRG_M4_0JYGGEP0Qn0WCOSp-go,2910
|
|
252
|
-
atomicshop/wrappers/loggingw/loggingw.py,sha256=
|
|
253
|
-
atomicshop/wrappers/loggingw/reading.py,sha256=
|
|
253
|
+
atomicshop/wrappers/loggingw/loggingw.py,sha256=64r5XZSAwJ5GfkN7JqAvuLFlJRdf79n0jr_FriaaaCw,21330
|
|
254
|
+
atomicshop/wrappers/loggingw/reading.py,sha256=sCNlgqLNH5XdKqOOjjEox7CvViMHzs6h7-hwCnx4NKk,17566
|
|
254
255
|
atomicshop/wrappers/mongodbw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
255
256
|
atomicshop/wrappers/mongodbw/install_mongodb.py,sha256=3ZPqrXxj3lC-PnAKGXclylLuOqsbyXYeUpb5iGjdeUU,6626
|
|
256
257
|
atomicshop/wrappers/mongodbw/mongo_infra.py,sha256=IjEF0jPzQz866MpTm7rnksnyyWQeUT_B2h2DA9ryAio,2034
|
|
257
|
-
atomicshop/wrappers/mongodbw/mongodbw.py,sha256=
|
|
258
|
+
atomicshop/wrappers/mongodbw/mongodbw.py,sha256=oM2pS-M0EI7HhewWY0ri_Ri9U5GOBo0CehPmo4Yas3o,32736
|
|
258
259
|
atomicshop/wrappers/nodejsw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
259
|
-
atomicshop/wrappers/nodejsw/install_nodejs.py,sha256=
|
|
260
|
+
atomicshop/wrappers/nodejsw/install_nodejs.py,sha256=TKGa3jSlSqZTL2NA0nMkWDFtlkz7rxGGn44ywCg7MN8,5228
|
|
260
261
|
atomicshop/wrappers/playwrightw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
261
262
|
atomicshop/wrappers/playwrightw/_tryouts.py,sha256=l1BLkFsiIMNlgv7nfZd1XGEvXQkIQkIcg48__9OaC00,4920
|
|
262
263
|
atomicshop/wrappers/playwrightw/base.py,sha256=WeRpx8otdXuKSr-BjY-uCJTze21kbPpfitoOjKQz5-g,9818
|
|
@@ -296,7 +297,7 @@ atomicshop/wrappers/socketw/accepter.py,sha256=hZZKVYlF3LOHQJsSIEKXZUf6QXXWm-Atq
|
|
|
296
297
|
atomicshop/wrappers/socketw/base.py,sha256=evoOIxg5Xff3THJnrVX00D5HobaOpDp6_e_gso7TJmA,2191
|
|
297
298
|
atomicshop/wrappers/socketw/certificator.py,sha256=3CpQKtcW68FSbH6LVSEZTqWBS6Yg_-3K0x4nFkId4UY,12236
|
|
298
299
|
atomicshop/wrappers/socketw/creator.py,sha256=3_OraDkw2DAWZfoSdY3svCGMOIxpjLEEY7NxWd7M5P4,9873
|
|
299
|
-
atomicshop/wrappers/socketw/dns_server.py,sha256=
|
|
300
|
+
atomicshop/wrappers/socketw/dns_server.py,sha256=VHV6s7vd0zqqW3dhE6li-260YRzmEB5ZUXqYJ9p0vVA,49069
|
|
300
301
|
atomicshop/wrappers/socketw/exception_wrapper.py,sha256=B-X5SHLSUIWToihH2MKnOB1F4A81_X0DpLLfnYKYbEc,7067
|
|
301
302
|
atomicshop/wrappers/socketw/get_process.py,sha256=zKEqh98cB9UDLFhtxVpperfXsCjyIMNANHilDD06p0U,6094
|
|
302
303
|
atomicshop/wrappers/socketw/receiver.py,sha256=XVvWOoeCo3vA0O5p19ryi-hcDIyx382WNG7WzMNVeYk,9322
|
|
@@ -304,13 +305,13 @@ atomicshop/wrappers/socketw/sender.py,sha256=5HPrgTS2pA1g-jbG1TUtR7drHT1Z_8UevlR
|
|
|
304
305
|
atomicshop/wrappers/socketw/sni.py,sha256=J1kPnQ77XwKN1pO5aOI1c_VfhuivCm95OOaQxMpPuZ0,17627
|
|
305
306
|
atomicshop/wrappers/socketw/socket_client.py,sha256=XC-YaqA1wu0rvWQ9Q99DWLxcycKPkPc72pSnflzalfo,20320
|
|
306
307
|
atomicshop/wrappers/socketw/socket_server_tester.py,sha256=Qobmh4XV8ZxLUaw-eW4ESKAbeSLecCKn2OWFzMhadk0,6420
|
|
307
|
-
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=
|
|
308
|
+
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=WtylpezgIIBuz-A6PfM0hO1sm9Exd4j3qhDXcFc74-E,35567
|
|
308
309
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
|
|
309
310
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=w1AH-zf4mBuT4euf28UKij9ihM-b1BRU9Qfby0QDdqI,2957
|
|
310
311
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
311
312
|
atomicshop/wrappers/winregw/winreg_network.py,sha256=bQ8Jql8bVGBJ0dt3VQ56lga_1LBOMLI3Km_otvvbU6c,7138
|
|
312
|
-
atomicshop-2.16.
|
|
313
|
-
atomicshop-2.16.
|
|
314
|
-
atomicshop-2.16.
|
|
315
|
-
atomicshop-2.16.
|
|
316
|
-
atomicshop-2.16.
|
|
313
|
+
atomicshop-2.16.33.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
314
|
+
atomicshop-2.16.33.dist-info/METADATA,sha256=snw-nClHcOxtJnor7m7ldSl-0Lu3-R5jfEZ9l53m3WU,10473
|
|
315
|
+
atomicshop-2.16.33.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
316
|
+
atomicshop-2.16.33.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
317
|
+
atomicshop-2.16.33.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|