|
15 | 15 |
|
16 | 16 | import pytest |
17 | 17 |
|
| 18 | +import structlog |
| 19 | + |
18 | 20 | from structlog import tracebacks |
19 | 21 |
|
20 | 22 |
|
@@ -772,12 +774,75 @@ def test_json_traceback_value_error( |
772 | 774 | tracebacks.ExceptionDictTransformer(**kwargs) |
773 | 775 |
|
774 | 776 |
|
775 | | -def test_exception_dict_transformer_missing_exc_info(): |
| 777 | +class TestLogException: |
776 | 778 | """ |
777 | | - ExceptionDictTransformer returns an empty list if exc_info is missing. |
| 779 | + Higher level integration tests for `Logger.exception()`. |
778 | 780 | """ |
779 | | - transformer = tracebacks.ExceptionDictTransformer() |
780 | 781 |
|
781 | | - result = transformer(exc_info=(None, None, None)) |
| 782 | + @pytest.fixture |
| 783 | + def cap_logs(self) -> structlog.testing.LogCapture: |
| 784 | + """ |
| 785 | + Create a LogCapture to be used as processor and fixture for retrieving |
| 786 | + logs in tests. |
| 787 | + """ |
| 788 | + return structlog.testing.LogCapture() |
| 789 | + |
| 790 | + @pytest.fixture |
| 791 | + def logger( |
| 792 | + self, cap_logs: structlog.testing.LogCapture |
| 793 | + ) -> structlog.Logger: |
| 794 | + """ |
| 795 | + Create a logger with the dict_tracebacks and a LogCapture processor. |
| 796 | + """ |
| 797 | + old_processors = structlog.get_config()["processors"] |
| 798 | + structlog.configure([structlog.processors.dict_tracebacks, cap_logs]) |
| 799 | + logger = structlog.get_logger("dict_tracebacks") |
| 800 | + try: |
| 801 | + yield logger |
| 802 | + finally: |
| 803 | + structlog.configure(processors=old_processors) |
| 804 | + |
| 805 | + def test_log_explicit_exception( |
| 806 | + self, logger: structlog.Logger, cap_logs: structlog.testing.LogCapture |
| 807 | + ) -> None: |
| 808 | + """ |
| 809 | + The log row contains a traceback when `Logger.exception()` is |
| 810 | + explicitly called with an exception instance. |
| 811 | + """ |
| 812 | + try: |
| 813 | + 1 / 0 |
| 814 | + except ZeroDivisionError as e: |
| 815 | + logger.exception("onoes", exception=e) |
| 816 | + |
| 817 | + log_row = cap_logs.entries[0] |
| 818 | + |
| 819 | + assert log_row["exception"][0]["exc_type"] == "ZeroDivisionError" |
| 820 | + |
| 821 | + def test_log_implicit_exception( |
| 822 | + self, logger: structlog.Logger, cap_logs: structlog.testing.LogCapture |
| 823 | + ) -> None: |
| 824 | + """ |
| 825 | + The log row contains a traceback when `Logger.exception()` is called |
| 826 | + in an `except` block but without explicitly passing the exception. |
| 827 | + """ |
| 828 | + try: |
| 829 | + 1 / 0 |
| 830 | + except ZeroDivisionError: |
| 831 | + logger.exception("onoes") |
| 832 | + |
| 833 | + log_row = cap_logs.entries[0] |
| 834 | + |
| 835 | + assert log_row["exception"][0]["exc_type"] == "ZeroDivisionError" |
| 836 | + |
| 837 | + def test_no_exception( |
| 838 | + self, logger: structlog.Logger, cap_logs: structlog.testing.LogCapture |
| 839 | + ) -> None: |
| 840 | + """ |
| 841 | + `Logger.exception()` should not be called outside an `except` block |
| 842 | + but this cases is gracefully handled and does not lead to an exception. |
| 843 | +
|
| 844 | + See: https://github.com/hynek/structlog/issues/634 |
| 845 | + """ |
| 846 | + logger.exception("onoes") |
782 | 847 |
|
783 | | - assert [] == result |
| 848 | + assert [{"event": "onoes", "log_level": "error"}] == cap_logs.entries |
0 commit comments