atomicshop 2.15.11__py3-none-any.whl → 3.10.5__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.
- atomicshop/__init__.py +1 -1
- atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
- atomicshop/a_mains/dns_gateway_setting.py +11 -0
- atomicshop/a_mains/get_local_tcp_ports.py +85 -0
- atomicshop/a_mains/github_wrapper.py +11 -0
- atomicshop/a_mains/install_ca_certificate.py +172 -0
- atomicshop/a_mains/process_from_port.py +119 -0
- atomicshop/a_mains/set_default_dns_gateway.py +90 -0
- atomicshop/a_mains/update_config_toml.py +38 -0
- atomicshop/basics/ansi_escape_codes.py +3 -1
- atomicshop/basics/argparse_template.py +2 -0
- atomicshop/basics/booleans.py +27 -30
- atomicshop/basics/bytes_arrays.py +43 -0
- atomicshop/basics/classes.py +149 -1
- atomicshop/basics/enums.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/basics/list_of_classes.py +29 -0
- atomicshop/basics/multiprocesses.py +374 -50
- atomicshop/basics/strings.py +72 -3
- atomicshop/basics/threads.py +14 -0
- atomicshop/basics/tracebacks.py +13 -3
- atomicshop/certificates.py +153 -52
- atomicshop/config_init.py +11 -6
- atomicshop/console_user_response.py +7 -14
- atomicshop/consoles.py +9 -0
- atomicshop/datetimes.py +1 -1
- atomicshop/diff_check.py +3 -3
- atomicshop/dns.py +128 -3
- atomicshop/etws/_pywintrace_fix.py +17 -0
- atomicshop/etws/trace.py +40 -42
- atomicshop/etws/traces/trace_dns.py +56 -44
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/file_io/csvs.py +27 -5
- atomicshop/file_io/docxs.py +34 -17
- atomicshop/file_io/file_io.py +31 -17
- atomicshop/file_io/jsons.py +49 -0
- atomicshop/file_io/tomls.py +139 -0
- atomicshop/filesystem.py +616 -291
- atomicshop/get_process_list.py +3 -3
- atomicshop/http_parse.py +149 -93
- atomicshop/ip_addresses.py +6 -1
- atomicshop/mitm/centered_settings.py +132 -0
- atomicshop/mitm/config_static.py +207 -0
- atomicshop/mitm/config_toml_editor.py +55 -0
- atomicshop/mitm/connection_thread_worker.py +875 -357
- atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
- atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
- atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
- atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
- atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
- atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
- atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
- atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
- atomicshop/mitm/engines/create_module_template.py +58 -14
- atomicshop/mitm/import_config.py +359 -139
- atomicshop/mitm/initialize_engines.py +160 -80
- atomicshop/mitm/message.py +64 -23
- atomicshop/mitm/mitm_main.py +892 -0
- atomicshop/mitm/recs_files.py +183 -0
- atomicshop/mitm/shared_functions.py +4 -10
- atomicshop/mitm/ssh_tester.py +82 -0
- atomicshop/mitm/statistic_analyzer.py +136 -40
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +265 -83
- atomicshop/monitor/checks/dns.py +1 -1
- atomicshop/networks.py +671 -0
- atomicshop/on_exit.py +39 -9
- atomicshop/package_mains_processor.py +84 -0
- atomicshop/permissions/permissions.py +22 -0
- atomicshop/permissions/ubuntu_permissions.py +239 -0
- atomicshop/permissions/win_permissions.py +33 -0
- atomicshop/print_api.py +24 -42
- atomicshop/process.py +24 -6
- atomicshop/process_poller/process_pool.py +0 -1
- atomicshop/process_poller/simple_process_pool.py +204 -5
- atomicshop/python_file_patcher.py +1 -1
- atomicshop/python_functions.py +27 -75
- atomicshop/speech_recognize.py +8 -0
- atomicshop/ssh_remote.py +158 -172
- atomicshop/system_resource_monitor.py +61 -47
- atomicshop/system_resources.py +8 -8
- atomicshop/tempfiles.py +1 -2
- atomicshop/urls.py +6 -0
- atomicshop/venvs.py +28 -0
- atomicshop/versioning.py +27 -0
- atomicshop/web.py +98 -27
- atomicshop/web_apis/google_custom_search.py +44 -0
- atomicshop/web_apis/google_llm.py +188 -0
- atomicshop/websocket_parse.py +450 -0
- atomicshop/wrappers/certauthw/certauth.py +1 -0
- atomicshop/wrappers/cryptographyw.py +29 -8
- atomicshop/wrappers/ctyping/etw_winapi/const.py +97 -47
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +178 -49
- atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
- atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
- atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -2
- atomicshop/wrappers/ctyping/setup_device.py +466 -0
- atomicshop/wrappers/ctyping/win_console.py +39 -0
- atomicshop/wrappers/dockerw/dockerw.py +113 -2
- atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
- atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
- atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
- atomicshop/wrappers/factw/get_file_data.py +12 -5
- atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
- atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
- atomicshop/wrappers/githubw.py +537 -54
- atomicshop/wrappers/loggingw/consts.py +1 -1
- atomicshop/wrappers/loggingw/filters.py +23 -0
- atomicshop/wrappers/loggingw/formatters.py +12 -0
- atomicshop/wrappers/loggingw/handlers.py +214 -107
- atomicshop/wrappers/loggingw/loggers.py +19 -0
- atomicshop/wrappers/loggingw/loggingw.py +860 -22
- atomicshop/wrappers/loggingw/reading.py +134 -112
- atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +1324 -36
- atomicshop/wrappers/netshw.py +271 -0
- atomicshop/wrappers/playwrightw/engine.py +34 -19
- atomicshop/wrappers/playwrightw/infra.py +5 -0
- atomicshop/wrappers/playwrightw/javascript.py +7 -3
- atomicshop/wrappers/playwrightw/keyboard.py +14 -0
- atomicshop/wrappers/playwrightw/scenarios.py +172 -5
- atomicshop/wrappers/playwrightw/waits.py +9 -7
- atomicshop/wrappers/powershell_networking.py +80 -0
- atomicshop/wrappers/psutilw/processes.py +37 -1
- atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/pywin32w/cert_store.py +116 -0
- atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
- atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
- atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
- atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
- atomicshop/wrappers/socketw/accepter.py +21 -7
- atomicshop/wrappers/socketw/certificator.py +216 -150
- atomicshop/wrappers/socketw/creator.py +190 -50
- atomicshop/wrappers/socketw/dns_server.py +491 -182
- atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
- atomicshop/wrappers/socketw/process_getter.py +86 -0
- atomicshop/wrappers/socketw/receiver.py +144 -102
- atomicshop/wrappers/socketw/sender.py +65 -35
- atomicshop/wrappers/socketw/sni.py +334 -165
- atomicshop/wrappers/socketw/socket_base.py +134 -0
- atomicshop/wrappers/socketw/socket_client.py +137 -95
- atomicshop/wrappers/socketw/socket_server_tester.py +11 -7
- atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
- atomicshop/wrappers/socketw/ssl_base.py +15 -14
- atomicshop/wrappers/socketw/statistics_csv.py +148 -17
- atomicshop/wrappers/sysmonw.py +1 -1
- atomicshop/wrappers/ubuntu_terminal.py +65 -26
- atomicshop/wrappers/win_auditw.py +189 -0
- atomicshop/wrappers/winregw/__init__.py +0 -0
- atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
- atomicshop/wrappers/winregw/winreg_network.py +232 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -51
- atomicshop-3.10.5.dist-info/RECORD +306 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
- atomicshop/_basics_temp.py +0 -101
- atomicshop/a_installs/win/fibratus.py +0 -9
- atomicshop/a_installs/win/mongodb.py +0 -9
- atomicshop/a_installs/win/pycharm.py +0 -9
- atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
- atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
- atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
- atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
- atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
- atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
- atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
- atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
- atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
- atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
- atomicshop/addons/package_setup/Setup.cmd +0 -7
- atomicshop/archiver/_search_in_zip.py +0 -189
- atomicshop/archiver/archiver.py +0 -34
- atomicshop/archiver/search_in_archive.py +0 -250
- atomicshop/archiver/sevenz_app_w.py +0 -86
- atomicshop/archiver/sevenzs.py +0 -44
- atomicshop/archiver/zips.py +0 -293
- atomicshop/file_types.py +0 -24
- atomicshop/mitm/config_editor.py +0 -37
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- atomicshop/mitm/initialize_mitm_server.py +0 -268
- atomicshop/pbtkmultifile_argparse.py +0 -88
- atomicshop/permissions.py +0 -151
- atomicshop/script_as_string_processor.py +0 -38
- atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
- atomicshop/ssh_scripts/process_from_port.py +0 -27
- atomicshop/wrappers/_process_wrapper_curl.py +0 -27
- atomicshop/wrappers/_process_wrapper_tar.py +0 -21
- atomicshop/wrappers/dockerw/install_docker.py +0 -209
- atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
- atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
- atomicshop/wrappers/ffmpegw.py +0 -125
- atomicshop/wrappers/fibratusw/install.py +0 -81
- atomicshop/wrappers/mongodbw/infrastructure.py +0 -53
- atomicshop/wrappers/mongodbw/install_mongodb.py +0 -190
- atomicshop/wrappers/msiw.py +0 -149
- atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
- atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
- atomicshop/wrappers/psutilw/networks.py +0 -45
- atomicshop/wrappers/pycharmw.py +0 -81
- atomicshop/wrappers/socketw/base.py +0 -59
- atomicshop/wrappers/socketw/get_process.py +0 -107
- atomicshop/wrappers/wslw.py +0 -191
- atomicshop-2.15.11.dist-info/RECORD +0 -302
- /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
- /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
- /atomicshop/{archiver → permissions}/__init__.py +0 -0
- /atomicshop/{wrappers/fibratusw → web_apis}/__init__.py +0 -0
- /atomicshop/wrappers/{nodejsw → pywin32w/wmis}/__init__.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
|
@@ -2,28 +2,37 @@ import os
|
|
|
2
2
|
from typing import Literal, Union
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
import datetime
|
|
5
|
+
import re
|
|
5
6
|
|
|
6
7
|
from ... import filesystem, datetimes
|
|
8
|
+
from ...basics import booleans, list_of_classes
|
|
7
9
|
from ...file_io import csvs
|
|
8
10
|
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
def is_string_ends_with_ymd(s: str) -> bool:
|
|
13
|
+
date_tail_re = re.compile(r'(\d{4}-\d{2}-\d{2})$')
|
|
14
|
+
|
|
15
|
+
m = date_tail_re.search(s)
|
|
16
|
+
if not m:
|
|
17
|
+
return False
|
|
18
|
+
try:
|
|
19
|
+
datetime.datetime.strptime(m.group(1), "%Y-%m-%d")
|
|
20
|
+
return True
|
|
21
|
+
except ValueError:
|
|
22
|
+
return False
|
|
12
23
|
|
|
13
24
|
|
|
14
25
|
def get_logs_paths(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
file_name_pattern: str = '*.*',
|
|
18
|
-
date_pattern: str = None,
|
|
26
|
+
log_file_path: str,
|
|
27
|
+
date_format: str = None,
|
|
19
28
|
latest_only: bool = False,
|
|
20
|
-
previous_day_only: bool = False
|
|
21
|
-
|
|
29
|
+
previous_day_only: bool = False,
|
|
30
|
+
yesterday_only: bool = False,
|
|
31
|
+
specific_date: str = None
|
|
32
|
+
) -> list[filesystem.AtomicPath]:
|
|
22
33
|
"""
|
|
23
34
|
This function gets the logs file paths from the directory. Supports rotating files to get the logs by time.
|
|
24
35
|
|
|
25
|
-
:param log_files_directory_path: Path to the log files. If specified, the function will get all the files from the
|
|
26
|
-
directory by the 'file_name_pattern'.
|
|
27
36
|
:param log_file_path: Path to the log file. If specified, the function will get the file and all the rotated logs
|
|
28
37
|
associated with this file. The 'file_name_pattern' will become the file name using the file name and extension.
|
|
29
38
|
|
|
@@ -35,112 +44,126 @@ def get_logs_paths(
|
|
|
35
44
|
|
|
36
45
|
# The 'log_files_directory_path' will also be taken from the 'log_file_path':
|
|
37
46
|
log_files_directory_path = 'C:/logs'
|
|
38
|
-
:param
|
|
39
|
-
Default file_name_pattern will match all the files.
|
|
40
|
-
:param date_pattern: Pattern to match the date in the log file name.
|
|
47
|
+
:param date_format: date format string pattern to match the date in the log file name.
|
|
41
48
|
If specified, the function will get the log file by the date pattern.
|
|
42
49
|
If not specified, the function will get the file date by file last modified time.
|
|
50
|
+
|
|
51
|
+
Example:
|
|
52
|
+
date_format = '%Y-%m-%d'
|
|
43
53
|
:param latest_only: Boolean, if True, only the latest log file path will be returned.
|
|
44
54
|
:param previous_day_only: Boolean, if True, only the log file path from the previous day will be returned.
|
|
55
|
+
:param yesterday_only: Boolean, if True, only the log file path from yesterday will be returned.
|
|
56
|
+
There's a difference between 'previous_day_only' and 'yesterday_only'.
|
|
57
|
+
'previous_day_only' will get the log file from the previous day in the list of files that were found.
|
|
58
|
+
Since that doesn't guarantee that the log file from the previous day is yesterday, we have 'yesterday_only'.
|
|
59
|
+
:param specific_date: Specific date to get the log file path.
|
|
60
|
+
If specified, the function will get the log file by the specific date.
|
|
61
|
+
Meaning that 'date_format' must be specified.
|
|
45
62
|
"""
|
|
46
63
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
booleans.is_only_1_true_in_list(
|
|
65
|
+
booleans_list_of_tuples=[
|
|
66
|
+
(latest_only, 'latest_only'),
|
|
67
|
+
(previous_day_only, 'previous_day_only'),
|
|
68
|
+
(yesterday_only, 'yesterday_only'),
|
|
69
|
+
(specific_date, 'specific_date'),
|
|
70
|
+
],
|
|
71
|
+
raise_if_all_false=False
|
|
72
|
+
)
|
|
51
73
|
|
|
52
|
-
if
|
|
53
|
-
raise ValueError('
|
|
74
|
+
if not date_format and specific_date:
|
|
75
|
+
raise ValueError('If "specific_date" is specified, "date_format" must be specified.')
|
|
54
76
|
|
|
55
|
-
#
|
|
56
|
-
if
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
log_file_extension: str = Path(log_file_path).suffix
|
|
60
|
-
file_name_pattern = f'{log_file_name}*{log_file_extension}'
|
|
77
|
+
# Get the file_name_pattern from the file name. Build the file_name_pattern.
|
|
78
|
+
# For some reason if the file name will be '.zip', then the file stem will be '.zip' and the extension will be ''.
|
|
79
|
+
log_file_name: str = Path(log_file_path).stem
|
|
80
|
+
log_file_extension: str = Path(log_file_path).suffix
|
|
61
81
|
|
|
62
|
-
|
|
63
|
-
|
|
82
|
+
if is_string_ends_with_ymd(log_file_name):
|
|
83
|
+
raise ValueError(
|
|
84
|
+
f'The log file name cannot end with a date in the format YYYY-MM-DD: {log_file_name}')
|
|
64
85
|
|
|
65
|
-
|
|
66
|
-
|
|
86
|
+
if not log_file_extension and '.' in log_file_name:
|
|
87
|
+
log_file_name, log_file_extension = log_file_name.rsplit('.')
|
|
88
|
+
log_file_extension = f'.{log_file_extension}'
|
|
89
|
+
|
|
90
|
+
file_name_pattern: str = f'{log_file_name}*{log_file_extension}'
|
|
91
|
+
|
|
92
|
+
# Get the directory path from the file path.
|
|
93
|
+
log_files_directory_path: str = str(Path(log_file_path).parent)
|
|
94
|
+
|
|
95
|
+
# Get all the log file paths by the file_name_pattern and the date_format string.
|
|
96
|
+
logs_files: list[filesystem.AtomicPath] = filesystem.get_paths_from_directory(
|
|
67
97
|
log_files_directory_path,
|
|
98
|
+
get_file=True,
|
|
68
99
|
file_name_check_pattern=file_name_pattern,
|
|
69
100
|
add_last_modified_time=True,
|
|
70
|
-
sort_by_last_modified_time=True
|
|
101
|
+
sort_by_last_modified_time=True,
|
|
102
|
+
datetime_format=date_format
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# The above will not include the latest log file if it is not rotated yet.
|
|
106
|
+
# noinspection PyTypeChecker
|
|
107
|
+
last_log_file_atomic_path: filesystem.AtomicPath = None
|
|
108
|
+
if os.path.isfile(log_file_path):
|
|
109
|
+
last_log_file_atomic_path = filesystem.AtomicPath(log_file_path)
|
|
110
|
+
last_log_file_atomic_path.update(update_last_modified=True)
|
|
111
|
+
|
|
112
|
+
if logs_files and last_log_file_atomic_path and date_format:
|
|
113
|
+
# The problem here is the file name that doesn't contain the date string in the name.
|
|
114
|
+
# If it is regular log rotation, then there will be one file that doesn't have the date string in the name.
|
|
115
|
+
# If the function used to get the previous day log, then there will be no file that doesn't have the date
|
|
116
|
+
# string.
|
|
117
|
+
|
|
118
|
+
# Get the latest timestamp from the files with dates.
|
|
119
|
+
latest_datetime_float: float = 0
|
|
120
|
+
for file_index, single_file in enumerate(logs_files):
|
|
121
|
+
if single_file.datetime_float > latest_datetime_float:
|
|
122
|
+
latest_datetime_float = single_file.datetime_float
|
|
123
|
+
|
|
124
|
+
# We will add one day to the latest date that we found and assign to the latest file in rotation
|
|
125
|
+
# which is without the datetime string.
|
|
126
|
+
latest_datetime_float += 86400
|
|
127
|
+
last_log_file_atomic_path.datetime_float = latest_datetime_float
|
|
128
|
+
last_log_file_atomic_path.datetime_datetime = datetime.datetime.fromtimestamp(latest_datetime_float)
|
|
129
|
+
last_log_file_atomic_path.datetime_string = (
|
|
130
|
+
last_log_file_atomic_path.datetime_datetime.strftime(date_format))
|
|
131
|
+
last_log_file_atomic_path.datetime_format = date_format
|
|
132
|
+
|
|
133
|
+
# Add the last log file to the list.
|
|
134
|
+
logs_files.append(last_log_file_atomic_path)
|
|
135
|
+
|
|
136
|
+
# Sort the files by the last modified time.
|
|
137
|
+
logs_files = list_of_classes.sort_by_attributes(logs_files, ['datetime_float'])
|
|
138
|
+
elif last_log_file_atomic_path and logs_files and not date_format:
|
|
139
|
+
logs_files.append(last_log_file_atomic_path)
|
|
140
|
+
elif last_log_file_atomic_path and not logs_files:
|
|
141
|
+
logs_files = [last_log_file_atomic_path]
|
|
71
142
|
|
|
72
|
-
# Get the datetime object from the first file name by the date pattern.
|
|
73
|
-
first_date_string = None
|
|
74
143
|
if logs_files:
|
|
75
|
-
first_file_name: str = Path(logs_files[0]['file_path']).name
|
|
76
|
-
first_datetime_object, first_date_string, first_timestamp_float = (
|
|
77
|
-
datetimes.get_datetime_from_complex_string_by_pattern(first_file_name, date_pattern))
|
|
78
|
-
|
|
79
|
-
# The problem here is the file name that doesn't contain the date string in the name.
|
|
80
|
-
# If it is regular log rotation, then there will be one file that doesn't have the date string in the name.
|
|
81
|
-
# If the function used to get the previous day log, then there will be no file that doesn't have the date string.
|
|
82
|
-
if len(logs_files) > 1 or (len(logs_files) == 1 and first_date_string):
|
|
83
|
-
if date_pattern:
|
|
84
|
-
latest_timestamp: float = 0
|
|
85
|
-
for file_index, single_file in enumerate(logs_files):
|
|
86
|
-
# Get file name from current loop file path.
|
|
87
|
-
current_file_name: str = Path(single_file['file_path']).name
|
|
88
|
-
logs_files[file_index]['file_name'] = current_file_name
|
|
89
|
-
|
|
90
|
-
# Get the datetime object from the file name by the date pattern.
|
|
91
|
-
datetime_object, date_string, timestamp_float = (
|
|
92
|
-
datetimes.get_datetime_from_complex_string_by_pattern(current_file_name, date_pattern))
|
|
93
|
-
|
|
94
|
-
# Update the last modified time to the dictionary.
|
|
95
|
-
logs_files[file_index]['last_modified'] = timestamp_float
|
|
96
|
-
logs_files[file_index]['datetime'] = datetime_object
|
|
97
|
-
logs_files[file_index]['date_string'] = date_string
|
|
98
|
-
|
|
99
|
-
if timestamp_float and timestamp_float > latest_timestamp:
|
|
100
|
-
latest_timestamp = timestamp_float
|
|
101
|
-
|
|
102
|
-
# Check timestamps, if more than 1 file is None, then the function that gets the date from the file name
|
|
103
|
-
# didn't work properly, probably because of the string datetime format or the filenames.
|
|
104
|
-
none_timestamps = [single_file['last_modified'] for single_file in logs_files].count(None)
|
|
105
|
-
if none_timestamps > 1:
|
|
106
|
-
raise LogReaderTimeCouldntBeFoundInFileNameError(
|
|
107
|
-
'The date pattern could not be found in the file name. Check the date pattern and the file names.')
|
|
108
|
-
|
|
109
|
-
# Now, there should be a file that doesn't have the string date pattern in the file name.
|
|
110
|
-
# We will add one day to the latest date that we found and assign to that file path.
|
|
111
|
-
for file_index, single_file in enumerate(logs_files):
|
|
112
|
-
if single_file['last_modified'] is None:
|
|
113
|
-
latest_timestamp += 86400
|
|
114
|
-
logs_files[file_index]['last_modified'] = latest_timestamp
|
|
115
|
-
logs_files[file_index]['datetime'] = datetime.datetime.fromtimestamp(latest_timestamp)
|
|
116
|
-
logs_files[file_index]['date_string'] = logs_files[file_index]['datetime'].strftime(date_pattern)
|
|
117
|
-
break
|
|
118
|
-
|
|
119
|
-
# Sort the files by the last modified time.
|
|
120
|
-
logs_files = sorted(logs_files, key=lambda x: x['last_modified'], reverse=False)
|
|
121
|
-
|
|
122
144
|
if latest_only:
|
|
123
145
|
logs_files = [logs_files[-1]]
|
|
124
|
-
|
|
125
|
-
if previous_day_only:
|
|
126
|
-
# Check if there is a previous day log file.
|
|
146
|
+
elif previous_day_only:
|
|
127
147
|
if len(logs_files) == 1:
|
|
128
148
|
logs_files = []
|
|
129
149
|
else:
|
|
130
150
|
logs_files = [logs_files[-2]]
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
151
|
+
elif yesterday_only:
|
|
152
|
+
# Get yesterday's date.
|
|
153
|
+
yesterday_date_string = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime(date_format)
|
|
154
|
+
# Check if there is a yesterday log file.
|
|
155
|
+
logs_files = [single_file
|
|
156
|
+
for single_file in logs_files if single_file.datetime_string == yesterday_date_string]
|
|
157
|
+
elif specific_date:
|
|
158
|
+
# Check if there is a specific date log file.
|
|
159
|
+
logs_files = [single_file for single_file in logs_files if single_file.datetime_string == specific_date]
|
|
135
160
|
|
|
136
161
|
return logs_files
|
|
137
162
|
|
|
138
163
|
|
|
139
164
|
def get_all_log_files_into_list(
|
|
140
|
-
log_files_directory_path: str = None,
|
|
141
165
|
log_file_path: str = None,
|
|
142
|
-
|
|
143
|
-
date_pattern: str = None,
|
|
166
|
+
date_format: str = None,
|
|
144
167
|
log_type: Literal['csv'] = 'csv',
|
|
145
168
|
header_type_of_files: Literal['first', 'all'] = 'first',
|
|
146
169
|
remove_logs: bool = False,
|
|
@@ -151,13 +174,13 @@ def get_all_log_files_into_list(
|
|
|
151
174
|
This function gets the logs contents from the log files. Supports rotating files to get the logs by time.
|
|
152
175
|
All the contents will be merged into one list.
|
|
153
176
|
|
|
154
|
-
:param log_files_directory_path: Path to the log files. Check the 'get_logs_paths' function for more details.
|
|
155
177
|
:param log_file_path: Path to the log file. Check the 'get_logs_paths' function for more details.
|
|
156
|
-
:param
|
|
157
|
-
Default file_name_pattern will match all the files.
|
|
158
|
-
:param date_pattern: Pattern to match the date in the log file name.
|
|
178
|
+
:param date_format: date format string pattern to match the date in the log file name.
|
|
159
179
|
If specified, the function will get the log file by the date pattern.
|
|
160
180
|
If not specified, the function will get the file date by file last modified time.
|
|
181
|
+
|
|
182
|
+
Example:
|
|
183
|
+
date_format = '%Y-%m-%d'
|
|
161
184
|
:param log_type: Type of log to get.
|
|
162
185
|
:param header_type_of_files: Type of header to get from the files.
|
|
163
186
|
'first' - Only the first file has a header for CSV. This header will be used for the rest of the files.
|
|
@@ -180,10 +203,8 @@ def get_all_log_files_into_list(
|
|
|
180
203
|
|
|
181
204
|
# Get all the log file paths by the file_name_pattern.
|
|
182
205
|
logs_files: list = get_logs_paths(
|
|
183
|
-
log_files_directory_path=log_files_directory_path,
|
|
184
206
|
log_file_path=log_file_path,
|
|
185
|
-
|
|
186
|
-
date_pattern=date_pattern)
|
|
207
|
+
date_format=date_format)
|
|
187
208
|
|
|
188
209
|
# Read all the logs.
|
|
189
210
|
logs_content: list = list()
|
|
@@ -191,13 +212,13 @@ def get_all_log_files_into_list(
|
|
|
191
212
|
for single_file in logs_files:
|
|
192
213
|
if log_type == 'csv':
|
|
193
214
|
if header_type_of_files == 'all':
|
|
194
|
-
csv_content, _ = csvs.read_csv_to_list_of_dicts_by_header(single_file
|
|
215
|
+
csv_content, _ = csvs.read_csv_to_list_of_dicts_by_header(single_file.path, **print_kwargs)
|
|
195
216
|
logs_content.extend(csv_content)
|
|
196
217
|
elif header_type_of_files == 'first':
|
|
197
218
|
# The function gets empty header to read it from the CSV file, the returns the header that it read.
|
|
198
219
|
# Then each time the header is fed once again to the function.
|
|
199
220
|
csv_content, header = csvs.read_csv_to_list_of_dicts_by_header(
|
|
200
|
-
single_file
|
|
221
|
+
single_file.path, header=header, **print_kwargs)
|
|
201
222
|
# Any way the first file will be read with header.
|
|
202
223
|
logs_content.extend(csv_content)
|
|
203
224
|
|
|
@@ -208,7 +229,7 @@ def get_all_log_files_into_list(
|
|
|
208
229
|
if remove_logs:
|
|
209
230
|
# Remove the statistics files.
|
|
210
231
|
for single_file in logs_files:
|
|
211
|
-
filesystem.remove_file(single_file
|
|
232
|
+
filesystem.remove_file(single_file.path)
|
|
212
233
|
|
|
213
234
|
if move_to_path:
|
|
214
235
|
# Get formatted time stamp for file name.
|
|
@@ -221,9 +242,7 @@ def get_all_log_files_into_list(
|
|
|
221
242
|
filesystem.create_directory(move_to_path_with_timestamp)
|
|
222
243
|
# Move the statistics files.
|
|
223
244
|
for single_file in logs_files:
|
|
224
|
-
|
|
225
|
-
move_to_path_with_file = f'{move_to_path_with_timestamp}{os.sep}{single_file_name}'
|
|
226
|
-
filesystem.move_file(single_file['file_path'], move_to_path_with_file)
|
|
245
|
+
filesystem.move_file(single_file.path, move_to_path_with_timestamp)
|
|
227
246
|
|
|
228
247
|
return logs_content
|
|
229
248
|
|
|
@@ -263,22 +282,25 @@ class LogReader:
|
|
|
263
282
|
def __init__(
|
|
264
283
|
self,
|
|
265
284
|
log_file_path: str,
|
|
266
|
-
|
|
285
|
+
date_format: str = None,
|
|
267
286
|
log_type: Literal['csv'] = 'csv',
|
|
268
287
|
get_previous_file: bool = False,
|
|
269
288
|
header: list = None
|
|
270
289
|
):
|
|
271
290
|
"""
|
|
272
291
|
:param log_file_path: Path to the log file.
|
|
273
|
-
:param
|
|
292
|
+
:param date_format: date format string pattern to match the date in the log file name.
|
|
274
293
|
If specified, the function will get the log file by the date pattern.
|
|
275
294
|
If not specified, the function will get the file date by file last modified time.
|
|
295
|
+
|
|
296
|
+
Example:
|
|
297
|
+
date_format = '%Y-%m-%d'
|
|
276
298
|
:param log_type: Type of log to get.
|
|
277
299
|
:param get_previous_file: Boolean, if True, the function will get the previous log file.
|
|
278
300
|
For example, your log is set to rotate every Midnight.
|
|
279
|
-
Meaning, once the day will change, the function will get the log file from the previous day in the
|
|
280
|
-
of the return tuple. This happens only once each 24 hours. Not from the time
|
|
281
|
-
the time the day changed.
|
|
301
|
+
Meaning, once the day will change, the function will get the log file from the previous day in the
|
|
302
|
+
third entry of the return tuple. This happens only once each 24 hours. Not from the time
|
|
303
|
+
the function was called, but from the time the day changed.
|
|
282
304
|
:param header: List of strings that will be the header of the CSV file. Default is 'None'.
|
|
283
305
|
None: the header from the CSV file will be used. The first row of the CSV file will be the header.
|
|
284
306
|
Meaning, that the first line will be skipped and the second line will be the first row of the content.
|
|
@@ -287,7 +309,7 @@ class LogReader:
|
|
|
287
309
|
"""
|
|
288
310
|
|
|
289
311
|
self.log_file_path: str = log_file_path
|
|
290
|
-
self.
|
|
312
|
+
self.date_format: str = date_format
|
|
291
313
|
self.log_type: Literal['csv'] = log_type
|
|
292
314
|
self.get_previous_file: bool = get_previous_file
|
|
293
315
|
self.header: list = header
|
|
@@ -329,7 +351,7 @@ class LogReader:
|
|
|
329
351
|
# Get the latest statistics file path.
|
|
330
352
|
latest_statistics_file_path_object = get_logs_paths(
|
|
331
353
|
log_file_path=self.log_file_path,
|
|
332
|
-
|
|
354
|
+
date_format=self.date_format,
|
|
333
355
|
latest_only=True
|
|
334
356
|
)
|
|
335
357
|
|
|
@@ -337,16 +359,16 @@ class LogReader:
|
|
|
337
359
|
# if not latest_statistics_file_path_object:
|
|
338
360
|
# return [], [], self.header
|
|
339
361
|
|
|
340
|
-
latest_statistics_file_path: str = latest_statistics_file_path_object[0]
|
|
362
|
+
latest_statistics_file_path: str = latest_statistics_file_path_object[0].path
|
|
341
363
|
|
|
342
364
|
# Get the previous day statistics file path.
|
|
343
365
|
previous_day_statistics_file_path: Union[str, None] = None
|
|
344
366
|
try:
|
|
345
367
|
previous_day_statistics_file_path = get_logs_paths(
|
|
346
368
|
log_file_path=self.log_file_path,
|
|
347
|
-
|
|
369
|
+
date_format=self.date_format,
|
|
348
370
|
previous_day_only=True
|
|
349
|
-
)[0]
|
|
371
|
+
)[0].path
|
|
350
372
|
# If you get IndexError, it means that there are no previous day logs to read.
|
|
351
373
|
except IndexError:
|
|
352
374
|
pass
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from pymongo import MongoClient
|
|
2
|
+
import pymongo.errors
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
MONGODB_DEFAULT_URI: str = 'mongodb://localhost:27017/'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MongoDBNoConnectionError(Exception):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_connection(
|
|
13
|
+
uri: str = MONGODB_DEFAULT_URI,
|
|
14
|
+
raise_exception: bool = False
|
|
15
|
+
) -> bool:
|
|
16
|
+
"""
|
|
17
|
+
Test the connection to the MongoDB server.
|
|
18
|
+
|
|
19
|
+
:param uri: str, URI to the MongoDB server.
|
|
20
|
+
:param raise_exception: bool, True to raise an exception if the connection fails, False otherwise (just return
|
|
21
|
+
False).
|
|
22
|
+
:return: bool, True if the connection is successful, False otherwise.
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
client = MongoClient(uri)
|
|
26
|
+
client.admin.command('ping')
|
|
27
|
+
return True
|
|
28
|
+
except pymongo.errors.ServerSelectionTimeoutError:
|
|
29
|
+
if raise_exception:
|
|
30
|
+
raise MongoDBNoConnectionError(f"Could not connect to the MongoDB server on: ")
|
|
31
|
+
return False
|