From af286561382ae40104a27b58f57d24f90644ecc1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 6 Feb 2024 19:33:08 +0100 Subject: [PATCH 01/14] Add rich as loghandler instead of stdout --- freqtrade/loggers/__init__.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/freqtrade/loggers/__init__.py b/freqtrade/loggers/__init__.py index 7e18d3cba..5753ad825 100644 --- a/freqtrade/loggers/__init__.py +++ b/freqtrade/loggers/__init__.py @@ -3,11 +3,13 @@ from logging import Formatter from logging.handlers import RotatingFileHandler, SysLogHandler from pathlib import Path +from rich.console import Console +from rich.logging import RichHandler + from freqtrade.constants import Config from freqtrade.exceptions import OperationalException from freqtrade.loggers.buffering_handler import FTBufferingHandler from freqtrade.loggers.set_log_levels import set_loggers -from freqtrade.loggers.std_err_stream_handler import FTStdErrStreamHandler logger = logging.getLogger(__name__) @@ -17,6 +19,8 @@ LOGFORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" bufferHandler = FTBufferingHandler(1000) bufferHandler.setFormatter(Formatter(LOGFORMAT)) +error_console = Console(stderr=True) + def get_existing_handlers(handlertype): """ @@ -33,8 +37,13 @@ def setup_logging_pre() -> None: logging handlers after the real initialization, because we don't know which ones the user desires beforehand. """ + rh = RichHandler(console=error_console) + rh.setFormatter(Formatter("%(message)s")) logging.basicConfig( - level=logging.INFO, format=LOGFORMAT, handlers=[FTStdErrStreamHandler(), bufferHandler] + level=logging.INFO, + format=LOGFORMAT, + # handlers=[FTStdErrStreamHandler(), bufferHandler] + handlers=[rh, bufferHandler], ) From 3e5ab8549f628e90d0662986db2cefea3175097b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 10:11:00 +0100 Subject: [PATCH 02/14] feat: add ftRichColorHandler --- freqtrade/loggers/__init__.py | 14 ++++++++--- freqtrade/loggers/ft_rich_handler.py | 33 +++++++++++++++++++++++++ freqtrade/optimize/hyperopt/hyperopt.py | 10 ++++---- 3 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 freqtrade/loggers/ft_rich_handler.py diff --git a/freqtrade/loggers/__init__.py b/freqtrade/loggers/__init__.py index 5753ad825..bb29f2403 100644 --- a/freqtrade/loggers/__init__.py +++ b/freqtrade/loggers/__init__.py @@ -4,14 +4,17 @@ from logging.handlers import RotatingFileHandler, SysLogHandler from pathlib import Path from rich.console import Console -from rich.logging import RichHandler from freqtrade.constants import Config from freqtrade.exceptions import OperationalException from freqtrade.loggers.buffering_handler import FTBufferingHandler +from freqtrade.loggers.ft_rich_handler import FtRichHandler from freqtrade.loggers.set_log_levels import set_loggers +# from freqtrade.loggers.std_err_stream_handler import FTStdErrStreamHandler + + logger = logging.getLogger(__name__) LOGFORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" @@ -37,13 +40,16 @@ def setup_logging_pre() -> None: logging handlers after the real initialization, because we don't know which ones the user desires beforehand. """ - rh = RichHandler(console=error_console) + rh = FtRichHandler(console=error_console) rh.setFormatter(Formatter("%(message)s")) logging.basicConfig( level=logging.INFO, format=LOGFORMAT, - # handlers=[FTStdErrStreamHandler(), bufferHandler] - handlers=[rh, bufferHandler], + handlers=[ + # FTStdErrStreamHandler(), + rh, + bufferHandler, + ], ) diff --git a/freqtrade/loggers/ft_rich_handler.py b/freqtrade/loggers/ft_rich_handler.py new file mode 100644 index 000000000..184273b5c --- /dev/null +++ b/freqtrade/loggers/ft_rich_handler.py @@ -0,0 +1,33 @@ +from datetime import datetime +from logging import Handler +from typing import Any + +from rich.text import Text + + +class FtRichHandler(Handler): + def __init__(self, console, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self._console = console + + def emit(self, record): + try: + msg = self.format(record) + # Format log message + log_time = Text( + datetime.fromtimestamp(record.created).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3], + style="gray46", + ) + name = Text(record.name) + log_level = Text(record.levelname, style=f"logging.level.{record.levelname.lower()}") + gray_sep = Text(" - ", style="gray46") + + self._console.print( + Text() + log_time + gray_sep + name + gray_sep + log_level + gray_sep + msg + ) + + self.flush() + except RecursionError: + raise + except Exception: + self.handleError(record) diff --git a/freqtrade/optimize/hyperopt/hyperopt.py b/freqtrade/optimize/hyperopt/hyperopt.py index 253691d4a..ae493d95f 100644 --- a/freqtrade/optimize/hyperopt/hyperopt.py +++ b/freqtrade/optimize/hyperopt/hyperopt.py @@ -16,11 +16,11 @@ from typing import Any import rapidjson from joblib import Parallel, cpu_count, delayed, wrap_non_picklable_objects from joblib.externals import cloudpickle -from rich.console import Console from freqtrade.constants import FTHYPT_FILEVERSION, LAST_BT_RESULT_FN, Config from freqtrade.enums import HyperoptState from freqtrade.exceptions import OperationalException +from freqtrade.loggers import error_console from freqtrade.misc import file_dump_json, plural from freqtrade.optimize.hyperopt.hyperopt_logger import logging_mp_handle, logging_mp_setup from freqtrade.optimize.hyperopt.hyperopt_optimizer import HyperOptimizer @@ -281,13 +281,13 @@ class Hyperopt: with Parallel(n_jobs=config_jobs) as parallel: jobs = parallel._effective_n_jobs() logger.info(f"Effective number of parallel workers used: {jobs}") - console = Console( - color_system="auto" if self.print_colorized else None, - ) + # console = Console( + # color_system="auto" if self.print_colorized else None, + # ) # Define progressbar with get_progress_tracker( - console=console, + console=error_console, cust_callables=[self._hyper_out], ) as pbar: task = pbar.add_task("Epochs", total=self.total_epochs) From 59f3d88c5827928ad058b727c954956675429184 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 10:39:31 +0100 Subject: [PATCH 03/14] feat: allow disabling color output --- freqtrade/loggers/__init__.py | 5 ++++- freqtrade/loggers/ft_rich_handler.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/freqtrade/loggers/__init__.py b/freqtrade/loggers/__init__.py index bb29f2403..6e560a9ea 100644 --- a/freqtrade/loggers/__init__.py +++ b/freqtrade/loggers/__init__.py @@ -22,7 +22,7 @@ LOGFORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" bufferHandler = FTBufferingHandler(1000) bufferHandler.setFormatter(Formatter(LOGFORMAT)) -error_console = Console(stderr=True) +error_console = Console(stderr=True, color_system=None) def get_existing_handlers(handlertype): @@ -60,6 +60,9 @@ def setup_logging(config: Config) -> None: # Log level verbosity = config["verbosity"] logging.root.addHandler(bufferHandler) + if config.get("print_colorized", True): + logger.info("Enabling colorized output") + error_console._color_system = "auto" logfile = config.get("logfile") diff --git a/freqtrade/loggers/ft_rich_handler.py b/freqtrade/loggers/ft_rich_handler.py index 184273b5c..32545bdc8 100644 --- a/freqtrade/loggers/ft_rich_handler.py +++ b/freqtrade/loggers/ft_rich_handler.py @@ -16,9 +16,9 @@ class FtRichHandler(Handler): # Format log message log_time = Text( datetime.fromtimestamp(record.created).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3], - style="gray46", + style="gray78", ) - name = Text(record.name) + name = Text(record.name, style="violet") log_level = Text(record.levelname, style=f"logging.level.{record.levelname.lower()}") gray_sep = Text(" - ", style="gray46") From 44d9cb85a0f4a6c6fee2f02f969f85734bbba7eb Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 10:45:22 +0100 Subject: [PATCH 04/14] chore: don't change time color for improved readability --- freqtrade/loggers/ft_rich_handler.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/loggers/ft_rich_handler.py b/freqtrade/loggers/ft_rich_handler.py index 32545bdc8..a289d5435 100644 --- a/freqtrade/loggers/ft_rich_handler.py +++ b/freqtrade/loggers/ft_rich_handler.py @@ -16,7 +16,6 @@ class FtRichHandler(Handler): # Format log message log_time = Text( datetime.fromtimestamp(record.created).strftime("%Y-%m-%d %H:%M:%S,%f")[:-3], - style="gray78", ) name = Text(record.name, style="violet") log_level = Text(record.levelname, style=f"logging.level.{record.levelname.lower()}") From e5da4d4be17045aca9a06ec892ba1611fd20f7b1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 10:49:19 +0100 Subject: [PATCH 05/14] chore: move print_colorized to transfer to config before logging setup --- freqtrade/configuration/configuration.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 796296a7b..8b506b452 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -135,6 +135,12 @@ class Configuration: if "logfile" in self.args and self.args["logfile"]: config.update({"logfile": self.args["logfile"]}) + if "print_colorized" in self.args and not self.args["print_colorized"]: + logger.info("Parameter --no-color detected ...") + config.update({"print_colorized": False}) + else: + config.update({"print_colorized": True}) + setup_logging(config) def _process_trading_options(self, config: Config) -> None: @@ -326,12 +332,6 @@ class Configuration: ] self._args_to_config_loop(config, configurations) - if "print_colorized" in self.args and not self.args["print_colorized"]: - logger.info("Parameter --no-color detected ...") - config.update({"print_colorized": False}) - else: - config.update({"print_colorized": True}) - configurations = [ ("print_json", "Parameter --print-json detected ..."), ("export_csv", "Parameter --export-csv detected: {}"), From 0f4330a6bba17d3e1770614bb5da736b5f9975a4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 10:50:05 +0100 Subject: [PATCH 06/14] feat: properly set color_system --- freqtrade/loggers/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/loggers/__init__.py b/freqtrade/loggers/__init__.py index 6e560a9ea..e6e2dd18f 100644 --- a/freqtrade/loggers/__init__.py +++ b/freqtrade/loggers/__init__.py @@ -61,8 +61,8 @@ def setup_logging(config: Config) -> None: verbosity = config["verbosity"] logging.root.addHandler(bufferHandler) if config.get("print_colorized", True): - logger.info("Enabling colorized output") - error_console._color_system = "auto" + logger.info("Enabling colorized output.") + error_console._color_system = error_console._detect_color_system() logfile = config.get("logfile") From dfcf4ba7fd51ef962f605ec37272cafda35262ee Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 10:57:57 +0100 Subject: [PATCH 07/14] chore: Improved types for rich_handler --- freqtrade/loggers/ft_rich_handler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/loggers/ft_rich_handler.py b/freqtrade/loggers/ft_rich_handler.py index a289d5435..e7cf31c08 100644 --- a/freqtrade/loggers/ft_rich_handler.py +++ b/freqtrade/loggers/ft_rich_handler.py @@ -1,12 +1,12 @@ from datetime import datetime from logging import Handler -from typing import Any +from rich.console import Console from rich.text import Text class FtRichHandler(Handler): - def __init__(self, console, *args: Any, **kwargs: Any) -> None: + def __init__(self, console: Console, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self._console = console From 392486bc170fd9113c37d539c9854b4b0319c1ce Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 11:32:28 +0100 Subject: [PATCH 08/14] feat: Add rich traceback output --- freqtrade/loggers/ft_rich_handler.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/freqtrade/loggers/ft_rich_handler.py b/freqtrade/loggers/ft_rich_handler.py index e7cf31c08..977c3184f 100644 --- a/freqtrade/loggers/ft_rich_handler.py +++ b/freqtrade/loggers/ft_rich_handler.py @@ -3,6 +3,7 @@ from logging import Handler from rich.console import Console from rich.text import Text +from rich.traceback import Traceback class FtRichHandler(Handler): @@ -20,10 +21,16 @@ class FtRichHandler(Handler): name = Text(record.name, style="violet") log_level = Text(record.levelname, style=f"logging.level.{record.levelname.lower()}") gray_sep = Text(" - ", style="gray46") - - self._console.print( - Text() + log_time + gray_sep + name + gray_sep + log_level + gray_sep + msg - ) + if record.exc_info: + exc_type, exc_value, exc_traceback = record.exc_info + tb = Traceback.from_exception(exc_type, exc_value, exc_traceback) + self._console.print(Text() + log_time + gray_sep + name + gray_sep + log_level) + self._console.print(tb) + else: + # pass + self._console.print( + Text() + log_time + gray_sep + name + gray_sep + log_level + gray_sep + msg + ) self.flush() except RecursionError: From b6867d956ce98597572f3b6ad748b35d23c7018c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 11:42:36 +0100 Subject: [PATCH 09/14] feat: improve Rich traceback rendering --- freqtrade/loggers/ft_rich_handler.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/freqtrade/loggers/ft_rich_handler.py b/freqtrade/loggers/ft_rich_handler.py index 977c3184f..e3c273c81 100644 --- a/freqtrade/loggers/ft_rich_handler.py +++ b/freqtrade/loggers/ft_rich_handler.py @@ -7,6 +7,11 @@ from rich.traceback import Traceback class FtRichHandler(Handler): + """ + Basic colorized logging handler using Rich. + Does not support all features of the standard logging handler, and uses a hard-coded log format + """ + def __init__(self, console: Console, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self._console = console @@ -21,16 +26,15 @@ class FtRichHandler(Handler): name = Text(record.name, style="violet") log_level = Text(record.levelname, style=f"logging.level.{record.levelname.lower()}") gray_sep = Text(" - ", style="gray46") + + self._console.print( + Text() + log_time + gray_sep + name + gray_sep + log_level + gray_sep + msg + ) + tb = None if record.exc_info: exc_type, exc_value, exc_traceback = record.exc_info tb = Traceback.from_exception(exc_type, exc_value, exc_traceback) - self._console.print(Text() + log_time + gray_sep + name + gray_sep + log_level) self._console.print(tb) - else: - # pass - self._console.print( - Text() + log_time + gray_sep + name + gray_sep + log_level + gray_sep + msg - ) self.flush() except RecursionError: From 3ed1454168a045ed3d558910b6136b8166523488 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 11:44:21 +0100 Subject: [PATCH 10/14] chore: reduce traceback verbosity --- freqtrade/loggers/ft_rich_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/loggers/ft_rich_handler.py b/freqtrade/loggers/ft_rich_handler.py index e3c273c81..6c18d15b9 100644 --- a/freqtrade/loggers/ft_rich_handler.py +++ b/freqtrade/loggers/ft_rich_handler.py @@ -33,7 +33,7 @@ class FtRichHandler(Handler): tb = None if record.exc_info: exc_type, exc_value, exc_traceback = record.exc_info - tb = Traceback.from_exception(exc_type, exc_value, exc_traceback) + tb = Traceback.from_exception(exc_type, exc_value, exc_traceback, extra_lines=1) self._console.print(tb) self.flush() From 0f2d3f2638fae0869af0c6fc6d6ea07514f46a31 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 11:47:51 +0100 Subject: [PATCH 11/14] test: Update tests to use rich Handler --- tests/test_log_setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_log_setup.py b/tests/test_log_setup.py index 6dc88b79d..d4bc63193 100644 --- a/tests/test_log_setup.py +++ b/tests/test_log_setup.py @@ -6,7 +6,7 @@ import pytest from freqtrade.exceptions import OperationalException from freqtrade.loggers import ( FTBufferingHandler, - FTStdErrStreamHandler, + FtRichHandler, set_loggers, setup_logging, setup_logging_pre, @@ -72,7 +72,7 @@ def test_set_loggers_syslog(): setup_logging(config) assert len(logger.handlers) == 3 assert [x for x in logger.handlers if isinstance(x, logging.handlers.SysLogHandler)] - assert [x for x in logger.handlers if isinstance(x, FTStdErrStreamHandler)] + assert [x for x in logger.handlers if isinstance(x, FtRichHandler)] assert [x for x in logger.handlers if isinstance(x, FTBufferingHandler)] # setting up logging again should NOT cause the loggers to be added a second time. setup_logging(config) @@ -96,7 +96,7 @@ def test_set_loggers_Filehandler(tmp_path): setup_logging(config) assert len(logger.handlers) == 3 assert [x for x in logger.handlers if isinstance(x, logging.handlers.RotatingFileHandler)] - assert [x for x in logger.handlers if isinstance(x, FTStdErrStreamHandler)] + assert [x for x in logger.handlers if isinstance(x, FtRichHandler)] assert [x for x in logger.handlers if isinstance(x, FTBufferingHandler)] # setting up logging again should NOT cause the loggers to be added a second time. setup_logging(config) @@ -145,7 +145,7 @@ def test_set_loggers_journald(mocker): setup_logging(config) assert len(logger.handlers) == 3 assert [x for x in logger.handlers if type(x).__name__ == "JournaldLogHandler"] - assert [x for x in logger.handlers if isinstance(x, FTStdErrStreamHandler)] + assert [x for x in logger.handlers if isinstance(x, FtRichHandler)] # reset handlers to not break pytest logger.handlers = orig_handlers From 3903e4455cc8e92daac0aa262169dd4eca5c76e4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 11:49:49 +0100 Subject: [PATCH 12/14] chore: remove unused variable in hyperopt --- freqtrade/optimize/hyperopt/hyperopt.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/freqtrade/optimize/hyperopt/hyperopt.py b/freqtrade/optimize/hyperopt/hyperopt.py index ae493d95f..cdb6d6a2f 100644 --- a/freqtrade/optimize/hyperopt/hyperopt.py +++ b/freqtrade/optimize/hyperopt/hyperopt.py @@ -93,7 +93,6 @@ class Hyperopt: self.print_all = self.config.get("print_all", False) self.hyperopt_table_header = 0 - self.print_colorized = self.config.get("print_colorized", False) self.print_json = self.config.get("print_json", False) self.hyperopter = HyperOptimizer(self.config) @@ -281,9 +280,6 @@ class Hyperopt: with Parallel(n_jobs=config_jobs) as parallel: jobs = parallel._effective_n_jobs() logger.info(f"Effective number of parallel workers used: {jobs}") - # console = Console( - # color_system="auto" if self.print_colorized else None, - # ) # Define progressbar with get_progress_tracker( From a4f3fe70c5621c4e1db3990df38d09882dbbaae1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 11:52:47 +0100 Subject: [PATCH 13/14] feat: add "no-color" argument to general arguments --- freqtrade/commands/arguments.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index a56185471..432bf4299 100755 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -11,7 +11,15 @@ from freqtrade.commands.cli_options import AVAILABLE_CLI_OPTIONS from freqtrade.constants import DEFAULT_CONFIG -ARGS_COMMON = ["verbosity", "logfile", "version", "config", "datadir", "user_data_dir"] +ARGS_COMMON = [ + "verbosity", + "print_colorized", + "logfile", + "version", + "config", + "datadir", + "user_data_dir", +] ARGS_STRATEGY = [ "strategy", @@ -58,7 +66,6 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + [ "epochs", "spaces", "print_all", - "print_colorized", "print_json", "hyperopt_jobs", "hyperopt_random_state", @@ -74,13 +81,12 @@ ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] ARGS_LIST_STRATEGIES = [ "strategy_path", "print_one_column", - "print_colorized", "recursive_strategy_search", ] -ARGS_LIST_FREQAIMODELS = ["freqaimodel_path", "print_one_column", "print_colorized"] +ARGS_LIST_FREQAIMODELS = ["freqaimodel_path", "print_one_column"] -ARGS_LIST_HYPEROPTS = ["hyperopt_path", "print_one_column", "print_colorized"] +ARGS_LIST_HYPEROPTS = ["hyperopt_path", "print_one_column"] ARGS_BACKTEST_SHOW = ["exportfilename", "backtest_show_pair_list", "backtest_breakdown"] @@ -202,7 +208,6 @@ ARGS_HYPEROPT_LIST = [ "hyperopt_list_max_total_profit", "hyperopt_list_min_objective", "hyperopt_list_max_objective", - "print_colorized", "print_json", "hyperopt_list_no_details", "hyperoptexportfilename", From 10969b7139cf4fb4a0731882fe1eb4964c6f022e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 Dec 2024 14:27:29 +0100 Subject: [PATCH 14/14] chore: improved error handling --- freqtrade/loggers/ft_rich_handler.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/freqtrade/loggers/ft_rich_handler.py b/freqtrade/loggers/ft_rich_handler.py index 6c18d15b9..bbd3d8fbd 100644 --- a/freqtrade/loggers/ft_rich_handler.py +++ b/freqtrade/loggers/ft_rich_handler.py @@ -1,6 +1,7 @@ from datetime import datetime from logging import Handler +from rich._null_file import NullFile from rich.console import Console from rich.text import Text from rich.traceback import Traceback @@ -27,6 +28,13 @@ class FtRichHandler(Handler): log_level = Text(record.levelname, style=f"logging.level.{record.levelname.lower()}") gray_sep = Text(" - ", style="gray46") + if isinstance(self._console.file, NullFile): + # Handles pythonw, where stdout/stderr are null, and we return NullFile + # instance from Console.file. In this case, we still want to make a log record + # even though we won't be writing anything to a file. + self.handleError(record) + return + self._console.print( Text() + log_time + gray_sep + name + gray_sep + log_level + gray_sep + msg ) @@ -36,7 +44,6 @@ class FtRichHandler(Handler): tb = Traceback.from_exception(exc_type, exc_value, exc_traceback, extra_lines=1) self._console.print(tb) - self.flush() except RecursionError: raise except Exception: