Logging¶
New in version 3.3.
Changed in version 3.4.
pytest captures log messages of level WARNING
or above automatically and displays them in their own section
for each failed test in the same manner as captured stdout and stderr.
Running without options:
pytest
Shows failed tests like so:
----------------------- Captured stdlog call ----------------------
test_reporting.py 26 WARNING text going to logger
----------------------- Captured stdout call ----------------------
text going to stdout
----------------------- Captured stderr call ----------------------
text going to stderr
==================== 2 failed in 0.02 seconds =====================
By default each captured log message shows the module, line number, log level and message.
If desired the log and date format can be specified to anything that the logging module supports by passing specific formatting options:
pytest --log-format="%(asctime)s %(levelname)s %(message)s" \
--log-date-format="%Y-%m-%d %H:%M:%S"
Shows failed tests like so:
----------------------- Captured stdlog call ----------------------
2010-04-10 14:48:44 WARNING text going to logger
----------------------- Captured stdout call ----------------------
text going to stdout
----------------------- Captured stderr call ----------------------
text going to stderr
==================== 2 failed in 0.02 seconds =====================
These options can also be customized through pytest.ini
file:
[pytest]
log_format = %(asctime)s %(levelname)s %(message)s
log_date_format = %Y-%m-%d %H:%M:%S
Further it is possible to disable reporting of captured content (stdout, stderr and logs) on failed tests completely with:
pytest --show-capture=no
caplog fixture¶
Inside tests it is possible to change the log level for the captured log
messages. This is supported by the caplog
fixture:
def test_foo(caplog):
caplog.set_level(logging.INFO)
pass
By default the level is set on the root logger, however as a convenience it is also possible to set the log level of any logger:
def test_foo(caplog):
caplog.set_level(logging.CRITICAL, logger='root.baz')
pass
The log levels set are restored automatically at the end of the test.
It is also possible to use a context manager to temporarily change the log
level inside a with
block:
def test_bar(caplog):
with caplog.at_level(logging.INFO):
pass
Again, by default the level of the root logger is affected but the level of any logger can be changed instead with:
def test_bar(caplog):
with caplog.at_level(logging.CRITICAL, logger='root.baz'):
pass
Lastly all the logs sent to the logger during the test run are made available on
the fixture in the form of both the logging.LogRecord
instances and the final log text.
This is useful for when you want to assert on the contents of a message:
def test_baz(caplog):
func_under_test()
for record in caplog.records:
assert record.levelname != 'CRITICAL'
assert 'wally' not in caplog.text
For all the available attributes of the log records see the
logging.LogRecord
class.
You can also resort to record_tuples
if all you want to do is to ensure,
that certain messages have been logged under a given logger name with a given
severity and message:
def test_foo(caplog):
logging.getLogger().info('boo %s', 'arg')
assert caplog.record_tuples == [
('root', logging.INFO, 'boo arg'),
]
You can call caplog.clear()
to reset the captured log records in a test:
def test_something_with_clearing_records(caplog):
some_method_that_creates_log_records()
caplog.clear()
your_test_method()
assert ['Foo'] == [rec.message for rec in caplog.records]
The caplog.records
attribute contains records from the current stage only, so
inside the setup
phase it contains only setup logs, same with the call
and
teardown
phases.
To access logs from other stages, use the caplog.get_records(when)
method. As an example,
if you want to make sure that tests which use a certain fixture never log any warnings, you can inspect
the records for the setup
and call
stages during teardown like so:
@pytest.fixture
def window(caplog):
window = create_window()
yield window
for when in ("setup", "call"):
messages = [
x.message for x in caplog.get_records(when) if x.level == logging.WARNING
]
if messages:
pytest.fail(
"warning messages encountered during testing: {}".format(messages)
)
The full API is available at _pytest.logging.LogCaptureFixture
.
Live Logs¶
By setting the log_cli
configuration option to true
, pytest will output
logging records as they are emitted directly into the console.
You can specify the logging level for which log records with equal or higher
level are printed to the console by passing --log-cli-level
. This setting
accepts the logging level names as seen in python’s documentation or an integer
as the logging level num.
Additionally, you can also specify --log-cli-format
and
--log-cli-date-format
which mirror and default to --log-format
and
--log-date-format
if not provided, but are applied only to the console
logging handler.
All of the CLI log options can also be set in the configuration INI file. The option names are:
log_cli_level
log_cli_format
log_cli_date_format
If you need to record the whole test suite logging calls to a file, you can pass
--log-file=/path/to/log/file
. This log file is opened in write mode which
means that it will be overwritten at each run tests session.
You can also specify the logging level for the log file by passing
--log-file-level
. This setting accepts the logging level names as seen in
python’s documentation(ie, uppercased level names) or an integer as the logging
level num.
Additionally, you can also specify --log-file-format
and
--log-file-date-format
which are equal to --log-format
and
--log-date-format
but are applied to the log file logging handler.
All of the log file options can also be set in the configuration INI file. The option names are:
log_file
log_file_level
log_file_format
log_file_date_format
Release notes¶
This feature was introduced as a drop-in replacement for the pytest-catchlog plugin and they conflict
with each other. The backward compatibility API with pytest-capturelog
has been dropped when this feature was introduced, so if for that reason you
still need pytest-catchlog
you can disable the internal feature by
adding to your pytest.ini
:
[pytest]
addopts=-p no:logging
Incompatible changes in pytest 3.4¶
This feature was introduced in 3.3
and some incompatible changes have been
made in 3.4
after community feedback:
- Log levels are no longer changed unless explicitly requested by the
log_level
configuration or--log-level
command-line options. This allows users to configure logger objects themselves. - Live Logs is now disabled by default and can be enabled setting the
log_cli
configuration option totrue
. When enabled, the verbosity is increased so logging for each test is visible. - Live Logs are now sent to
sys.stdout
and no longer require the-s
command-line option to work.
If you want to partially restore the logging behavior of version 3.3
, you can add this options to your ini
file:
[pytest]
log_cli=true
log_level=NOTSET
More details about the discussion that lead to this changes can be read in issue #3013.