orionis 0.481.0__py3-none-any.whl → 0.482.0__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.
- orionis/metadata/framework.py +1 -1
- orionis/services/log/handlers/filename.py +476 -24
- orionis/services/log/handlers/size_rotating.py +4 -1
- orionis/services/log/handlers/timed_rotating.py +5 -2
- orionis/services/log/log_service.py +7 -9
- orionis/support/facades/application.py +23 -0
- {orionis-0.481.0.dist-info → orionis-0.482.0.dist-info}/METADATA +1 -1
- {orionis-0.481.0.dist-info → orionis-0.482.0.dist-info}/RECORD +12 -11
- {orionis-0.481.0.dist-info → orionis-0.482.0.dist-info}/WHEEL +0 -0
- {orionis-0.481.0.dist-info → orionis-0.482.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.481.0.dist-info → orionis-0.482.0.dist-info}/top_level.txt +0 -0
- {orionis-0.481.0.dist-info → orionis-0.482.0.dist-info}/zip-safe +0 -0
orionis/metadata/framework.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
from pathlib import Path
|
|
2
|
+
from datetime import datetime, timedelta
|
|
4
3
|
|
|
5
4
|
class FileNameLogger:
|
|
6
5
|
|
|
@@ -18,7 +17,6 @@ class FileNameLogger:
|
|
|
18
17
|
ValueError
|
|
19
18
|
If the provided path is not a non-empty string.
|
|
20
19
|
"""
|
|
21
|
-
|
|
22
20
|
# Validate that the path is a non-empty string
|
|
23
21
|
if not isinstance(path, str) or not path:
|
|
24
22
|
raise ValueError("The 'path' parameter must be a non-empty string.")
|
|
@@ -26,26 +24,31 @@ class FileNameLogger:
|
|
|
26
24
|
# Store the stripped path as a private instance variable
|
|
27
25
|
self.__path = path.strip()
|
|
28
26
|
|
|
29
|
-
def
|
|
27
|
+
def __splitDirectory(
|
|
28
|
+
self
|
|
29
|
+
) -> tuple[str, str, str]:
|
|
30
30
|
"""
|
|
31
|
-
|
|
31
|
+
Split the original file path into directory, file name, and extension.
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
This private method processes the stored file path, separating it into its
|
|
34
|
+
directory path, base file name (without extension), and file extension. It
|
|
35
|
+
also ensures that the directory exists, creating it if necessary.
|
|
36
36
|
|
|
37
37
|
Returns
|
|
38
38
|
-------
|
|
39
|
-
str
|
|
40
|
-
|
|
39
|
+
tuple of str
|
|
40
|
+
A tuple containing:
|
|
41
|
+
- The directory path as a string.
|
|
42
|
+
- The base file name (without extension) as a string.
|
|
43
|
+
- The file extension (including the dot) as a string.
|
|
41
44
|
|
|
42
45
|
Notes
|
|
43
46
|
-----
|
|
44
|
-
- The
|
|
45
|
-
-
|
|
47
|
+
- The method handles both forward slash ('/') and backslash ('\\') as path separators.
|
|
48
|
+
- If the directory does not exist, it will be created.
|
|
46
49
|
"""
|
|
47
50
|
|
|
48
|
-
#
|
|
51
|
+
# Determine the path separator and split the path into components
|
|
49
52
|
if '/' in self.__path:
|
|
50
53
|
parts = self.__path.split('/')
|
|
51
54
|
elif '\\' in self.__path:
|
|
@@ -53,22 +56,471 @@ class FileNameLogger:
|
|
|
53
56
|
else:
|
|
54
57
|
parts = self.__path.split(os.sep)
|
|
55
58
|
|
|
56
|
-
# Extract the base file name and its extension
|
|
59
|
+
# Extract the base file name and its extension from the last component
|
|
57
60
|
filename, ext = os.path.splitext(parts[-1])
|
|
58
61
|
|
|
59
62
|
# Reconstruct the directory path (excluding the file name)
|
|
60
63
|
path = os.path.join(*parts[:-1]) if len(parts) > 1 else ''
|
|
61
64
|
|
|
62
|
-
#
|
|
63
|
-
|
|
65
|
+
# Ensure the directory exists; create it if it does not
|
|
66
|
+
if not os.path.isdir(path):
|
|
67
|
+
os.makedirs(path, exist_ok=True)
|
|
68
|
+
|
|
69
|
+
# Return the directory path, file name, and extension as a tuple
|
|
70
|
+
return path, filename, ext
|
|
71
|
+
|
|
72
|
+
def __listFilesInDirectory(
|
|
73
|
+
self,
|
|
74
|
+
directory: str
|
|
75
|
+
) -> list[str]:
|
|
76
|
+
"""
|
|
77
|
+
List all files in the specified directory.
|
|
78
|
+
|
|
79
|
+
This private method retrieves all files in the given directory, returning
|
|
80
|
+
their names as a list. It does not include subdirectories or hidden files.
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
directory : str
|
|
85
|
+
The path to the directory from which to list files.
|
|
86
|
+
|
|
87
|
+
Returns
|
|
88
|
+
-------
|
|
89
|
+
list of dict
|
|
90
|
+
A list of dictionaries, each containing:
|
|
91
|
+
|
|
92
|
+
Notes
|
|
93
|
+
-----
|
|
94
|
+
- The method does not check for file types; it returns all files regardless of extension.
|
|
95
|
+
- If the directory does not exist, an empty list is returned.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
# Check if the directory exists; if not, return an empty list
|
|
99
|
+
if not os.path.isdir(directory):
|
|
100
|
+
return []
|
|
101
|
+
|
|
102
|
+
# List all files in the directory and return their names
|
|
103
|
+
files = []
|
|
104
|
+
for f in os.listdir(directory):
|
|
105
|
+
if os.path.isfile(os.path.join(directory, f)):
|
|
106
|
+
files.append({
|
|
107
|
+
'name': f,
|
|
108
|
+
'path': os.path.join(directory, f),
|
|
109
|
+
'size': os.path.getsize(os.path.join(directory, f)),
|
|
110
|
+
'modified': datetime.fromtimestamp(os.path.getmtime(os.path.join(directory, f)))
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
# Return the list of file names
|
|
114
|
+
return files
|
|
115
|
+
|
|
116
|
+
def __stack(
|
|
117
|
+
self,
|
|
118
|
+
path: str,
|
|
119
|
+
filename: str,
|
|
120
|
+
ext: str
|
|
121
|
+
) -> str:
|
|
122
|
+
"""
|
|
123
|
+
Construct the log file path for the 'stack' channel.
|
|
124
|
+
|
|
125
|
+
This private method generates the full file path for a log file when the
|
|
126
|
+
'stack' channel is specified. It combines the provided directory path,
|
|
127
|
+
base file name, and file extension to create the complete file path.
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
path : str
|
|
132
|
+
The directory path where the log file should be stored.
|
|
133
|
+
filename : str
|
|
134
|
+
The base name of the log file (without extension).
|
|
135
|
+
ext : str
|
|
136
|
+
The file extension, including the dot (e.g., '.log').
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
str
|
|
141
|
+
The full file path for the log file in the specified directory.
|
|
142
|
+
|
|
143
|
+
Notes
|
|
144
|
+
-----
|
|
145
|
+
- This method does not modify or create any directories; it only constructs the path.
|
|
146
|
+
- The resulting path is platform-independent.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
# Join the directory path, file name, and extension to form the full file path
|
|
150
|
+
return os.path.join(path, f"{filename}{ext}")
|
|
151
|
+
|
|
152
|
+
def __hourly(
|
|
153
|
+
self,
|
|
154
|
+
directory: str,
|
|
155
|
+
filename: str,
|
|
156
|
+
ext: str
|
|
157
|
+
) -> str:
|
|
158
|
+
"""
|
|
159
|
+
Construct the log file path for the 'hourly' channel.
|
|
160
|
+
|
|
161
|
+
This private method generates the full file path for a log file when the
|
|
162
|
+
'hourly' channel is specified. If a log file has already been created within
|
|
163
|
+
the last hour, it returns its path; otherwise, it creates a new file name
|
|
164
|
+
with a timestamp.
|
|
64
165
|
|
|
65
|
-
|
|
66
|
-
|
|
166
|
+
Parameters
|
|
167
|
+
----------
|
|
168
|
+
directory : str
|
|
169
|
+
The directory path where the log file should be stored.
|
|
170
|
+
filename : str
|
|
171
|
+
The base name of the log file (without extension).
|
|
172
|
+
ext : str
|
|
173
|
+
The file extension, including the dot (e.g., '.log').
|
|
174
|
+
|
|
175
|
+
Returns
|
|
176
|
+
-------
|
|
177
|
+
str
|
|
178
|
+
The full file path for the log file in the specified directory.
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
now = datetime.now()
|
|
182
|
+
one_hour_ago = now - timedelta(hours=1)
|
|
183
|
+
files = self.__listFilesInDirectory(directory)
|
|
184
|
+
|
|
185
|
+
# Find the most recent file created within the last hour
|
|
186
|
+
recent_file = None
|
|
187
|
+
for file in sorted(files, key=lambda x: x['modified'], reverse=True):
|
|
188
|
+
if file['modified'] >= one_hour_ago and 'hourly' in file['name']:
|
|
189
|
+
recent_file = file['path']
|
|
190
|
+
break
|
|
191
|
+
|
|
192
|
+
# If a recent file is found, return its path
|
|
193
|
+
if recent_file:
|
|
194
|
+
return recent_file
|
|
195
|
+
|
|
196
|
+
# No recent file found, create a new one with timestamp
|
|
197
|
+
timestamp = now.strftime("%Y%m%d_%H%M%S")
|
|
198
|
+
|
|
199
|
+
# Ensure the filename starts with 'hourly_' if not already present
|
|
200
|
+
if 'hourly' not in filename:
|
|
201
|
+
filename = f"hourly_{filename}"
|
|
202
|
+
|
|
203
|
+
# Construct the new file name with the timestamp prefix
|
|
204
|
+
new_filename = f"{timestamp}_{filename}{ext}"
|
|
205
|
+
return os.path.join(directory, new_filename)
|
|
206
|
+
|
|
207
|
+
def __daily(
|
|
208
|
+
self,
|
|
209
|
+
directory: str,
|
|
210
|
+
filename: str,
|
|
211
|
+
ext: str
|
|
212
|
+
) -> str:
|
|
213
|
+
"""
|
|
214
|
+
Construct the log file path for the 'daily' channel.
|
|
215
|
+
|
|
216
|
+
This private method generates the full file path for a log file when the
|
|
217
|
+
'daily' channel is specified. If a log file has already been created for
|
|
218
|
+
the current day, it returns its path; otherwise, it creates a new file name
|
|
219
|
+
with the current date and a high-resolution timestamp to ensure uniqueness.
|
|
220
|
+
|
|
221
|
+
Parameters
|
|
222
|
+
----------
|
|
223
|
+
directory : str
|
|
224
|
+
The directory path where the log file should be stored.
|
|
225
|
+
filename : str
|
|
226
|
+
The base name of the log file (without extension).
|
|
227
|
+
ext : str
|
|
228
|
+
The file extension, including the dot (e.g., '.log').
|
|
67
229
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
230
|
+
Returns
|
|
231
|
+
-------
|
|
232
|
+
str
|
|
233
|
+
The full file path for the log file in the specified directory. If a log
|
|
234
|
+
file for the current day already exists, its path is returned; otherwise,
|
|
235
|
+
a new file path is generated with the current date and a unique timestamp.
|
|
236
|
+
|
|
237
|
+
Notes
|
|
238
|
+
-----
|
|
239
|
+
- The method checks for existing log files for the current day and reuses them if found.
|
|
240
|
+
- If no such file exists, a new file name is generated using the current date and a Unix timestamp.
|
|
241
|
+
- The resulting path is platform-independent.
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
# Get the current date in YYYY_MM_DD format
|
|
245
|
+
date = datetime.now().strftime("%Y_%m_%d")
|
|
246
|
+
|
|
247
|
+
# List all files in the target directory
|
|
248
|
+
files = self.__listFilesInDirectory(directory)
|
|
249
|
+
|
|
250
|
+
# Search for the most recent file created today
|
|
251
|
+
recent_file = None
|
|
252
|
+
for file in sorted(files, key=lambda x: x['modified'], reverse=True):
|
|
253
|
+
if str(file['name']).startswith(date) and 'daily' in file['name']:
|
|
254
|
+
recent_file = file['path']
|
|
255
|
+
break
|
|
256
|
+
|
|
257
|
+
# If a file for today exists, return its path
|
|
258
|
+
if recent_file:
|
|
259
|
+
return recent_file
|
|
260
|
+
|
|
261
|
+
# Prefix the filename with 'daily_' if not already present
|
|
262
|
+
if 'daily' not in filename:
|
|
263
|
+
filename = f"daily_{filename}"
|
|
264
|
+
|
|
265
|
+
# Generate a unique filename using the current date and Unix timestamp
|
|
266
|
+
unix_time = int(datetime.now().timestamp())
|
|
267
|
+
new_filename = f"{date}_{unix_time}_{filename}{ext}"
|
|
268
|
+
return os.path.join(directory, new_filename)
|
|
269
|
+
|
|
270
|
+
def __weekly(
|
|
271
|
+
self,
|
|
272
|
+
directory: str,
|
|
273
|
+
filename: str,
|
|
274
|
+
ext: str
|
|
275
|
+
) -> str:
|
|
276
|
+
"""
|
|
277
|
+
Construct the log file path for the 'weekly' channel.
|
|
278
|
+
|
|
279
|
+
This private method generates the full file path for a log file when the
|
|
280
|
+
'weekly' channel is specified. If a log file has already been created for
|
|
281
|
+
the current week, it returns its path; otherwise, it creates a new file name
|
|
282
|
+
with the current year, ISO week number, and a Unix timestamp to ensure uniqueness.
|
|
283
|
+
|
|
284
|
+
Parameters
|
|
285
|
+
----------
|
|
286
|
+
directory : str
|
|
287
|
+
The directory path where the log file should be stored.
|
|
288
|
+
filename : str
|
|
289
|
+
The base name of the log file (without extension).
|
|
290
|
+
ext : str
|
|
291
|
+
The file extension, including the dot (e.g., '.log').
|
|
72
292
|
|
|
73
|
-
|
|
74
|
-
|
|
293
|
+
Returns
|
|
294
|
+
-------
|
|
295
|
+
str
|
|
296
|
+
The full file path for the log file in the specified directory. If a log
|
|
297
|
+
file for the current week already exists, its path is returned; otherwise,
|
|
298
|
+
a new file path is generated using the current year, ISO week number, and a unique timestamp.
|
|
299
|
+
|
|
300
|
+
Notes
|
|
301
|
+
-----
|
|
302
|
+
- The method checks for existing log files for the current week and reuses them if found.
|
|
303
|
+
- If no such file exists, a new file name is generated using the current year, ISO week number, and Unix timestamp.
|
|
304
|
+
- The resulting path is platform-independent.
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
# Get the current week number and year using ISO calendar
|
|
308
|
+
now = datetime.now()
|
|
309
|
+
year, week_num, _ = now.isocalendar()
|
|
310
|
+
week = f"{year}_W{week_num:02d}"
|
|
311
|
+
|
|
312
|
+
# List all files in the target directory
|
|
313
|
+
files = self.__listFilesInDirectory(directory)
|
|
314
|
+
|
|
315
|
+
# Search for the most recent file created this week with 'weekly' in its name
|
|
316
|
+
recent_file = None
|
|
317
|
+
for file in sorted(files, key=lambda x: x['modified'], reverse=True):
|
|
318
|
+
if str(file['name']).startswith(week) and 'weekly' in file['name']:
|
|
319
|
+
recent_file = file['path']
|
|
320
|
+
break
|
|
321
|
+
|
|
322
|
+
# If a file for this week exists, return its path
|
|
323
|
+
if recent_file:
|
|
324
|
+
return recent_file
|
|
325
|
+
|
|
326
|
+
# Prefix the filename with 'weekly_' if not already present
|
|
327
|
+
if 'weekly' not in filename:
|
|
328
|
+
filename = f"weekly_{filename}"
|
|
329
|
+
|
|
330
|
+
# Generate a unique filename using the current year, week, and Unix timestamp
|
|
331
|
+
unix_time = int(datetime.now().timestamp())
|
|
332
|
+
new_filename = f"{week}_{unix_time}_{filename}{ext}"
|
|
333
|
+
|
|
334
|
+
# Return the full path to the new weekly log file
|
|
335
|
+
return os.path.join(directory, new_filename)
|
|
336
|
+
|
|
337
|
+
def __monthly(
|
|
338
|
+
self,
|
|
339
|
+
directory: str,
|
|
340
|
+
filename: str,
|
|
341
|
+
ext: str
|
|
342
|
+
) -> str:
|
|
343
|
+
"""
|
|
344
|
+
Construct the log file path for the 'monthly' channel.
|
|
345
|
+
|
|
346
|
+
This private method generates the full file path for a log file when the
|
|
347
|
+
'monthly' channel is specified. If a log file has already been created for
|
|
348
|
+
the current month, it returns its path; otherwise, it creates a new file name
|
|
349
|
+
with the current year, month, and a Unix timestamp to ensure uniqueness.
|
|
350
|
+
|
|
351
|
+
Parameters
|
|
352
|
+
----------
|
|
353
|
+
directory : str
|
|
354
|
+
The directory path where the log file should be stored.
|
|
355
|
+
filename : str
|
|
356
|
+
The base name of the log file (without extension).
|
|
357
|
+
ext : str
|
|
358
|
+
The file extension, including the dot (e.g., '.log').
|
|
359
|
+
|
|
360
|
+
Returns
|
|
361
|
+
-------
|
|
362
|
+
str
|
|
363
|
+
The full file path for the log file in the specified directory. If a log
|
|
364
|
+
file for the current month already exists, its path is returned; otherwise,
|
|
365
|
+
a new file path is generated using the current year, month, and a unique timestamp.
|
|
366
|
+
|
|
367
|
+
Notes
|
|
368
|
+
-----
|
|
369
|
+
- The method checks for existing log files for the current month and reuses them if found.
|
|
370
|
+
- If no such file exists, a new file name is generated using the current year, month, and Unix timestamp.
|
|
371
|
+
- The resulting path is platform-independent.
|
|
372
|
+
"""
|
|
373
|
+
|
|
374
|
+
# Get the current year and month
|
|
375
|
+
now = datetime.now()
|
|
376
|
+
year = now.year
|
|
377
|
+
month = now.month
|
|
378
|
+
month_str = f"{year}_M{month:02d}"
|
|
379
|
+
|
|
380
|
+
# List all files in the target directory
|
|
381
|
+
files = self.__listFilesInDirectory(directory)
|
|
382
|
+
|
|
383
|
+
# Search for the most recent file created this month with 'monthly' in its name
|
|
384
|
+
recent_file = None
|
|
385
|
+
for file in sorted(files, key=lambda x: x['modified'], reverse=True):
|
|
386
|
+
if str(file['name']).startswith(month_str) and 'monthly' in file['name']:
|
|
387
|
+
recent_file = file['path']
|
|
388
|
+
break
|
|
389
|
+
|
|
390
|
+
# If a file for this month exists, return its path
|
|
391
|
+
if recent_file:
|
|
392
|
+
return recent_file
|
|
393
|
+
|
|
394
|
+
# Prefix the filename with 'monthly_' if not already present
|
|
395
|
+
if 'monthly' not in filename:
|
|
396
|
+
filename = f"monthly_{filename}"
|
|
397
|
+
|
|
398
|
+
# Generate a unique filename using the current year, month, and Unix timestamp
|
|
399
|
+
unix_time = int(datetime.now().timestamp())
|
|
400
|
+
new_filename = f"{month_str}_{unix_time}_{filename}{ext}"
|
|
401
|
+
|
|
402
|
+
# Return the full path to the new monthly log file
|
|
403
|
+
return os.path.join(directory, new_filename)
|
|
404
|
+
|
|
405
|
+
def __chunked(
|
|
406
|
+
self,
|
|
407
|
+
directory: str,
|
|
408
|
+
filename: str,
|
|
409
|
+
ext: str,
|
|
410
|
+
max_bytes: int = 5242880
|
|
411
|
+
) -> str:
|
|
412
|
+
"""
|
|
413
|
+
Construct the log file path for the 'chunked' channel.
|
|
414
|
+
|
|
415
|
+
This private method generates the full file path for a log file when the
|
|
416
|
+
'chunked' channel is specified. It checks for the most recent log file
|
|
417
|
+
in the specified directory with 'chunked' in its name and a size less than
|
|
418
|
+
the specified maximum number of bytes. If such a file exists, its path is
|
|
419
|
+
returned. Otherwise, a new file name is generated using the current Unix
|
|
420
|
+
timestamp and the 'chunked_' prefix.
|
|
421
|
+
|
|
422
|
+
Parameters
|
|
423
|
+
----------
|
|
424
|
+
directory : str
|
|
425
|
+
The directory path where the log file should be stored.
|
|
426
|
+
filename : str
|
|
427
|
+
The base name of the log file (without extension).
|
|
428
|
+
ext : str
|
|
429
|
+
The file extension, including the dot (e.g., '.log').
|
|
430
|
+
max_bytes : int, optional
|
|
431
|
+
The maximum allowed size in bytes for a chunked log file. Default is 5 MB (5242880 bytes).
|
|
432
|
+
|
|
433
|
+
Returns
|
|
434
|
+
-------
|
|
435
|
+
str
|
|
436
|
+
The full file path for the chunked log file in the specified directory.
|
|
437
|
+
If a suitable file exists (with 'chunked' in its name and size less than
|
|
438
|
+
`max_bytes`), its path is returned. Otherwise, a new file path is generated
|
|
439
|
+
with a unique timestamp and returned.
|
|
440
|
+
|
|
441
|
+
Notes
|
|
442
|
+
-----
|
|
443
|
+
- The method checks for existing chunked log files and reuses them if their size
|
|
444
|
+
is below the specified threshold.
|
|
445
|
+
- If no such file exists, a new file name is generated using the current Unix timestamp.
|
|
446
|
+
- The resulting path is platform-independent.
|
|
447
|
+
"""
|
|
448
|
+
|
|
449
|
+
# List all files in the target directory
|
|
450
|
+
files = self.__listFilesInDirectory(directory)
|
|
451
|
+
|
|
452
|
+
# Search for the most recent file with 'chunked' in its name and size less than max_bytes
|
|
453
|
+
recent_file = None
|
|
454
|
+
for file in sorted(files, key=lambda x: x['modified'], reverse=True):
|
|
455
|
+
if 'chunked' in file['name'] and file['size'] < max_bytes:
|
|
456
|
+
recent_file = file['path']
|
|
457
|
+
break
|
|
458
|
+
|
|
459
|
+
# If a suitable chunked file exists, return its path
|
|
460
|
+
if recent_file:
|
|
461
|
+
return recent_file
|
|
462
|
+
|
|
463
|
+
# Prefix the filename with 'chunked_' if not already present
|
|
464
|
+
if 'chunked' not in filename:
|
|
465
|
+
filename = f"chunked_{filename}"
|
|
466
|
+
|
|
467
|
+
# Generate a unique filename using the current Unix timestamp
|
|
468
|
+
unix_time = int(datetime.now().timestamp())
|
|
469
|
+
new_filename = f"{unix_time}_{filename}{ext}"
|
|
470
|
+
|
|
471
|
+
# Return the full path to the new chunked log file
|
|
472
|
+
return os.path.join(directory, new_filename)
|
|
473
|
+
|
|
474
|
+
def generate(self, channel: str, max_bytes: int = 5242880) -> str:
|
|
475
|
+
"""
|
|
476
|
+
Generate the appropriate log file path based on the specified channel.
|
|
477
|
+
|
|
478
|
+
This method determines the log file naming strategy according to the given
|
|
479
|
+
channel type. It delegates the file path construction to the corresponding
|
|
480
|
+
private method for each channel. For the 'chunked' channel, the maximum
|
|
481
|
+
allowed file size can be specified.
|
|
482
|
+
|
|
483
|
+
Parameters
|
|
484
|
+
----------
|
|
485
|
+
channel : str
|
|
486
|
+
The log channel type. Supported values are:
|
|
487
|
+
'stack', 'hourly', 'daily', 'weekly', 'monthly', 'chunked'.
|
|
488
|
+
max_bytes : int, optional
|
|
489
|
+
The maximum allowed size in bytes for a chunked log file. Only used
|
|
490
|
+
when `channel` is 'chunked'. Default is 5 MB (5242880 bytes).
|
|
491
|
+
|
|
492
|
+
Returns
|
|
493
|
+
-------
|
|
494
|
+
str
|
|
495
|
+
The full file path for the log file according to the specified channel.
|
|
496
|
+
|
|
497
|
+
Raises
|
|
498
|
+
------
|
|
499
|
+
ValueError
|
|
500
|
+
If the provided channel is not supported.
|
|
501
|
+
|
|
502
|
+
Notes
|
|
503
|
+
-----
|
|
504
|
+
- The method uses the original file path provided during initialization.
|
|
505
|
+
- For all channels except 'chunked', `max_bytes` is ignored.
|
|
506
|
+
- The resulting file path is platform-independent.
|
|
507
|
+
"""
|
|
508
|
+
|
|
509
|
+
# Select the appropriate file path generation strategy based on the channel
|
|
510
|
+
if channel == 'stack':
|
|
511
|
+
return self.__stack(*self.__splitDirectory())
|
|
512
|
+
elif channel == 'hourly':
|
|
513
|
+
return self.__hourly(*self.__splitDirectory())
|
|
514
|
+
elif channel == 'daily':
|
|
515
|
+
return self.__daily(*self.__splitDirectory())
|
|
516
|
+
elif channel == 'weekly':
|
|
517
|
+
return self.__weekly(*self.__splitDirectory())
|
|
518
|
+
elif channel == 'monthly':
|
|
519
|
+
return self.__monthly(*self.__splitDirectory())
|
|
520
|
+
elif channel == 'chunked':
|
|
521
|
+
return self.__chunked(*self.__splitDirectory(), max_bytes=max_bytes)
|
|
522
|
+
else:
|
|
523
|
+
raise ValueError(
|
|
524
|
+
f"Unknown channel: {channel}. Supported channels are: "
|
|
525
|
+
"'stack', 'hourly', 'daily', 'weekly', 'monthly', 'chunked'."
|
|
526
|
+
)
|
|
@@ -25,5 +25,8 @@ class PrefixedSizeRotatingFileHandler(RotatingFileHandler):
|
|
|
25
25
|
The timestamp prefix helps in identifying the creation time of each rotated log file.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
+
# Import Application to access configuration settings
|
|
29
|
+
from orionis.support.facades.application import Application
|
|
30
|
+
|
|
28
31
|
# Generate the new filename using FileNameLogger, which adds a timestamp prefix.
|
|
29
|
-
return FileNameLogger(default_name).generate()
|
|
32
|
+
return FileNameLogger(default_name).generate('chunked', Application.config('logging.channels.chunked.mb_size', 5))
|
|
@@ -25,5 +25,8 @@ class PrefixedTimedRotatingFileHandler(TimedRotatingFileHandler):
|
|
|
25
25
|
The timestamp prefix helps in organizing and distinguishing rotated log files.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
#
|
|
29
|
-
|
|
28
|
+
# Import Application to access configuration settings
|
|
29
|
+
from orionis.support.facades.application import Application
|
|
30
|
+
|
|
31
|
+
# Generate the new filename using FileNameLogger, which adds a timestamp prefix.
|
|
32
|
+
return FileNameLogger(default_name).generate(Application.config('logging.default', 'stack'))
|
|
@@ -110,9 +110,6 @@ class Logger(ILogger):
|
|
|
110
110
|
# Get the configuration object for the selected channel
|
|
111
111
|
config_channels = getattr(self.__config.channels, channel)
|
|
112
112
|
|
|
113
|
-
# Generate the log file path using the FileNameLogger utility
|
|
114
|
-
path: str = FileNameLogger(getattr(config_channels, 'path')).generate()
|
|
115
|
-
|
|
116
113
|
# Determine the logging level (default to DEBUG if not specified)
|
|
117
114
|
level: Level | int = getattr(config_channels, 'level', 10)
|
|
118
115
|
level = level if isinstance(level, int) else level.value
|
|
@@ -122,7 +119,7 @@ class Logger(ILogger):
|
|
|
122
119
|
# Simple file handler for stack channel
|
|
123
120
|
handlers = [
|
|
124
121
|
logging.FileHandler(
|
|
125
|
-
filename=path,
|
|
122
|
+
filename=FileNameLogger(getattr(config_channels, 'path')).generate(channel),
|
|
126
123
|
encoding="utf-8"
|
|
127
124
|
)
|
|
128
125
|
]
|
|
@@ -131,7 +128,7 @@ class Logger(ILogger):
|
|
|
131
128
|
# Rotating file handler for hourly logs
|
|
132
129
|
handlers = [
|
|
133
130
|
PrefixedTimedRotatingFileHandler(
|
|
134
|
-
filename=path,
|
|
131
|
+
filename=FileNameLogger(getattr(config_channels, 'path')).generate(channel),
|
|
135
132
|
when="h",
|
|
136
133
|
interval=1,
|
|
137
134
|
backupCount=getattr(config_channels, 'retention_hours', 24),
|
|
@@ -144,7 +141,7 @@ class Logger(ILogger):
|
|
|
144
141
|
# Rotating file handler for daily logs
|
|
145
142
|
handlers = [
|
|
146
143
|
PrefixedTimedRotatingFileHandler(
|
|
147
|
-
filename=path,
|
|
144
|
+
filename=FileNameLogger(getattr(config_channels, 'path')).generate(channel),
|
|
148
145
|
when="d",
|
|
149
146
|
interval=1,
|
|
150
147
|
backupCount=getattr(config_channels, 'retention_days', 7),
|
|
@@ -158,7 +155,7 @@ class Logger(ILogger):
|
|
|
158
155
|
# Rotating file handler for weekly logs
|
|
159
156
|
handlers = [
|
|
160
157
|
PrefixedTimedRotatingFileHandler(
|
|
161
|
-
filename=path,
|
|
158
|
+
filename=FileNameLogger(getattr(config_channels, 'path')).generate(channel),
|
|
162
159
|
when="w0",
|
|
163
160
|
interval=1,
|
|
164
161
|
backupCount=getattr(config_channels, 'retention_weeks', 4),
|
|
@@ -171,7 +168,7 @@ class Logger(ILogger):
|
|
|
171
168
|
# Rotating file handler for monthly logs
|
|
172
169
|
handlers = [
|
|
173
170
|
PrefixedTimedRotatingFileHandler(
|
|
174
|
-
filename=path,
|
|
171
|
+
filename=FileNameLogger(getattr(config_channels, 'path')).generate(channel),
|
|
175
172
|
when="midnight",
|
|
176
173
|
interval=30,
|
|
177
174
|
backupCount=getattr(config_channels, 'retention_months', 4),
|
|
@@ -182,9 +179,10 @@ class Logger(ILogger):
|
|
|
182
179
|
|
|
183
180
|
elif channel == "chunked":
|
|
184
181
|
# Size-based rotating file handler for chunked logs
|
|
182
|
+
max_bytes = getattr(config_channels, 'mb_size', 10) * 1024 * 1024
|
|
185
183
|
handlers = [
|
|
186
184
|
PrefixedSizeRotatingFileHandler(
|
|
187
|
-
filename=path,
|
|
185
|
+
filename=FileNameLogger(getattr(config_channels, 'path')).generate(channel, max_bytes),
|
|
188
186
|
maxBytes=getattr(config_channels, 'mb_size', 10) * 1024 * 1024,
|
|
189
187
|
backupCount=getattr(config_channels, 'files', 5),
|
|
190
188
|
encoding="utf-8"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from orionis.container.facades.facade import Facade
|
|
2
|
+
|
|
3
|
+
class Application(Facade):
|
|
4
|
+
|
|
5
|
+
@classmethod
|
|
6
|
+
def getFacadeAccessor(cls) -> str:
|
|
7
|
+
"""
|
|
8
|
+
Get the registered service container binding key for the console component.
|
|
9
|
+
|
|
10
|
+
This method returns the specific binding key that is used to resolve the
|
|
11
|
+
console output service from the dependency injection container. The facade
|
|
12
|
+
pattern uses this key to locate and instantiate the underlying console
|
|
13
|
+
service implementation.
|
|
14
|
+
|
|
15
|
+
Returns
|
|
16
|
+
-------
|
|
17
|
+
str
|
|
18
|
+
The string identifier 'x-orionis.services.log.log_service' used as the
|
|
19
|
+
binding key to resolve the console service from the service container.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
# Return the predefined binding key for the console output service
|
|
23
|
+
return "x-orionis.services.log.log_service"
|
|
@@ -199,7 +199,7 @@ orionis/foundation/providers/scheduler_provider.py,sha256=72SoixFog9IOE9Ve9Xcfw6
|
|
|
199
199
|
orionis/foundation/providers/testing_provider.py,sha256=SrJRpdvcblx9WvX7x9Y3zc7OQfiTf7la0HAJrm2ESlE,3725
|
|
200
200
|
orionis/foundation/providers/workers_provider.py,sha256=oa_2NIDH6UxZrtuGkkoo_zEoNIMGgJ46vg5CCgAm7wI,3926
|
|
201
201
|
orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
202
|
-
orionis/metadata/framework.py,sha256=
|
|
202
|
+
orionis/metadata/framework.py,sha256=_5YbwWTtix0nrC_iOD_3NIidY-aj0jZHYz4I8YgV7ME,4109
|
|
203
203
|
orionis/metadata/package.py,sha256=k7Yriyp5aUcR-iR8SK2ec_lf0_Cyc-C7JczgXa-I67w,16039
|
|
204
204
|
orionis/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
205
205
|
orionis/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -270,15 +270,15 @@ orionis/services/introspection/modules/contracts/reflection.py,sha256=YLqKg5Ehad
|
|
|
270
270
|
orionis/services/introspection/objects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
271
271
|
orionis/services/introspection/objects/types.py,sha256=vNKWc2b7K-X7B2X8RCimgAWQqbQlVT-aL24nUB8t_yQ,6343
|
|
272
272
|
orionis/services/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
273
|
-
orionis/services/log/log_service.py,sha256=
|
|
273
|
+
orionis/services/log/log_service.py,sha256=y1ysxZ7MuO2NuJXGnPVp1xXsJf6TVkOiMdd-ZvgbwQI,11620
|
|
274
274
|
orionis/services/log/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
275
275
|
orionis/services/log/contracts/log_service.py,sha256=YVWkK5z6-3jyJv6aT8fbp53nQBF8jlD-aHGKqFYPdAM,1692
|
|
276
276
|
orionis/services/log/exceptions/__init__.py,sha256=PPn_LBV3U-0Yi69ZLDQmlkbmlL1iLTleLw-s88Ipg9o,84
|
|
277
277
|
orionis/services/log/exceptions/runtime.py,sha256=LnaK0w0WlgxtZ9Zjn9RYIgp6fbQZmXZ_1fy9dkuA2jQ,468
|
|
278
278
|
orionis/services/log/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
279
|
-
orionis/services/log/handlers/filename.py,sha256=
|
|
280
|
-
orionis/services/log/handlers/size_rotating.py,sha256=
|
|
281
|
-
orionis/services/log/handlers/timed_rotating.py,sha256=
|
|
279
|
+
orionis/services/log/handlers/filename.py,sha256=722mnk075vvq02MtpKaDWzLHEUd3sQyhL0a6xd0vLeA,20122
|
|
280
|
+
orionis/services/log/handlers/size_rotating.py,sha256=O0rE2LkS4nfjsOjcOXL0aG1csOuK2RKGeRdBlYJ6qTs,1333
|
|
281
|
+
orionis/services/log/handlers/timed_rotating.py,sha256=XM72DFwKcE0AU4oiCvhy2FXxteZ7HtxpGaxisv504nY,1317
|
|
282
282
|
orionis/services/system/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
283
283
|
orionis/services/system/imports.py,sha256=aSXG9879ur91d6OsqV2DUYWmmwbwFHX8CHb99cPfFcU,7057
|
|
284
284
|
orionis/services/system/workers.py,sha256=EfGxU_w42xRnZ1yslsui3wVG8pfe__V3GYGEIyo8JxQ,3144
|
|
@@ -291,6 +291,7 @@ orionis/support/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
291
291
|
orionis/support/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
292
292
|
orionis/support/entities/base.py,sha256=kVx9YWZjYS6C9MraarU7U12OeT5enBp5XqizrQm4RQs,4801
|
|
293
293
|
orionis/support/facades/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
294
|
+
orionis/support/facades/application.py,sha256=GxB6TzsCSyDEHlvJJr-WVrppJvuolXCcV1vZ0tq_H6E,883
|
|
294
295
|
orionis/support/facades/console.py,sha256=Yhpgv0FpwyOXP4IMgTtDw0_nkcu-J_9nhZRPwJCetCg,875
|
|
295
296
|
orionis/support/facades/dumper.py,sha256=qQPoMbkXExv6UaByoDCyJA-gt5SA1oQtym2TwpihtoI,794
|
|
296
297
|
orionis/support/facades/executor.py,sha256=fRBQ447WpL2T42Ys02k_DJNqukFFk8-bbNFz4GEbRfI,931
|
|
@@ -370,7 +371,7 @@ orionis/test/validators/web_report.py,sha256=n9BfzOZz6aEiNTypXcwuWbFRG0OdHNSmCNu
|
|
|
370
371
|
orionis/test/validators/workers.py,sha256=rWcdRexINNEmGaO7mnc1MKUxkHKxrTsVuHgbnIfJYgc,1206
|
|
371
372
|
orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
372
373
|
orionis/test/view/render.py,sha256=f-zNhtKSg9R5Njqujbg2l2amAs2-mRVESneLIkWOZjU,4082
|
|
373
|
-
orionis-0.
|
|
374
|
+
orionis-0.482.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
|
|
374
375
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
375
376
|
tests/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
376
377
|
tests/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -517,8 +518,8 @@ tests/testing/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
517
518
|
tests/testing/validators/test_testing_validators.py,sha256=WPo5GxTP6xE-Dw3X1vZoqOMpb6HhokjNSbgDsDRDvy4,16588
|
|
518
519
|
tests/testing/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
519
520
|
tests/testing/view/test_render.py,sha256=tnnMBwS0iKUIbogLvu-7Rii50G6Koddp3XT4wgdFEYM,1050
|
|
520
|
-
orionis-0.
|
|
521
|
-
orionis-0.
|
|
522
|
-
orionis-0.
|
|
523
|
-
orionis-0.
|
|
524
|
-
orionis-0.
|
|
521
|
+
orionis-0.482.0.dist-info/METADATA,sha256=G2omW6axkClb2bZufamTZKGAw4zPQPxlI-QGmAzf_VE,4801
|
|
522
|
+
orionis-0.482.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
523
|
+
orionis-0.482.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
|
|
524
|
+
orionis-0.482.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
|
|
525
|
+
orionis-0.482.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|