rpa-suite 1.6.2__py3-none-any.whl → 1.6.4__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.
rpa_suite/core/log.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # rpa_suite/core/log.py
2
2
 
3
3
  # imports internal
4
- from rpa_suite.functions._printer import error_print, alert_print, success_print
4
+ from rpa_suite.functions._printer import alert_print, success_print
5
5
 
6
6
  # imports third party
7
7
  from loguru import logger
@@ -11,49 +11,91 @@ from typing import Optional as Op
11
11
  import sys
12
12
  import os
13
13
  import inspect
14
-
14
+ import traceback
15
+
16
+ class LogFiltersError(Exception):
17
+ """Custom exception for LogFilters errors."""
18
+ def __init__(self, message):
19
+ clean_message = message.replace("LogFilters Error:", "").strip()
20
+ super().__init__(f'LogFilters Error: {clean_message}')
21
+
22
+ class LogCustomHandlerError(Exception):
23
+ """Custom exception for LogCustomHandler errors."""
24
+ def __init__(self, message):
25
+ clean_message = message.replace("LogCustomHandler Error:", "").strip()
26
+ super().__init__(f'LogCustomHandler Error: {clean_message}')
27
+
28
+ class LogCustomFormatterError(Exception):
29
+ """Custom exception for LogCustomFormatter errors."""
30
+ def __init__(self, message):
31
+ clean_message = message.replace("LogCustomFormatter Error:", "").strip()
32
+ super().__init__(f'LogCustomFormatter Error: {clean_message}')
33
+
34
+ class LogError(Exception):
35
+ """Custom exception for Log errors."""
36
+ def __init__(self, message):
37
+ clean_message = message.replace("Log Error:", "").strip()
38
+ super().__init__(f'Log Error: {clean_message}')
15
39
 
16
40
  class Filters:
41
+ """
42
+ Filter class for log messages based on word filtering.
43
+ """
17
44
  word_filter: Op[list[str]]
18
45
 
19
- def __call__(self, record):
20
- if self.word_filter and len(self.word_filter) > 0:
21
- for words in self.word_filter:
22
- string_words: list[str] = [str(word) for word in words]
23
- for word in string_words:
24
- if word in record["message"]:
25
- record["message"] = "Log Alterado devido a palavra Filtrada!"
26
- return True
27
- return True
28
-
46
+ def __call__(self, record: dict[str, str]):
47
+ try:
48
+ if self.word_filter and len(self.word_filter) > 0:
49
+ message = record["message"]
50
+ for words in self.word_filter:
51
+ string_words: list[str] = [str(word) for word in words]
52
+ for word in string_words:
53
+ if word in message:
54
+ record["message"] = message.replace(word, "***")
55
+ return True
56
+ return True
57
+ except Exception as e:
58
+ raise LogFiltersError(f"Error trying execute: {self.__call__.__name__}! {str(e)}.")
29
59
 
30
60
  class CustomHandler:
61
+ """
62
+ Custom handler for log messages with formatting capabilities.
63
+ """
31
64
  def __init__(self, formatter):
32
65
  self.formatter = formatter
33
66
 
34
67
  def write(self, message):
35
- frame = inspect.currentframe().f_back.f_back
36
- log_msg = self.formatter.format(message, frame)
37
- sys.stderr.write(log_msg)
38
-
68
+ try:
69
+ frame = inspect.currentframe().f_back.f_back
70
+ log_msg = self.formatter.format(message, frame)
71
+ sys.stderr.write(log_msg)
72
+ except Exception as e:
73
+ raise LogCustomHandlerError(f"Error trying execute: {self.write.__name__}! {str(e)}.")
39
74
 
40
75
  class CustomFormatter:
76
+ """
77
+ Custom formatter for log messages with specific formatting rules.
78
+ """
41
79
  def format(self, record):
42
- # Use the info from record["extra"] which is set in Log._log to the caller's file and line
43
- filename = record["extra"].get("filename", "")
44
- lineno = record["extra"].get("lineno", "")
45
- format_string = "<green>{time:DD.MM.YY.HH:mm}</green> <level>{level: <8}</level> <green>{filename}</green>:<cyan>{lineno: <4}</cyan> <level>{message}</level>\n"
46
- log_msg = format_string.format(
47
- time=record["time"],
48
- level=record["level"].name,
49
- filename=filename,
50
- lineno=lineno,
51
- message=record["message"],
52
- )
53
- return log_msg
54
-
80
+ try:
81
+ filename = record["extra"].get("filename", "")
82
+ lineno = record["extra"].get("lineno", "")
83
+ format_string = "<green>{time:DD.MM.YY.HH:mm}</green> <level>{level: <8}</level> <green>{filename}</green>:<cyan>{lineno: <4}</cyan> <level>{message}</level>\n"
84
+ log_msg = format_string.format(
85
+ time=record["time"],
86
+ level=record["level"].name,
87
+ filename=filename,
88
+ lineno=lineno,
89
+ message=record["message"],
90
+ )
91
+ return log_msg
92
+ except Exception as e:
93
+ raise LogCustomFormatterError(f"Error trying execute: {self.format.__name__}! {str(e)}.")
55
94
 
56
95
  class Log:
96
+ """
97
+ Main logging class providing comprehensive logging functionality.
98
+ """
57
99
  filters: Filters
58
100
  custom_handler: CustomHandler
59
101
  custom_formatter: CustomFormatter
@@ -61,9 +103,16 @@ class Log:
61
103
  name_file_log: str | None = None
62
104
  full_path: str | None = None
63
105
  file_handler = None
106
+ enable_traceback: bool = False # NEW PROPERTY
64
107
 
65
108
  def __init__(self):
66
- self.logger = logger
109
+ """
110
+ Initialize the Log class with default loguru logger.
111
+ """
112
+ try:
113
+ self.logger = logger
114
+ except Exception as e:
115
+ raise LogError(f"Error trying execute: {self.__init__.__name__}! {str(e)}.")
67
116
 
68
117
  def config_logger(
69
118
  self,
@@ -72,10 +121,23 @@ class Log:
72
121
  name_file_log: str = "log",
73
122
  filter_words: list[str] = None,
74
123
  display_message: bool = False,
124
+ enable_traceback: bool = False, # NEW PARAMETER
75
125
  ):
126
+ """
127
+ Configure the logger with specified parameters.
128
+
129
+ Args:
130
+ path_dir: Directory path for log files
131
+ name_log_dir: Name of the log directory
132
+ name_file_log: Name of the log file
133
+ filter_words: List of words to filter from logs
134
+ display_message: Whether to display configuration messages
135
+ enable_traceback: Whether to include traceback in error logs
136
+ """
76
137
  try:
77
138
  self.path_dir = path_dir
78
139
  self.name_file_log = name_file_log
140
+ self.enable_traceback = enable_traceback # CONFIGURE THE PROPERTY
79
141
 
80
142
  if self.path_dir == "default":
81
143
  self.path_dir = os.getcwd()
@@ -86,12 +148,12 @@ class Log:
86
148
  try:
87
149
  os.makedirs(self.full_path, exist_ok=True)
88
150
  if display_message:
89
- success_print(f"Diretório:'{self.full_path}' foi criado com sucesso.")
151
+ success_print(f"Directory:'{self.full_path}' was created successfully.")
90
152
  except FileExistsError:
91
153
  if display_message:
92
- alert_print(f"Diretório:'{self.full_path}' existe.")
154
+ alert_print(f"Directory:'{self.full_path}' already exists.")
93
155
  except PermissionError:
94
- alert_print(f"Permissão negada: não é possível criar o diretório '{self.full_path}'.")
156
+ LogError(f"Permission denied: cannot create directory '{self.full_path}'.")
95
157
 
96
158
  new_filter = None
97
159
  if filter_words is not None:
@@ -115,12 +177,22 @@ class Log:
115
177
  return file_handler
116
178
 
117
179
  except Exception as e:
118
- error_print(f"Houve um erro durante a execução da função: {self.config_logger.__name__}! Error: {str(e)}.")
119
- return None
180
+ raise LogError(f"Error trying execute: {self.config_logger.__name__}! {str(e)}.")
120
181
 
182
+ def _escape_traceback(self, tb_string: str) -> str:
183
+ """
184
+ Escape special characters in traceback to avoid conflicts with Loguru colorizer.
185
+ """
186
+ try:
187
+ # Escape characters that might be interpreted as color tags
188
+ escaped = tb_string.replace('<', '\\<').replace('>', '\\>')
189
+ return escaped
190
+ except Exception as e:
191
+ raise LogError(f"Error trying execute: {self._escape_traceback.__name__}! {str(e)}.")
192
+
121
193
  def _log(self, level: str, msg: str):
122
194
  """
123
- Method to generete logs used from self.
195
+ Method to generate logs used from self.
124
196
  """
125
197
  try:
126
198
  # Find the first frame that's not from this log.py file
@@ -137,42 +209,58 @@ class Log:
137
209
  frame = inspect.currentframe().f_back.f_back
138
210
 
139
211
  full_path_filename = frame.f_code.co_filename
140
-
141
- # Normalize path to use os.sep
142
212
  full_path_filename = os.path.normpath(full_path_filename)
143
-
144
- # Get the last two components: parent folder and filename
145
213
  parent_folder = os.path.basename(os.path.dirname(full_path_filename))
146
214
  file_name = os.path.basename(full_path_filename)
147
215
  display_filename = f"{parent_folder}/{file_name}"
148
-
149
216
  lineno = frame.f_lineno
150
217
 
218
+ # IF TRACEBACK IS ENABLED AND IT'S ERROR LEVEL, ADD TRACEBACK
219
+ if self.enable_traceback and level in ["ERROR", "CRITICAL"]:
220
+ try:
221
+ # Capture current traceback if there's an active exception
222
+ tb_string = traceback.format_exc()
223
+ if tb_string != "NoneType: None\n": # Check if there's real traceback
224
+ # ESCAPE SPECIAL CHARACTERS IN TRACEBACK
225
+ escaped_traceback = self._escape_traceback(tb_string)
226
+ msg = f"{msg}\n{escaped_traceback}"
227
+ except Exception:
228
+ # If can't capture traceback, continue normally
229
+ pass
230
+
151
231
  self.logger.bind(filename=display_filename, lineno=lineno).log(level, msg)
152
232
  except Exception as e:
153
- error_print(f"Erro durante a função de log! Error: {str(e)}")
233
+ raise LogError(f"Error trying execute: {self._log.__name__}! {str(e)}.")
154
234
 
155
235
  def log_start_run_debug(self, msg_start_loggin: str) -> None:
236
+ """
237
+ Log a debug message to start a new run session.
238
+ """
156
239
  try:
157
240
  with open(self.file_handler, "a") as log_file:
158
- log_file.write("\n") # Add a blank line before logging the start message
241
+ log_file.write("\n")
159
242
  self._log("DEBUG", msg_start_loggin)
160
243
  except Exception as e:
161
- error_print(
162
- f"Erro fn: {self.log_start_run_debug.__name__} ao tentar acessar o arquivo de log Confira se foi criado a configuração de log correta com a função config_logger e se a pasta e arquivo estão nos diretório desejado! Error: {str(e)}."
244
+ raise LogError(
245
+ f"Error trying execute: {self.log_start_run_debug.__name__}! see log directory and configuration to config_logger: {str(e)}."
163
246
  )
164
247
 
165
248
  def log_debug(self, msg: str) -> None:
249
+ """Log a debug level message."""
166
250
  self._log("DEBUG", msg)
167
251
 
168
252
  def log_info(self, msg: str) -> None:
253
+ """Log an info level message."""
169
254
  self._log("INFO", msg)
170
255
 
171
256
  def log_warning(self, msg: str) -> None:
257
+ """Log a warning level message."""
172
258
  self._log("WARNING", msg)
173
259
 
174
260
  def log_error(self, msg: str) -> None:
261
+ """Log an error level message."""
175
262
  self._log("ERROR", msg)
176
263
 
177
264
  def log_critical(self, msg: str) -> None:
178
- self._log("CRITICAL", msg)
265
+ """Log a critical level message."""
266
+ self._log("CRITICAL", msg)