From 102adf17e0ca9c653fa976e6464d158d1255ba37 Mon Sep 17 00:00:00 2001 From: Thomas Sibley Date: Wed, 14 Aug 2024 11:43:40 -0700 Subject: [PATCH] Add a debugging mode controlled by AUGUR_DEBUG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment, this only enables printing of stack traces and the full exception chain for handled (i.e. anticipated) errors, which otherwise were not printed. In the future, this mode can also control the output of verbose debugging/troubleshooting logging for more commands. Commit contents and message based on similar commits I made to Nextstrain CLI.¹ Resolves . ¹ --- CHANGES.md | 2 ++ augur/__init__.py | 15 +++++++++++++++ augur/debug.py | 12 ++++++++++++ docs/api/developer/augur.debug.rst | 7 +++++++ docs/api/developer/augur.rst | 1 + 5 files changed, 37 insertions(+) create mode 100644 augur/debug.py create mode 100644 docs/api/developer/augur.debug.rst diff --git a/CHANGES.md b/CHANGES.md index dd4883ae2..001c15b77 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ ### Features * Two new commands, `augur read-file` and `augur write-file`, now allow external programs to do i/o like Augur by piping from/to these new commands. They provide handling of compression formats and newlines consistent with the rest of Augur. [#1562][] (@tsibley) +* A new debugging mode can be enabled by setting the `AUGUR_DEBUG` environment variable to `1` (or another truthy value). Currently the only effect is to print more information about handled (i.e. anticipated) errors. For example, stack traces and parent exceptions in an exception chain are normally omitted for handled errors, but setting this env var includes them. Future debugging and troubleshooting features, like verbose operation logging, will likely also condition on this new debugging mode. [#1577][] (@tsibley) ### Bug Fixes @@ -13,6 +14,7 @@ [#1561]: https://github.com/nextstrain/augur/pull/1561 [#1562]: https://github.com/nextstrain/augur/pull/1562 [#1564]: https://github.com/nextstrain/augur/pull/1564 +[#1577]: https://github.com/nextstrain/augur/pull/1577 diff --git a/augur/__init__.py b/augur/__init__.py index 7b4f2066b..9ef4928dd 100644 --- a/augur/__init__.py +++ b/augur/__init__.py @@ -11,6 +11,7 @@ from types import SimpleNamespace from treetime import TreeTimeError, TreeTimeUnknownError +from .debug import DEBUGGING from .errors import AugurError from .io.print import print_err from .argparse_ import add_command_subparsers, add_default_command @@ -67,21 +68,35 @@ def run(argv): try: return args.__command__.run(args) except AugurError as e: + if DEBUGGING: + traceback.print_exc(file=sys.stderr) print_err(f"ERROR: {e}") sys.exit(2) except RecursionError: + if DEBUGGING: + traceback.print_exc(file=sys.stderr) print_err("FATAL: Maximum recursion depth reached. You can set the env variable AUGUR_RECURSION_LIMIT to adjust this (current limit: {})".format(sys.getrecursionlimit())) sys.exit(2) except FileNotFoundError as e: + if DEBUGGING: + traceback.print_exc(file=sys.stderr) print_err(f"ERROR: {e.strerror}: '{e.filename}'") sys.exit(2) except TreeTimeUnknownError as e: + # TreeTime already prints the traceback (and some other verbiage) in + # TreeTime.run()¹, so don't duplicate it. This is also why the "(see + # above)" in our message below makes sense. + # -trs, 14 Aug 2024 + # + # ¹ print_err(dedent("""\ ERROR from TreeTime: An error occurred in TreeTime (see above). This may be due to an issue with TreeTime or Augur. Please report you are calling TreeTime via Augur. """)) sys.exit(2) except TreeTimeError as e: + if DEBUGGING: + traceback.print_exc(file=sys.stderr) print_err(f"ERROR: {e}") print_err("\n") print_err(dedent("""\ diff --git a/augur/debug.py b/augur/debug.py new file mode 100644 index 000000000..9d36f1f82 --- /dev/null +++ b/augur/debug.py @@ -0,0 +1,12 @@ +""" +Debug flags and utilities. + +.. envvar:: AUGUR_DEBUG + + Set to a truthy value (e.g. 1) to print more information about (handled) + errors. For example, when this is not set or falsey, stack traces and + parent exceptions in an exception chain are omitted from handled errors. +""" +from os import environ + +DEBUGGING = bool(environ.get("AUGUR_DEBUG")) diff --git a/docs/api/developer/augur.debug.rst b/docs/api/developer/augur.debug.rst new file mode 100644 index 000000000..a84b1bc8e --- /dev/null +++ b/docs/api/developer/augur.debug.rst @@ -0,0 +1,7 @@ +augur.debug module +================== + +.. automodule:: augur.debug + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/developer/augur.rst b/docs/api/developer/augur.rst index 8d611731b..4ef15e6e3 100644 --- a/docs/api/developer/augur.rst +++ b/docs/api/developer/augur.rst @@ -31,6 +31,7 @@ Submodules augur.ancestral augur.argparse_ augur.clades + augur.debug augur.distance augur.errors augur.export