Skip to content

Commit

Permalink
Logger handler manages exception info using the existing ExceptionTra…
Browse files Browse the repository at this point in the history
…ce class
  • Loading branch information
dylan-robins committed Jan 4, 2025
1 parent bd98a59 commit 3b86542
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 9 deletions.
11 changes: 11 additions & 0 deletions src/cleo/logging/cleo_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
from logging import LogRecord
from typing import TYPE_CHECKING
from typing import ClassVar
from typing import cast

from cleo.exceptions import CleoUserError
from cleo.io.outputs.output import Verbosity
from cleo.ui.exception_trace.component import ExceptionTrace


if TYPE_CHECKING:
Expand Down Expand Up @@ -65,6 +68,14 @@ def emit(self, record: logging.LogRecord) -> None:
try:
msg = self.tags.get(record.levelname, "") + self.format(record) + "</>"
self.output.write(msg, new_line=True)
if record.exc_info:
_type, error, traceback = record.exc_info
simple = not self.output.is_verbose() or isinstance(
error, CleoUserError
)
error = cast(Exception, error)
trace = ExceptionTrace(error)
trace.render(self.output, simple)

except Exception:
self.handleError(record)
21 changes: 20 additions & 1 deletion tests/fixtures/foo4_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

import logging

from typing import TYPE_CHECKING
from typing import ClassVar

from cleo.commands.command import Command
from cleo.helpers import option


if TYPE_CHECKING:
from cleo.io.inputs.option import Option


_logger = logging.getLogger(__file__)
Expand All @@ -17,13 +23,26 @@ def log_stuff() -> None:
_logger.error("This is an error log record")


def log_exception() -> None:
try:
raise RuntimeError("This is an exception that I raised")
except RuntimeError as e:
_logger.exception(e)


class Foo4Command(Command):
name = "foo4"

description = "The foo4 bar command"

aliases: ClassVar[list[str]] = ["foo4"]

options: ClassVar[list[Option]] = [option("exception")]

def handle(self) -> int:
log_stuff()
if self.option("exception"):
log_exception()
else:
log_stuff()

return 0
68 changes: 60 additions & 8 deletions tests/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ def root_logger() -> logging.Logger:
return root


def test_run_with_logging_integration_normal(
tester: ApplicationTester, root_logger: logging.Logger
def test_cleohandler_normal(
tester: ApplicationTester,
root_logger: logging.Logger,
) -> None:
handler = CleoHandler(tester.io.output)
root_logger.addHandler(handler)
Expand All @@ -46,8 +47,9 @@ def test_run_with_logging_integration_normal(
assert tester.io.fetch_output() == expected


def test_run_with_logging_integration_quiet(
tester: ApplicationTester, root_logger: logging.Logger
def test_cleohandler_quiet(
tester: ApplicationTester,
root_logger: logging.Logger,
) -> None:
handler = CleoHandler(tester.io.output)
root_logger.addHandler(handler)
Expand All @@ -58,8 +60,9 @@ def test_run_with_logging_integration_quiet(
assert tester.io.fetch_output() == ""


def test_run_with_logging_integration_verbose(
tester: ApplicationTester, root_logger: logging.Logger
def test_cleohandler_verbose(
tester: ApplicationTester,
root_logger: logging.Logger,
) -> None:
handler = CleoHandler(tester.io.output)
root_logger.addHandler(handler)
Expand All @@ -76,8 +79,9 @@ def test_run_with_logging_integration_verbose(
assert tester.io.fetch_output() == expected


def test_run_with_logging_integration_very_verbose(
tester: ApplicationTester, root_logger: logging.Logger
def test_cleohandler_very_verbose(
tester: ApplicationTester,
root_logger: logging.Logger,
) -> None:
handler = CleoHandler(tester.io.output)
root_logger.addHandler(handler)
Expand All @@ -93,3 +97,51 @@ def test_run_with_logging_integration_very_verbose(

assert status_code == 0
assert tester.io.fetch_output() == expected


def test_cleohandler_exception_normal(
tester: ApplicationTester,
root_logger: logging.Logger,
) -> None:
handler = CleoHandler(tester.io.output)
root_logger.addHandler(handler)

status_code = tester.execute("--exception")

assert status_code == 0
lines = tester.io.fetch_output().splitlines()

assert len(lines) == 7
assert lines[0] == "This is an exception that I raised"


def test_cleohandler_exception_verbose(
tester: ApplicationTester,
root_logger: logging.Logger,
) -> None:
handler = CleoHandler(tester.io.output)
root_logger.addHandler(handler)

status_code = tester.execute("-v --exception")

assert status_code == 0
lines = tester.io.fetch_output().splitlines()

assert len(lines) == 20
assert lines[0] == "This is an exception that I raised"


def test_cleohandler_exception_very_verbose(
tester: ApplicationTester,
root_logger: logging.Logger,
) -> None:
handler = CleoHandler(tester.io.output)
root_logger.addHandler(handler)

status_code = tester.execute("-vv --exception")

assert status_code == 0
lines = tester.io.fetch_output().splitlines()

assert len(lines) == 20
assert lines[0] == "This is an exception that I raised"

0 comments on commit 3b86542

Please sign in to comment.