orionis 0.481.0__py3-none-any.whl → 0.483.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/console/commands/scheduler_list.py +139 -0
- orionis/console/commands/scheduler_work.py +68 -23
- orionis/console/core/reactor.py +3 -1
- 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.483.0.dist-info}/METADATA +1 -1
- {orionis-0.481.0.dist-info → orionis-0.483.0.dist-info}/RECORD +15 -13
- {orionis-0.481.0.dist-info → orionis-0.483.0.dist-info}/WHEEL +0 -0
- {orionis-0.481.0.dist-info → orionis-0.483.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.481.0.dist-info → orionis-0.483.0.dist-info}/top_level.txt +0 -0
- {orionis-0.481.0.dist-info → orionis-0.483.0.dist-info}/zip-safe +0 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import os
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from rich.panel import Panel
|
|
6
|
+
from rich.table import Table
|
|
7
|
+
from orionis.console.base.command import BaseCommand
|
|
8
|
+
from orionis.console.contracts.schedule import ISchedule
|
|
9
|
+
from orionis.console.exceptions import CLIOrionisRuntimeError
|
|
10
|
+
from orionis.foundation.contracts.application import IApplication
|
|
11
|
+
|
|
12
|
+
class ScheduleListCommand(BaseCommand):
|
|
13
|
+
"""
|
|
14
|
+
Command class to display usage information for the Orionis CLI.
|
|
15
|
+
|
|
16
|
+
Methods
|
|
17
|
+
-------
|
|
18
|
+
handle(orionis: IApplication, console: Console) -> bool
|
|
19
|
+
Displays a table of scheduled tasks defined in the application.
|
|
20
|
+
Imports the scheduler module, retrieves scheduled jobs, and prints them
|
|
21
|
+
in a formatted table using the rich library.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
bool
|
|
26
|
+
Returns True if the scheduled jobs are listed successfully or if no jobs are found.
|
|
27
|
+
Raises CLIOrionisRuntimeError if an error occurs during execution.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
# Indicates whether timestamps will be shown in the command output
|
|
31
|
+
timestamps: bool = False
|
|
32
|
+
|
|
33
|
+
# Command signature and description
|
|
34
|
+
signature: str = "schedule:list"
|
|
35
|
+
|
|
36
|
+
# Command description
|
|
37
|
+
description: str = "Executes the scheduled tasks defined in the application."
|
|
38
|
+
|
|
39
|
+
def handle(self, orionis: IApplication, console: Console) -> bool:
|
|
40
|
+
"""
|
|
41
|
+
Displays a table of scheduled jobs defined in the application.
|
|
42
|
+
|
|
43
|
+
This method dynamically imports the scheduler module, retrieves the list of
|
|
44
|
+
scheduled jobs using the ISchedule service, and prints the jobs in a formatted
|
|
45
|
+
table. If no jobs are found, a message is displayed. Handles and reports errors
|
|
46
|
+
encountered during the process.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
orionis : IApplication
|
|
51
|
+
The application instance providing configuration and service resolution.
|
|
52
|
+
console : Console
|
|
53
|
+
The rich Console instance used for output.
|
|
54
|
+
|
|
55
|
+
Returns
|
|
56
|
+
-------
|
|
57
|
+
bool
|
|
58
|
+
Returns True if the scheduled jobs are listed successfully or if no jobs are found.
|
|
59
|
+
Raises CLIOrionisRuntimeError if an error occurs during execution.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
|
|
64
|
+
# Get the absolute path of the scheduler from the application configuration
|
|
65
|
+
scheduler_path = orionis.path('console_scheduler')
|
|
66
|
+
|
|
67
|
+
# Get the base path from the current working directory
|
|
68
|
+
base_path = Path(os.getcwd()).resolve()
|
|
69
|
+
scheduler_path = Path(scheduler_path).resolve()
|
|
70
|
+
rel_path = scheduler_path.relative_to(base_path)
|
|
71
|
+
|
|
72
|
+
# Convert the path to a module name (replace separators with dots, remove .py)
|
|
73
|
+
module_name = ".".join(rel_path.with_suffix('').parts)
|
|
74
|
+
|
|
75
|
+
# Dynamically import the scheduler module
|
|
76
|
+
scheduler_module = importlib.import_module(module_name)
|
|
77
|
+
|
|
78
|
+
# Retrieve the Scheduler class from the imported module
|
|
79
|
+
Scheduler = getattr(scheduler_module, "Scheduler", None)
|
|
80
|
+
|
|
81
|
+
# Raise an error if the Scheduler class is not found
|
|
82
|
+
if Scheduler is None:
|
|
83
|
+
raise CLIOrionisRuntimeError(f"Scheduler class not found in module {module_name}")
|
|
84
|
+
|
|
85
|
+
# Retrieve the 'tasks' method from the Scheduler class
|
|
86
|
+
task_method = getattr(Scheduler, "tasks", None)
|
|
87
|
+
|
|
88
|
+
# Raise an error if the 'tasks' method is not found
|
|
89
|
+
if task_method is None:
|
|
90
|
+
raise CLIOrionisRuntimeError(f"Method 'tasks' not found in Scheduler class in module {module_name}")
|
|
91
|
+
|
|
92
|
+
# Create an instance of ISchedule using the application container
|
|
93
|
+
schedule_serice: ISchedule = orionis.make(ISchedule)
|
|
94
|
+
|
|
95
|
+
# Initialize the scheduled tasks by calling the 'tasks' method
|
|
96
|
+
task_method(schedule_serice)
|
|
97
|
+
|
|
98
|
+
# Retrieve the list of scheduled jobs/events
|
|
99
|
+
list_tasks = schedule_serice.events()
|
|
100
|
+
|
|
101
|
+
# Display a message if no scheduled jobs are found
|
|
102
|
+
if not list_tasks:
|
|
103
|
+
console.line()
|
|
104
|
+
console.print(Panel("No scheduled jobs found.", border_style="green"))
|
|
105
|
+
console.line()
|
|
106
|
+
return True
|
|
107
|
+
|
|
108
|
+
# Create and configure a table to display scheduled jobs
|
|
109
|
+
table = Table(title="Scheduled Jobs", show_lines=True)
|
|
110
|
+
table.add_column("Signature", style="cyan", no_wrap=True)
|
|
111
|
+
table.add_column("Arguments", style="magenta")
|
|
112
|
+
table.add_column("Purpose", style="green")
|
|
113
|
+
table.add_column("Random Delay", style="yellow")
|
|
114
|
+
table.add_column("Start Date", style="white")
|
|
115
|
+
table.add_column("End Date", style="white")
|
|
116
|
+
table.add_column("Details", style="dim")
|
|
117
|
+
|
|
118
|
+
# Populate the table with job details
|
|
119
|
+
for job in list_tasks:
|
|
120
|
+
signature = str(job.get("signature", ""))
|
|
121
|
+
args = ", ".join(map(str, job.get("args", [])))
|
|
122
|
+
purpose = str(job.get("purpose", ""))
|
|
123
|
+
random_delay = str(job.get("random_delay", ""))
|
|
124
|
+
start_date = str(job.get("start_date", "")) if job.get("start_date") else "-"
|
|
125
|
+
end_date = str(job.get("end_date", "")) if job.get("end_date") else "-"
|
|
126
|
+
details = str(job.get("details", ""))
|
|
127
|
+
|
|
128
|
+
table.add_row(signature, args, purpose, random_delay, start_date, end_date, details)
|
|
129
|
+
|
|
130
|
+
# Print the table to the console
|
|
131
|
+
console.line()
|
|
132
|
+
console.print(table)
|
|
133
|
+
console.line()
|
|
134
|
+
return True
|
|
135
|
+
|
|
136
|
+
except Exception as exc:
|
|
137
|
+
|
|
138
|
+
# Catch any unexpected exceptions and raise as a CLIOrionisRuntimeError
|
|
139
|
+
raise CLIOrionisRuntimeError(f"An unexpected error occurred while clearing the cache: {exc}")
|
|
@@ -1,18 +1,41 @@
|
|
|
1
1
|
import importlib
|
|
2
2
|
import os
|
|
3
|
+
from datetime import datetime
|
|
3
4
|
from pathlib import Path
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel
|
|
7
|
+
from rich.text import Text
|
|
4
8
|
from orionis.console.base.command import BaseCommand
|
|
5
9
|
from orionis.console.contracts.schedule import ISchedule
|
|
6
10
|
from orionis.console.exceptions import CLIOrionisRuntimeError
|
|
7
11
|
from orionis.foundation.contracts.application import IApplication
|
|
8
|
-
from rich.console import Console
|
|
9
|
-
from rich.panel import Panel
|
|
10
|
-
from rich.text import Text
|
|
11
|
-
from datetime import datetime
|
|
12
12
|
|
|
13
13
|
class ScheduleWorkCommand(BaseCommand):
|
|
14
14
|
"""
|
|
15
|
-
|
|
15
|
+
Executes the scheduled tasks defined in the application's scheduler.
|
|
16
|
+
|
|
17
|
+
This command dynamically loads the scheduler module specified in the application's configuration,
|
|
18
|
+
retrieves the `Scheduler` class and its `tasks` method, registers the scheduled tasks with the
|
|
19
|
+
ISchedule service, and starts the scheduler worker. It provides user feedback via the console and
|
|
20
|
+
handles errors by raising CLIOrionisRuntimeError exceptions.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
orionis : IApplication
|
|
25
|
+
The application instance providing configuration and service resolution.
|
|
26
|
+
console : Console
|
|
27
|
+
The Rich console instance used for displaying output to the user.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
bool
|
|
32
|
+
Returns True if the scheduler worker starts successfully. If an error occurs during the process,
|
|
33
|
+
a CLIOrionisRuntimeError is raised.
|
|
34
|
+
|
|
35
|
+
Raises
|
|
36
|
+
------
|
|
37
|
+
CLIOrionisRuntimeError
|
|
38
|
+
If the scheduler module, class, or tasks method cannot be found, or if any unexpected error occurs.
|
|
16
39
|
"""
|
|
17
40
|
|
|
18
41
|
# Indicates whether timestamps will be shown in the command output
|
|
@@ -25,44 +48,66 @@ class ScheduleWorkCommand(BaseCommand):
|
|
|
25
48
|
description: str = "Executes the scheduled tasks defined in the application."
|
|
26
49
|
|
|
27
50
|
async def handle(self, orionis: IApplication, console: Console) -> bool:
|
|
28
|
-
|
|
51
|
+
"""
|
|
52
|
+
Executes the scheduled tasks defined in the application's scheduler.
|
|
53
|
+
|
|
54
|
+
This method dynamically loads the scheduler module specified in the application's configuration,
|
|
55
|
+
retrieves the `Scheduler` class and its `tasks` method, registers the scheduled tasks with the
|
|
56
|
+
ISchedule service, and starts the scheduler worker. It provides user feedback via the console and
|
|
57
|
+
handles errors by raising CLIOrionisRuntimeError exceptions.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
orionis : IApplication
|
|
62
|
+
The application instance providing configuration and service resolution.
|
|
63
|
+
console : Console
|
|
64
|
+
The Rich console instance used for displaying output to the user.
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
bool
|
|
69
|
+
Returns True if the scheduler worker starts successfully. If an error occurs during the process,
|
|
70
|
+
a CLIOrionisRuntimeError is raised.
|
|
71
|
+
|
|
72
|
+
Raises
|
|
73
|
+
------
|
|
74
|
+
CLIOrionisRuntimeError
|
|
75
|
+
If the scheduler module, class, or tasks method cannot be found, or if any unexpected error occurs.
|
|
76
|
+
"""
|
|
29
77
|
try:
|
|
30
|
-
|
|
31
|
-
# Obtener la ruta absoluta del scheduler desde la configuración de la aplicación
|
|
78
|
+
# Get the absolute path to the scheduler module from the application configuration
|
|
32
79
|
scheduler_path = orionis.path('console_scheduler')
|
|
33
80
|
|
|
34
|
-
#
|
|
81
|
+
# Resolve the base path (current working directory)
|
|
35
82
|
base_path = Path(os.getcwd()).resolve()
|
|
36
83
|
scheduler_path = Path(scheduler_path).resolve()
|
|
84
|
+
|
|
85
|
+
# Compute the relative path from the base path to the scheduler module
|
|
37
86
|
rel_path = scheduler_path.relative_to(base_path)
|
|
38
87
|
|
|
39
|
-
#
|
|
88
|
+
# Convert the relative path to a Python module name (dot notation, no .py extension)
|
|
40
89
|
module_name = ".".join(rel_path.with_suffix('').parts)
|
|
41
90
|
|
|
42
|
-
#
|
|
91
|
+
# Dynamically import the scheduler module
|
|
43
92
|
scheduler_module = importlib.import_module(module_name)
|
|
44
93
|
|
|
45
|
-
#
|
|
94
|
+
# Retrieve the Scheduler class from the imported module
|
|
46
95
|
Scheduler = getattr(scheduler_module, "Scheduler", None)
|
|
47
|
-
|
|
48
|
-
# Check if the Scheduler class was found
|
|
49
96
|
if Scheduler is None:
|
|
50
97
|
raise CLIOrionisRuntimeError(f"Scheduler class not found in module {module_name}")
|
|
51
98
|
|
|
52
|
-
#
|
|
99
|
+
# Retrieve the 'tasks' method from the Scheduler class
|
|
53
100
|
task_method = getattr(Scheduler, "tasks", None)
|
|
54
|
-
|
|
55
|
-
# Check if the method exists
|
|
56
101
|
if task_method is None:
|
|
57
102
|
raise CLIOrionisRuntimeError(f"Method 'tasks' not found in Scheduler class in module {module_name}")
|
|
58
103
|
|
|
59
|
-
#
|
|
104
|
+
# Create an instance of the ISchedule service
|
|
60
105
|
schedule_serice: ISchedule = orionis.make(ISchedule)
|
|
61
106
|
|
|
62
|
-
#
|
|
107
|
+
# Register scheduled tasks using the Scheduler's tasks method
|
|
63
108
|
task_method(schedule_serice)
|
|
64
109
|
|
|
65
|
-
# Display a
|
|
110
|
+
# Display a start message for the scheduler worker
|
|
66
111
|
console.line()
|
|
67
112
|
start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
68
113
|
panel_content = Text.assemble(
|
|
@@ -79,10 +124,10 @@ class ScheduleWorkCommand(BaseCommand):
|
|
|
79
124
|
)
|
|
80
125
|
console.line()
|
|
81
126
|
|
|
82
|
-
#
|
|
127
|
+
# Start the scheduler worker asynchronously
|
|
83
128
|
await schedule_serice.start()
|
|
129
|
+
return True
|
|
84
130
|
|
|
85
131
|
except Exception as exc:
|
|
86
|
-
|
|
87
|
-
# Catch any unexpected exceptions and raise as a CLIOrionisRuntimeError
|
|
132
|
+
# Raise any unexpected exceptions as CLIOrionisRuntimeError
|
|
88
133
|
raise CLIOrionisRuntimeError(f"An unexpected error occurred while clearing the cache: {exc}")
|
orionis/console/core/reactor.py
CHANGED
|
@@ -112,6 +112,7 @@ class Reactor(IReactor):
|
|
|
112
112
|
from orionis.console.commands.workflow import WorkFlowGithubCommand
|
|
113
113
|
from orionis.console.commands.cache import CacheClearCommand
|
|
114
114
|
from orionis.console.commands.scheduler_work import ScheduleWorkCommand
|
|
115
|
+
from orionis.console.commands.scheduler_list import ScheduleListCommand
|
|
115
116
|
|
|
116
117
|
# List of core command classes to load (extend this list as more core commands are added)
|
|
117
118
|
core_commands = [
|
|
@@ -121,7 +122,8 @@ class Reactor(IReactor):
|
|
|
121
122
|
PublisherCommand,
|
|
122
123
|
WorkFlowGithubCommand,
|
|
123
124
|
CacheClearCommand,
|
|
124
|
-
ScheduleWorkCommand
|
|
125
|
+
ScheduleWorkCommand,
|
|
126
|
+
ScheduleListCommand
|
|
125
127
|
]
|
|
126
128
|
|
|
127
129
|
# Iterate through the core command classes and register them
|
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"
|
|
@@ -14,7 +14,8 @@ orionis/console/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
14
14
|
orionis/console/commands/cache.py,sha256=8DsYoRzSBLn0P9qkGVItRbo0R6snWBDBg0_Xa7tmVhs,2322
|
|
15
15
|
orionis/console/commands/help.py,sha256=ooPoenP08ArMAWiL89_oUGD9l1Faen2QjLTG90i4zCQ,3187
|
|
16
16
|
orionis/console/commands/publisher.py,sha256=FUg-EUzK7LLXsla10ZUZro8V0Z5S-KjmsaSdRHSSGbA,21381
|
|
17
|
-
orionis/console/commands/
|
|
17
|
+
orionis/console/commands/scheduler_list.py,sha256=SXaD1XJFV1bbyjlDuQhlHz2y1kW-VVCxQxuKJMtQRtA,5956
|
|
18
|
+
orionis/console/commands/scheduler_work.py,sha256=cymbGHaLmwv2WtEenZTtm7iNVfs8gG8_oWXU18Jtzd0,5746
|
|
18
19
|
orionis/console/commands/test.py,sha256=_Tb-I9vabiqhqGeLfRbV5Y1LEVCdhZhBAwoEQZCzQuM,2435
|
|
19
20
|
orionis/console/commands/version.py,sha256=SUuNDJ40f2uq69OQUmPQXJKaa9Bm_iVRDPmBd7zc1Yc,3658
|
|
20
21
|
orionis/console/commands/workflow.py,sha256=NYOmjTSvm2o6AE4h9LSTZMFSYPQreNmEJtronyOxaYk,2451
|
|
@@ -24,7 +25,7 @@ orionis/console/contracts/kernel.py,sha256=mh4LlhEYHh3FuGZZQ0GBhD6ZLa5YQvaNj2r01
|
|
|
24
25
|
orionis/console/contracts/reactor.py,sha256=Xeq7Zrw6WE5MV_XOQfiQEchAFbb6-0TjLpjWOxYW--g,4554
|
|
25
26
|
orionis/console/contracts/schedule.py,sha256=eGjcOH7kgdf0fWDZRfOFUQsIx4E8G38ayX5JwpkpN8E,4977
|
|
26
27
|
orionis/console/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
-
orionis/console/core/reactor.py,sha256=
|
|
28
|
+
orionis/console/core/reactor.py,sha256=XE4VvUPnOSQ_qmkLMYEDfwKaqDZyFxCiVtoSJVqpk_M,30372
|
|
28
29
|
orionis/console/dumper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
30
|
orionis/console/dumper/dump.py,sha256=CATERiQ6XuIrKQsDaWcVxzTtlAJI9qLJX44fQxEX8ws,22443
|
|
30
31
|
orionis/console/dumper/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -199,7 +200,7 @@ orionis/foundation/providers/scheduler_provider.py,sha256=72SoixFog9IOE9Ve9Xcfw6
|
|
|
199
200
|
orionis/foundation/providers/testing_provider.py,sha256=SrJRpdvcblx9WvX7x9Y3zc7OQfiTf7la0HAJrm2ESlE,3725
|
|
200
201
|
orionis/foundation/providers/workers_provider.py,sha256=oa_2NIDH6UxZrtuGkkoo_zEoNIMGgJ46vg5CCgAm7wI,3926
|
|
201
202
|
orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
202
|
-
orionis/metadata/framework.py,sha256=
|
|
203
|
+
orionis/metadata/framework.py,sha256=Omguwj98GlVjFh8nCMjYoLHSqVMJ57Duo0GXurO-QLk,4109
|
|
203
204
|
orionis/metadata/package.py,sha256=k7Yriyp5aUcR-iR8SK2ec_lf0_Cyc-C7JczgXa-I67w,16039
|
|
204
205
|
orionis/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
205
206
|
orionis/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -270,15 +271,15 @@ orionis/services/introspection/modules/contracts/reflection.py,sha256=YLqKg5Ehad
|
|
|
270
271
|
orionis/services/introspection/objects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
271
272
|
orionis/services/introspection/objects/types.py,sha256=vNKWc2b7K-X7B2X8RCimgAWQqbQlVT-aL24nUB8t_yQ,6343
|
|
272
273
|
orionis/services/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
273
|
-
orionis/services/log/log_service.py,sha256=
|
|
274
|
+
orionis/services/log/log_service.py,sha256=y1ysxZ7MuO2NuJXGnPVp1xXsJf6TVkOiMdd-ZvgbwQI,11620
|
|
274
275
|
orionis/services/log/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
275
276
|
orionis/services/log/contracts/log_service.py,sha256=YVWkK5z6-3jyJv6aT8fbp53nQBF8jlD-aHGKqFYPdAM,1692
|
|
276
277
|
orionis/services/log/exceptions/__init__.py,sha256=PPn_LBV3U-0Yi69ZLDQmlkbmlL1iLTleLw-s88Ipg9o,84
|
|
277
278
|
orionis/services/log/exceptions/runtime.py,sha256=LnaK0w0WlgxtZ9Zjn9RYIgp6fbQZmXZ_1fy9dkuA2jQ,468
|
|
278
279
|
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=
|
|
280
|
+
orionis/services/log/handlers/filename.py,sha256=722mnk075vvq02MtpKaDWzLHEUd3sQyhL0a6xd0vLeA,20122
|
|
281
|
+
orionis/services/log/handlers/size_rotating.py,sha256=O0rE2LkS4nfjsOjcOXL0aG1csOuK2RKGeRdBlYJ6qTs,1333
|
|
282
|
+
orionis/services/log/handlers/timed_rotating.py,sha256=XM72DFwKcE0AU4oiCvhy2FXxteZ7HtxpGaxisv504nY,1317
|
|
282
283
|
orionis/services/system/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
283
284
|
orionis/services/system/imports.py,sha256=aSXG9879ur91d6OsqV2DUYWmmwbwFHX8CHb99cPfFcU,7057
|
|
284
285
|
orionis/services/system/workers.py,sha256=EfGxU_w42xRnZ1yslsui3wVG8pfe__V3GYGEIyo8JxQ,3144
|
|
@@ -291,6 +292,7 @@ orionis/support/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
291
292
|
orionis/support/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
292
293
|
orionis/support/entities/base.py,sha256=kVx9YWZjYS6C9MraarU7U12OeT5enBp5XqizrQm4RQs,4801
|
|
293
294
|
orionis/support/facades/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
295
|
+
orionis/support/facades/application.py,sha256=GxB6TzsCSyDEHlvJJr-WVrppJvuolXCcV1vZ0tq_H6E,883
|
|
294
296
|
orionis/support/facades/console.py,sha256=Yhpgv0FpwyOXP4IMgTtDw0_nkcu-J_9nhZRPwJCetCg,875
|
|
295
297
|
orionis/support/facades/dumper.py,sha256=qQPoMbkXExv6UaByoDCyJA-gt5SA1oQtym2TwpihtoI,794
|
|
296
298
|
orionis/support/facades/executor.py,sha256=fRBQ447WpL2T42Ys02k_DJNqukFFk8-bbNFz4GEbRfI,931
|
|
@@ -370,7 +372,7 @@ orionis/test/validators/web_report.py,sha256=n9BfzOZz6aEiNTypXcwuWbFRG0OdHNSmCNu
|
|
|
370
372
|
orionis/test/validators/workers.py,sha256=rWcdRexINNEmGaO7mnc1MKUxkHKxrTsVuHgbnIfJYgc,1206
|
|
371
373
|
orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
372
374
|
orionis/test/view/render.py,sha256=f-zNhtKSg9R5Njqujbg2l2amAs2-mRVESneLIkWOZjU,4082
|
|
373
|
-
orionis-0.
|
|
375
|
+
orionis-0.483.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
|
|
374
376
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
375
377
|
tests/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
376
378
|
tests/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -517,8 +519,8 @@ tests/testing/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
517
519
|
tests/testing/validators/test_testing_validators.py,sha256=WPo5GxTP6xE-Dw3X1vZoqOMpb6HhokjNSbgDsDRDvy4,16588
|
|
518
520
|
tests/testing/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
519
521
|
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.
|
|
522
|
+
orionis-0.483.0.dist-info/METADATA,sha256=3XeBNGAmPP22h8aO4LHXJ9ynNTdYmmYjWQzrzLe5KhA,4801
|
|
523
|
+
orionis-0.483.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
524
|
+
orionis-0.483.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
|
|
525
|
+
orionis-0.483.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
|
|
526
|
+
orionis-0.483.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|