orionis 0.407.0__py3-none-any.whl → 0.409.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/container/container.py +11 -9
- orionis/container/enums/lifetimes.py +2 -0
- orionis/container/validators/__init__.py +21 -0
- orionis/metadata/framework.py +1 -1
- orionis/services/log/contracts/log_service.py +56 -4
- orionis/services/log/handlers/filename.py +20 -12
- orionis/services/log/handlers/size_rotating.py +11 -3
- orionis/services/log/handlers/timed_rotating.py +11 -3
- orionis/services/log/log_service.py +122 -72
- orionis/services/paths/contracts/resolver.py +0 -1
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/METADATA +1 -1
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/RECORD +37 -35
- tests/container/context/test_manager.py +15 -5
- tests/container/context/test_scope.py +12 -4
- tests/container/entities/test_binding.py +130 -21
- tests/container/enums/test_lifetimes.py +52 -18
- tests/container/facades/test_facade.py +29 -12
- tests/container/providers/test_providers.py +17 -10
- tests/container/resolver/test_resolver.py +14 -7
- tests/container/test_container.py +226 -71
- tests/container/test_singleton.py +43 -24
- tests/container/test_thread_safety.py +28 -156
- tests/container/validators/test_implements.py +59 -13
- tests/container/validators/test_is_abstract_class.py +73 -25
- tests/container/validators/test_is_callable.py +55 -26
- tests/container/validators/test_is_concrete_class.py +80 -17
- tests/container/validators/test_is_instance.py +67 -22
- tests/container/validators/test_is_not_subclass.py +28 -95
- tests/container/validators/test_is_subclass.py +84 -21
- tests/container/validators/test_is_valid_alias.py +46 -12
- tests/container/validators/test_lifetime.py +45 -14
- tests/services/log/__init__.py +0 -0
- tests/services/log/test_log.py +97 -0
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/WHEEL +0 -0
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/top_level.txt +0 -0
- {orionis-0.407.0.dist-info → orionis-0.409.0.dist-info}/zip-safe +0 -0
orionis/container/container.py
CHANGED
|
@@ -6,15 +6,17 @@ from orionis.container.entities.binding import Binding
|
|
|
6
6
|
from orionis.container.enums.lifetimes import Lifetime
|
|
7
7
|
from orionis.container.exceptions import OrionisContainerException
|
|
8
8
|
from orionis.container.resolver.resolver import Resolver
|
|
9
|
-
from orionis.container.validators
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
from orionis.container.validators import (
|
|
10
|
+
ImplementsAbstractMethods,
|
|
11
|
+
IsAbstractClass,
|
|
12
|
+
IsCallable,
|
|
13
|
+
IsConcreteClass,
|
|
14
|
+
IsInstance,
|
|
15
|
+
IsNotSubclass,
|
|
16
|
+
IsSubclass,
|
|
17
|
+
IsValidAlias,
|
|
18
|
+
LifetimeValidator
|
|
19
|
+
)
|
|
18
20
|
from orionis.services.introspection.abstract.reflection import ReflectionAbstract
|
|
19
21
|
from orionis.services.introspection.callables.reflection import ReflectionCallable
|
|
20
22
|
|
|
@@ -23,7 +23,9 @@ class Lifetime(Enum):
|
|
|
23
23
|
|
|
24
24
|
# A new instance is provided every time the dependency is requested.
|
|
25
25
|
TRANSIENT = auto()
|
|
26
|
+
|
|
26
27
|
# A single shared instance is provided for the entire application lifetime.
|
|
27
28
|
SINGLETON = auto()
|
|
29
|
+
|
|
28
30
|
# An instance is provided per scope (e.g., per request or session).
|
|
29
31
|
SCOPED = auto()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .implements import ImplementsAbstractMethods
|
|
2
|
+
from .is_abstract_class import IsAbstractClass
|
|
3
|
+
from .is_concrete_class import IsConcreteClass
|
|
4
|
+
from .is_instance import IsInstance
|
|
5
|
+
from .is_callable import IsCallable
|
|
6
|
+
from .is_subclass import IsSubclass
|
|
7
|
+
from .is_not_subclass import IsNotSubclass
|
|
8
|
+
from .is_valid_alias import IsValidAlias
|
|
9
|
+
from .lifetime import LifetimeValidator
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"ImplementsAbstractMethods",
|
|
13
|
+
"IsAbstractClass",
|
|
14
|
+
"IsConcreteClass",
|
|
15
|
+
"IsInstance",
|
|
16
|
+
"IsCallable",
|
|
17
|
+
"IsSubclass",
|
|
18
|
+
"IsNotSubclass",
|
|
19
|
+
"IsValidAlias",
|
|
20
|
+
"LifetimeValidator",
|
|
21
|
+
]
|
orionis/metadata/framework.py
CHANGED
|
@@ -4,20 +4,72 @@ class ILoggerService(ABC):
|
|
|
4
4
|
|
|
5
5
|
@abstractmethod
|
|
6
6
|
def info(self, message: str) -> None:
|
|
7
|
-
"""
|
|
7
|
+
"""
|
|
8
|
+
Logs an informational message.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
message : str
|
|
13
|
+
The message to be logged as informational.
|
|
14
|
+
|
|
15
|
+
Returns
|
|
16
|
+
-------
|
|
17
|
+
None
|
|
18
|
+
This method does not return any value.
|
|
19
|
+
"""
|
|
20
|
+
# To be implemented by subclasses
|
|
8
21
|
pass
|
|
9
22
|
|
|
10
23
|
@abstractmethod
|
|
11
24
|
def error(self, message: str) -> None:
|
|
12
|
-
"""
|
|
25
|
+
"""
|
|
26
|
+
Logs an error message.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
message : str
|
|
31
|
+
The message to be logged as an error.
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
None
|
|
36
|
+
This method does not return any value.
|
|
37
|
+
"""
|
|
38
|
+
# To be implemented by subclasses
|
|
13
39
|
pass
|
|
14
40
|
|
|
15
41
|
@abstractmethod
|
|
16
42
|
def warning(self, message: str) -> None:
|
|
17
|
-
"""
|
|
43
|
+
"""
|
|
44
|
+
Logs a warning message.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
message : str
|
|
49
|
+
The message to be logged as a warning.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
None
|
|
54
|
+
This method does not return any value.
|
|
55
|
+
"""
|
|
56
|
+
# To be implemented by subclasses
|
|
18
57
|
pass
|
|
19
58
|
|
|
20
59
|
@abstractmethod
|
|
21
60
|
def debug(self, message: str) -> None:
|
|
22
|
-
"""
|
|
61
|
+
"""
|
|
62
|
+
Logs a debug message.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
message : str
|
|
67
|
+
The message to be logged for debugging purposes.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
None
|
|
72
|
+
This method does not return any value.
|
|
73
|
+
"""
|
|
74
|
+
# To be implemented by subclasses
|
|
23
75
|
pass
|
|
@@ -12,19 +12,27 @@ class FileNameLogger:
|
|
|
12
12
|
----------
|
|
13
13
|
path : str
|
|
14
14
|
The original file path for the log file.
|
|
15
|
-
"""
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
Raises
|
|
17
|
+
------
|
|
18
|
+
ValueError
|
|
19
|
+
If the provided path is not a non-empty string.
|
|
20
|
+
"""
|
|
21
|
+
# Validate that the path is a non-empty string
|
|
18
22
|
if not isinstance(path, str) or not path:
|
|
19
23
|
raise ValueError("The 'path' parameter must be a non-empty string.")
|
|
20
24
|
|
|
21
|
-
#
|
|
25
|
+
# Store the stripped path as a private instance variable
|
|
22
26
|
self.__path = path.strip()
|
|
23
27
|
|
|
24
28
|
def generate(self) -> str:
|
|
25
29
|
"""
|
|
26
30
|
Generate a new log file path with a timestamp prefix.
|
|
27
31
|
|
|
32
|
+
The method constructs a new file path by prefixing the original file name
|
|
33
|
+
with a timestamp in the format 'YYYYMMDD_HHMMSS'. It also ensures that the
|
|
34
|
+
directory for the log file exists, creating it if necessary.
|
|
35
|
+
|
|
28
36
|
Returns
|
|
29
37
|
-------
|
|
30
38
|
str
|
|
@@ -32,10 +40,10 @@ class FileNameLogger:
|
|
|
32
40
|
|
|
33
41
|
Notes
|
|
34
42
|
-----
|
|
35
|
-
The
|
|
43
|
+
- The timestamp is generated using the current date and time.
|
|
44
|
+
- The directory for the log file is created if it does not exist.
|
|
36
45
|
"""
|
|
37
|
-
|
|
38
|
-
# Split the original path to extract the base name and extension
|
|
46
|
+
# Split the original path into components based on the separator
|
|
39
47
|
if '/' in self.__path:
|
|
40
48
|
parts = self.__path.split('/')
|
|
41
49
|
elif '\\' in self.__path:
|
|
@@ -43,22 +51,22 @@ class FileNameLogger:
|
|
|
43
51
|
else:
|
|
44
52
|
parts = self.__path.split(os.sep)
|
|
45
53
|
|
|
46
|
-
#
|
|
54
|
+
# Extract the base file name and its extension
|
|
47
55
|
filename, ext = os.path.splitext(parts[-1])
|
|
48
56
|
|
|
49
|
-
#
|
|
57
|
+
# Reconstruct the directory path (excluding the file name)
|
|
50
58
|
path = os.path.join(*parts[:-1]) if len(parts) > 1 else ''
|
|
51
59
|
|
|
52
|
-
#
|
|
60
|
+
# Generate a timestamp prefix for the file name
|
|
53
61
|
prefix = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
54
62
|
|
|
55
|
-
#
|
|
63
|
+
# Build the full file path with the timestamped file name
|
|
56
64
|
full_path = os.path.join(path, f"{prefix}_{filename}{ext}")
|
|
57
65
|
|
|
58
|
-
# Ensure the log directory exists
|
|
66
|
+
# Ensure the log directory exists; create it if it does not
|
|
59
67
|
log_dir = Path(full_path).parent
|
|
60
68
|
if not log_dir.exists():
|
|
61
69
|
log_dir.mkdir(parents=True, exist_ok=True)
|
|
62
70
|
|
|
63
|
-
# Return the full path
|
|
71
|
+
# Return the full path to the timestamped log file
|
|
64
72
|
return full_path
|
|
@@ -5,17 +5,25 @@ class PrefixedSizeRotatingFileHandler(RotatingFileHandler):
|
|
|
5
5
|
|
|
6
6
|
def rotation_filename(self, default_name) -> str:
|
|
7
7
|
"""
|
|
8
|
-
|
|
8
|
+
Generates a rotated log filename by prefixing the original filename with a timestamp.
|
|
9
9
|
|
|
10
10
|
Parameters
|
|
11
11
|
----------
|
|
12
12
|
default_name : str
|
|
13
|
-
The original file path to
|
|
13
|
+
The original file path that is subject to rotation.
|
|
14
14
|
|
|
15
15
|
Returns
|
|
16
16
|
-------
|
|
17
17
|
str
|
|
18
|
-
The new file path
|
|
18
|
+
The new file path as a string, where the base name is prefixed with a timestamp
|
|
19
|
+
in the format 'YYYYMMDD_HHMMSS'. This ensures uniqueness and chronological ordering
|
|
20
|
+
of rotated log files.
|
|
21
|
+
|
|
22
|
+
Notes
|
|
23
|
+
-----
|
|
24
|
+
This method utilizes the FileNameLogger class to construct the prefixed filename.
|
|
25
|
+
The timestamp prefix helps in identifying the creation time of each rotated log file.
|
|
19
26
|
"""
|
|
20
27
|
|
|
28
|
+
# Generate the new filename using FileNameLogger, which adds a timestamp prefix.
|
|
21
29
|
return FileNameLogger(default_name).generate()
|
|
@@ -5,17 +5,25 @@ class PrefixedTimedRotatingFileHandler(TimedRotatingFileHandler):
|
|
|
5
5
|
|
|
6
6
|
def rotation_filename(self, default_name) -> str:
|
|
7
7
|
"""
|
|
8
|
-
|
|
8
|
+
Generates a rotated log filename by prefixing the original filename with a timestamp.
|
|
9
9
|
|
|
10
10
|
Parameters
|
|
11
11
|
----------
|
|
12
12
|
default_name : str
|
|
13
|
-
The original file path to
|
|
13
|
+
The original file path that is subject to rotation.
|
|
14
14
|
|
|
15
15
|
Returns
|
|
16
16
|
-------
|
|
17
17
|
str
|
|
18
|
-
The new file path
|
|
18
|
+
The new file path as a string, where the base name is prefixed with a timestamp
|
|
19
|
+
in the format 'YYYYMMDD_HHMMSS'. This ensures each rotated log file is uniquely
|
|
20
|
+
identified by its creation time.
|
|
21
|
+
|
|
22
|
+
Notes
|
|
23
|
+
-----
|
|
24
|
+
This method utilizes the FileNameLogger class to construct the new filename.
|
|
25
|
+
The timestamp prefix helps in organizing and distinguishing rotated log files.
|
|
19
26
|
"""
|
|
20
27
|
|
|
28
|
+
# Use FileNameLogger to generate a new filename with a timestamp prefix
|
|
21
29
|
return FileNameLogger(default_name).generate()
|
|
@@ -14,33 +14,46 @@ class LoggerService(ILoggerService):
|
|
|
14
14
|
**kwargs
|
|
15
15
|
):
|
|
16
16
|
"""
|
|
17
|
-
|
|
17
|
+
Initializes the LoggerService instance with the provided logging configuration.
|
|
18
|
+
|
|
19
|
+
This constructor sets up the logger configuration using either a `Logging` object,
|
|
20
|
+
a configuration dictionary, or keyword arguments. It validates the input and
|
|
21
|
+
ensures that the configuration is properly instantiated before initializing
|
|
22
|
+
the logger. If no configuration is provided, it attempts to create one using
|
|
23
|
+
the supplied keyword arguments.
|
|
18
24
|
|
|
19
25
|
Parameters
|
|
20
26
|
----------
|
|
21
27
|
config : Logging or dict, optional
|
|
22
|
-
The logging configuration. Can be an instance of the Logging class,
|
|
23
|
-
a dictionary
|
|
24
|
-
is initialized using kwargs
|
|
28
|
+
The logging configuration. Can be an instance of the `Logging` class,
|
|
29
|
+
a dictionary containing configuration parameters, or None. If None,
|
|
30
|
+
configuration is initialized using `kwargs`.
|
|
25
31
|
**kwargs
|
|
26
|
-
Additional keyword arguments used to initialize the Logging configuration
|
|
27
|
-
if config is None.
|
|
32
|
+
Additional keyword arguments used to initialize the `Logging` configuration
|
|
33
|
+
if `config` is None.
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
None
|
|
38
|
+
This method does not return any value. It sets up the logger service instance.
|
|
28
39
|
|
|
29
40
|
Raises
|
|
30
41
|
------
|
|
31
42
|
LoggerRuntimeError
|
|
32
|
-
If the logger configuration cannot be initialized from the provided arguments
|
|
43
|
+
If the logger configuration cannot be initialized from the provided arguments,
|
|
44
|
+
such as invalid types or missing required parameters.
|
|
33
45
|
"""
|
|
34
46
|
|
|
35
|
-
#
|
|
47
|
+
# Initialize private attributes for logger and configuration
|
|
36
48
|
self.__logger = None
|
|
37
49
|
self.__config = None
|
|
38
50
|
|
|
39
|
-
#
|
|
51
|
+
# If no configuration is provided, attempt to create one using kwargs
|
|
40
52
|
if config is None:
|
|
41
53
|
try:
|
|
42
54
|
self.__config = Logging(**kwargs)
|
|
43
55
|
except Exception as e:
|
|
56
|
+
# Raise a runtime error if configuration initialization fails
|
|
44
57
|
raise LoggerRuntimeError(
|
|
45
58
|
f"Error initializing logger configuration: {e}. "
|
|
46
59
|
"Please check the provided parameters. "
|
|
@@ -49,54 +62,64 @@ class LoggerService(ILoggerService):
|
|
|
49
62
|
f"Expected: {Logging.__module__}.{Logging.__name__} or dict."
|
|
50
63
|
)
|
|
51
64
|
|
|
52
|
-
# If config is a dictionary, convert it to Logging
|
|
65
|
+
# If config is a dictionary, convert it to a Logging instance
|
|
53
66
|
elif isinstance(config, dict):
|
|
54
67
|
self.__config = Logging(**config)
|
|
55
68
|
|
|
56
|
-
# If config is already
|
|
69
|
+
# If config is already a Logging instance, use it directly
|
|
57
70
|
elif isinstance(config, Logging):
|
|
58
71
|
self.__config = config
|
|
59
72
|
|
|
60
|
-
# Initialize
|
|
73
|
+
# Initialize the logger using the validated configuration
|
|
61
74
|
self.__initLogger()
|
|
62
75
|
|
|
63
76
|
def __initLogger(self):
|
|
64
77
|
"""
|
|
65
|
-
|
|
78
|
+
Initializes and configures the logger instance based on the provided settings.
|
|
79
|
+
|
|
80
|
+
This method sets up the logger to write logs to a file, using different handlers
|
|
81
|
+
depending on the logging channel type (e.g., stack, hourly, daily, weekly, monthly, chunked).
|
|
82
|
+
It ensures the log format includes a timestamp, log level, and message. If the specified
|
|
83
|
+
log directory does not exist, it is created automatically. The logger's level and retention
|
|
84
|
+
policies are determined by the configuration.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
None
|
|
66
89
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
None
|
|
93
|
+
This method does not return any value. It sets up the logger instance as an attribute.
|
|
70
94
|
|
|
71
95
|
Raises
|
|
72
96
|
------
|
|
73
97
|
LoggerRuntimeError
|
|
74
|
-
If the logger cannot be initialized due to an error.
|
|
98
|
+
If the logger cannot be initialized due to an error in configuration or handler setup.
|
|
75
99
|
"""
|
|
76
100
|
import logging
|
|
77
101
|
from datetime import datetime
|
|
78
102
|
|
|
79
103
|
try:
|
|
80
|
-
|
|
81
|
-
# List to hold the handlers
|
|
104
|
+
# List to hold the logging handlers
|
|
82
105
|
handlers = []
|
|
83
106
|
|
|
84
|
-
#
|
|
107
|
+
# Retrieve the default logging channel from configuration
|
|
85
108
|
channel: str = self.__config.default
|
|
86
109
|
|
|
87
|
-
# Get the configuration for the
|
|
110
|
+
# Get the configuration object for the selected channel
|
|
88
111
|
config_channels = getattr(self.__config.channels, channel)
|
|
89
112
|
|
|
90
|
-
#
|
|
113
|
+
# Generate the log file path using the FileNameLogger utility
|
|
91
114
|
path: str = FileNameLogger(getattr(config_channels, 'path')).generate()
|
|
92
115
|
|
|
93
|
-
#
|
|
116
|
+
# Determine the logging level (default to DEBUG if not specified)
|
|
94
117
|
level: Level | int = getattr(config_channels, 'level', 10)
|
|
95
118
|
level = level if isinstance(level, int) else level.value
|
|
96
119
|
|
|
97
|
-
#
|
|
120
|
+
# Select and configure the appropriate handler based on the channel type
|
|
98
121
|
if channel == "stack":
|
|
99
|
-
|
|
122
|
+
# Simple file handler for stack channel
|
|
100
123
|
handlers = [
|
|
101
124
|
logging.FileHandler(
|
|
102
125
|
filename=path,
|
|
@@ -105,89 +128,92 @@ class LoggerService(ILoggerService):
|
|
|
105
128
|
]
|
|
106
129
|
|
|
107
130
|
elif channel == "hourly":
|
|
108
|
-
|
|
131
|
+
# Rotating file handler for hourly logs
|
|
109
132
|
handlers = [
|
|
110
133
|
PrefixedTimedRotatingFileHandler(
|
|
111
|
-
filename
|
|
112
|
-
when
|
|
113
|
-
interval
|
|
114
|
-
backupCount
|
|
115
|
-
encoding
|
|
116
|
-
utc
|
|
134
|
+
filename=path,
|
|
135
|
+
when="h",
|
|
136
|
+
interval=1,
|
|
137
|
+
backupCount=getattr(config_channels, 'retention_hours', 24),
|
|
138
|
+
encoding="utf-8",
|
|
139
|
+
utc=False
|
|
117
140
|
)
|
|
118
141
|
]
|
|
119
142
|
|
|
120
143
|
elif channel == "daily":
|
|
121
|
-
|
|
144
|
+
# Rotating file handler for daily logs
|
|
122
145
|
handlers = [
|
|
123
146
|
PrefixedTimedRotatingFileHandler(
|
|
124
|
-
filename
|
|
125
|
-
when
|
|
126
|
-
interval
|
|
127
|
-
backupCount
|
|
128
|
-
encoding
|
|
129
|
-
atTime
|
|
130
|
-
utc
|
|
147
|
+
filename=path,
|
|
148
|
+
when="d",
|
|
149
|
+
interval=1,
|
|
150
|
+
backupCount=getattr(config_channels, 'retention_days', 7),
|
|
151
|
+
encoding="utf-8",
|
|
152
|
+
atTime=datetime.strptime(getattr(config_channels, 'at', "00:00"), "%H:%M").time(),
|
|
153
|
+
utc=False
|
|
131
154
|
)
|
|
132
155
|
]
|
|
133
156
|
|
|
134
157
|
elif channel == "weekly":
|
|
135
|
-
|
|
158
|
+
# Rotating file handler for weekly logs
|
|
136
159
|
handlers = [
|
|
137
160
|
PrefixedTimedRotatingFileHandler(
|
|
138
|
-
filename
|
|
139
|
-
when
|
|
140
|
-
interval
|
|
141
|
-
backupCount
|
|
142
|
-
encoding
|
|
143
|
-
utc
|
|
161
|
+
filename=path,
|
|
162
|
+
when="w0",
|
|
163
|
+
interval=1,
|
|
164
|
+
backupCount=getattr(config_channels, 'retention_weeks', 4),
|
|
165
|
+
encoding="utf-8",
|
|
166
|
+
utc=False
|
|
144
167
|
)
|
|
145
168
|
]
|
|
146
169
|
|
|
147
170
|
elif channel == "monthly":
|
|
148
|
-
|
|
171
|
+
# Rotating file handler for monthly logs
|
|
149
172
|
handlers = [
|
|
150
173
|
PrefixedTimedRotatingFileHandler(
|
|
151
|
-
filename
|
|
152
|
-
when
|
|
153
|
-
interval
|
|
154
|
-
backupCount
|
|
155
|
-
encoding
|
|
156
|
-
utc
|
|
174
|
+
filename=path,
|
|
175
|
+
when="midnight",
|
|
176
|
+
interval=30,
|
|
177
|
+
backupCount=getattr(config_channels, 'retention_months', 4),
|
|
178
|
+
encoding="utf-8",
|
|
179
|
+
utc=False
|
|
157
180
|
)
|
|
158
181
|
]
|
|
159
182
|
|
|
160
183
|
elif channel == "chunked":
|
|
161
|
-
|
|
184
|
+
# Size-based rotating file handler for chunked logs
|
|
162
185
|
handlers = [
|
|
163
186
|
PrefixedSizeRotatingFileHandler(
|
|
164
|
-
filename
|
|
165
|
-
maxBytes
|
|
166
|
-
backupCount
|
|
167
|
-
encoding
|
|
187
|
+
filename=path,
|
|
188
|
+
maxBytes=getattr(config_channels, 'mb_size', 10) * 1024 * 1024,
|
|
189
|
+
backupCount=getattr(config_channels, 'files', 5),
|
|
190
|
+
encoding="utf-8"
|
|
168
191
|
)
|
|
169
192
|
]
|
|
170
193
|
|
|
171
|
-
# Configure the logger
|
|
194
|
+
# Configure the logger with the selected handlers and formatting
|
|
172
195
|
logging.basicConfig(
|
|
173
|
-
level
|
|
174
|
-
format
|
|
175
|
-
datefmt
|
|
176
|
-
encoding
|
|
177
|
-
handlers
|
|
196
|
+
level=level,
|
|
197
|
+
format="%(asctime)s [%(levelname)s] - %(message)s",
|
|
198
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
199
|
+
encoding="utf-8",
|
|
200
|
+
handlers=handlers
|
|
178
201
|
)
|
|
179
202
|
|
|
180
|
-
#
|
|
203
|
+
# Store the logger instance as a private attribute
|
|
181
204
|
self.__logger = logging.getLogger(__name__)
|
|
182
205
|
|
|
183
206
|
except Exception as e:
|
|
184
|
-
|
|
185
207
|
# Raise a runtime error if logger initialization fails
|
|
186
208
|
raise LoggerRuntimeError(f"Failed to initialize logger: {e}")
|
|
187
209
|
|
|
188
210
|
def info(self, message: str) -> None:
|
|
189
211
|
"""
|
|
190
|
-
|
|
212
|
+
Logs an informational message to the configured logger.
|
|
213
|
+
|
|
214
|
+
This method records informational messages that highlight the progress or state
|
|
215
|
+
of the application at a coarse-grained level. The message is stripped of leading
|
|
216
|
+
and trailing whitespace before being logged.
|
|
191
217
|
|
|
192
218
|
Parameters
|
|
193
219
|
----------
|
|
@@ -197,12 +223,19 @@ class LoggerService(ILoggerService):
|
|
|
197
223
|
Returns
|
|
198
224
|
-------
|
|
199
225
|
None
|
|
226
|
+
This method does not return any value.
|
|
200
227
|
"""
|
|
228
|
+
|
|
229
|
+
# Log the informational message after stripping whitespace
|
|
201
230
|
self.__logger.info(message.strip())
|
|
202
231
|
|
|
203
232
|
def error(self, message: str) -> None:
|
|
204
233
|
"""
|
|
205
|
-
|
|
234
|
+
Logs an error-level message to the configured logger.
|
|
235
|
+
|
|
236
|
+
This method records error messages that indicate serious issues or failures
|
|
237
|
+
within the application. The message is stripped of leading and trailing
|
|
238
|
+
whitespace before being logged.
|
|
206
239
|
|
|
207
240
|
Parameters
|
|
208
241
|
----------
|
|
@@ -212,12 +245,19 @@ class LoggerService(ILoggerService):
|
|
|
212
245
|
Returns
|
|
213
246
|
-------
|
|
214
247
|
None
|
|
248
|
+
This method does not return any value.
|
|
215
249
|
"""
|
|
250
|
+
|
|
251
|
+
# Log the error message after stripping whitespace
|
|
216
252
|
self.__logger.error(message.strip())
|
|
217
253
|
|
|
218
254
|
def warning(self, message: str) -> None:
|
|
219
255
|
"""
|
|
220
|
-
Log a warning message.
|
|
256
|
+
Log a warning-level message to the configured logger.
|
|
257
|
+
|
|
258
|
+
This method records warning messages that indicate potential issues or
|
|
259
|
+
unexpected situations in the application. The message is stripped of
|
|
260
|
+
leading and trailing whitespace before being logged.
|
|
221
261
|
|
|
222
262
|
Parameters
|
|
223
263
|
----------
|
|
@@ -227,20 +267,30 @@ class LoggerService(ILoggerService):
|
|
|
227
267
|
Returns
|
|
228
268
|
-------
|
|
229
269
|
None
|
|
270
|
+
This method does not return any value.
|
|
230
271
|
"""
|
|
272
|
+
|
|
273
|
+
# Log the warning message after stripping whitespace
|
|
231
274
|
self.__logger.warning(message.strip())
|
|
232
275
|
|
|
233
276
|
def debug(self, message: str) -> None:
|
|
234
277
|
"""
|
|
235
|
-
|
|
278
|
+
Logs a debug-level message to the configured logger.
|
|
279
|
+
|
|
280
|
+
This method records diagnostic messages that are useful for debugging
|
|
281
|
+
and development purposes. The message is stripped of leading and trailing
|
|
282
|
+
whitespace before being logged.
|
|
236
283
|
|
|
237
284
|
Parameters
|
|
238
285
|
----------
|
|
239
286
|
message : str
|
|
240
|
-
The debug message to
|
|
287
|
+
The debug message to be logged.
|
|
241
288
|
|
|
242
289
|
Returns
|
|
243
290
|
-------
|
|
244
291
|
None
|
|
292
|
+
This method does not return any value.
|
|
245
293
|
"""
|
|
294
|
+
|
|
295
|
+
# Log the debug message after stripping whitespace
|
|
246
296
|
self.__logger.debug(message.strip())
|