|
| 1 | +# Manage logging |
| 2 | + |
| 3 | +pytask can capture log records emitted during task execution, show them for failing |
| 4 | +tasks, stream them live to the terminal, and write them to a file. |
| 5 | + |
| 6 | +If you do not use Python's [`logging`](https://docs.python.org/3/library/logging.html) |
| 7 | +module often, think of log records simply as structured status messages such as |
| 8 | +"starting download", "loaded 200 rows", or "publishing failed". |
| 9 | + |
| 10 | +This guide focuses on the most common ways to work with logging in pytask. |
| 11 | + |
| 12 | +## Quick start |
| 13 | + |
| 14 | +If you want to... use this: |
| 15 | + |
| 16 | +- see log messages only when a task fails: run `pytask` |
| 17 | +- show only logs in failure reports: run `pytask --show-capture=log` |
| 18 | +- see logs immediately while tasks run: run `pytask --log-cli --log-cli-level=INFO` |
| 19 | +- save logs to a file: run `pytask --log-file=build.log` |
| 20 | +- capture more detailed messages such as `INFO` or `DEBUG`: add `--log-level=INFO` or |
| 21 | + `--log-level=DEBUG` |
| 22 | + |
| 23 | +## A minimal example |
| 24 | + |
| 25 | +```py title="task_logging.py" |
| 26 | +import logging |
| 27 | +import sys |
| 28 | + |
| 29 | + |
| 30 | +logger = logging.getLogger(__name__) |
| 31 | + |
| 32 | + |
| 33 | +def task_prepare_report(): |
| 34 | + logger.info("preparing report.txt") |
| 35 | + |
| 36 | + |
| 37 | +def task_publish_report(): |
| 38 | + logger.warning("publishing report is about to fail") |
| 39 | + print("stdout from publish") |
| 40 | + sys.stderr.write("stderr from publish\n") |
| 41 | + raise RuntimeError("simulated publish failure") |
| 42 | +``` |
| 43 | + |
| 44 | +The most common logging levels are: |
| 45 | + |
| 46 | +- `DEBUG`: very detailed information for debugging |
| 47 | +- `INFO`: normal progress messages |
| 48 | +- `WARNING`: something unexpected happened, but execution can continue |
| 49 | +- `ERROR`: a more serious problem |
| 50 | + |
| 51 | +If you are just getting started, `INFO` and `WARNING` are usually the most useful |
| 52 | +levels. |
| 53 | + |
| 54 | +Here is what this looks like with live logging enabled and failure output restricted to |
| 55 | +captured logs: |
| 56 | + |
| 57 | +```console |
| 58 | +$ pytask --log-cli --log-cli-level=INFO --show-capture=log |
| 59 | +``` |
| 60 | + |
| 61 | +--8<-- "docs/source/_static/md/logging-live.md" |
| 62 | + |
| 63 | +## Show captured logs for failing tasks |
| 64 | + |
| 65 | +Log records emitted with Python's |
| 66 | +[`logging`](https://docs.python.org/3/library/logging.html) module are attached to the |
| 67 | +report of a failing task in the same way as captured `stdout` and `stderr`. |
| 68 | + |
| 69 | +```py title="task_logging.py" |
| 70 | +import logging |
| 71 | + |
| 72 | + |
| 73 | +logger = logging.getLogger(__name__) |
| 74 | + |
| 75 | + |
| 76 | +def task_example(): |
| 77 | + logger.warning("something went wrong") |
| 78 | + raise RuntimeError("fail") |
| 79 | +``` |
| 80 | + |
| 81 | +```console |
| 82 | +$ pytask |
| 83 | +``` |
| 84 | + |
| 85 | +By default, pytask shows captured log output for failing tasks together with the |
| 86 | +traceback and any captured `stdout` or `stderr`. |
| 87 | + |
| 88 | +This is useful when a task fails and you want to see what happened right before the |
| 89 | +error. |
| 90 | + |
| 91 | +Use `--show-capture` to control which captured output is shown: |
| 92 | + |
| 93 | +```console |
| 94 | +$ pytask --show-capture=log |
| 95 | +$ pytask --show-capture=all |
| 96 | +$ pytask --show-capture=no |
| 97 | +``` |
| 98 | + |
| 99 | +`--show-capture=log` is useful when you only want log records in the failure report and |
| 100 | +want to hide captured `stdout` and `stderr`. |
| 101 | + |
| 102 | +## Control which log records are captured |
| 103 | + |
| 104 | +By default, pytask does not change the logging level. Captured output therefore depends |
| 105 | +on your normal logging configuration. |
| 106 | + |
| 107 | +In practice this often means that `WARNING` and `ERROR` messages appear, while `INFO` |
| 108 | +and `DEBUG` messages do not, unless you configure logging more explicitly. |
| 109 | + |
| 110 | +Use `--log-level` to set the threshold for captured log records explicitly: |
| 111 | + |
| 112 | +```console |
| 113 | +$ pytask --log-level=INFO |
| 114 | +$ pytask --log-level=DEBUG |
| 115 | +``` |
| 116 | + |
| 117 | +As a rule of thumb: |
| 118 | + |
| 119 | +- use `INFO` if you want to see normal progress messages, |
| 120 | +- use `DEBUG` only when you need very detailed diagnostics. |
| 121 | + |
| 122 | +This option affects: |
| 123 | + |
| 124 | +- log records attached to failing task reports, |
| 125 | +- live logs shown with `--log-cli`, |
| 126 | +- exported logs written with `--log-file`. |
| 127 | + |
| 128 | +You can customize the formatting of captured log records with: |
| 129 | + |
| 130 | +```console |
| 131 | +$ pytask --log-format="%(asctime)s %(levelname)s %(message)s" \ |
| 132 | + --log-date-format="%Y-%m-%d %H:%M:%S" |
| 133 | +``` |
| 134 | + |
| 135 | +## Stream logs live while tasks run |
| 136 | + |
| 137 | +Use `--log-cli` to print log records directly to the terminal during task execution. |
| 138 | + |
| 139 | +```console |
| 140 | +$ pytask --log-cli --log-cli-level=INFO |
| 141 | +``` |
| 142 | + |
| 143 | +This is helpful when tasks take a while and you want immediate feedback instead of |
| 144 | +waiting for the final report. |
| 145 | + |
| 146 | +You can customize live logs separately from the captured report output: |
| 147 | + |
| 148 | +```console |
| 149 | +$ pytask --log-cli \ |
| 150 | + --log-cli-level=INFO \ |
| 151 | + --log-cli-format="%(levelname)s:%(message)s" \ |
| 152 | + --log-cli-date-format="%H:%M:%S" |
| 153 | +``` |
| 154 | + |
| 155 | +If `--log-cli-format` or `--log-cli-date-format` are not provided, pytask falls back to |
| 156 | +`--log-format` and `--log-date-format`. |
| 157 | + |
| 158 | +## Write logs to a file |
| 159 | + |
| 160 | +Use `--log-file` to export log records from executed tasks to a file. |
| 161 | + |
| 162 | +```console |
| 163 | +$ pytask --log-file=build.log |
| 164 | +``` |
| 165 | + |
| 166 | +This is useful for CI runs, long builds, or when you want to inspect logs after the run |
| 167 | +has finished. |
| 168 | + |
| 169 | +The file is overwritten by default. Use `--log-file-mode=a` to append instead. |
| 170 | + |
| 171 | +```console |
| 172 | +$ pytask --log-file=build.log --log-file-mode=a |
| 173 | +``` |
| 174 | + |
| 175 | +You can control the file output independently: |
| 176 | + |
| 177 | +```console |
| 178 | +$ pytask --log-file=build.log \ |
| 179 | + --log-file-level=INFO \ |
| 180 | + --log-file-format="%(asctime)s %(name)s %(levelname)s %(message)s" \ |
| 181 | + --log-file-date-format="%Y-%m-%d %H:%M:%S" |
| 182 | +``` |
| 183 | + |
| 184 | +Relative log file paths are resolved relative to the project root detected by pytask. |
| 185 | + |
| 186 | +## A good beginner setup |
| 187 | + |
| 188 | +If you want a practical setup without spending much time on logging configuration, this |
| 189 | +is a good default: |
| 190 | + |
| 191 | +```console |
| 192 | +$ pytask --log-cli --log-cli-level=INFO --log-file=build.log --show-capture=log |
| 193 | +``` |
| 194 | + |
| 195 | +This gives you: |
| 196 | + |
| 197 | +- live progress messages in the terminal, |
| 198 | +- a log file you can inspect later, |
| 199 | +- only log output in failure reports, without extra `stdout` and `stderr` noise. |
| 200 | + |
| 201 | +## Configure logging defaults in `pyproject.toml` |
| 202 | + |
| 203 | +All logging options can be configured in `pyproject.toml`. |
| 204 | + |
| 205 | +```toml title="pyproject.toml" |
| 206 | +[tool.pytask.ini_options] |
| 207 | +log_level = "INFO" |
| 208 | +log_format = "%(asctime)s %(levelname)s %(message)s" |
| 209 | +log_date_format = "%Y-%m-%d %H:%M:%S" |
| 210 | + |
| 211 | +log_cli = true |
| 212 | +log_cli_level = "INFO" |
| 213 | +log_cli_format = "%(levelname)s:%(message)s" |
| 214 | + |
| 215 | +log_file = "build.log" |
| 216 | +log_file_mode = "w" |
| 217 | +log_file_level = "INFO" |
| 218 | +log_file_format = "%(asctime)s %(name)s %(levelname)s %(message)s" |
| 219 | +log_file_date_format = "%Y-%m-%d %H:%M:%S" |
| 220 | +``` |
| 221 | + |
| 222 | +## Use logging with the programmatic interface |
| 223 | + |
| 224 | +The same options are available via |
| 225 | +[`pytask.build`](../api/functional_interfaces.md#build-workflow). |
| 226 | + |
| 227 | +```py title="build.py" |
| 228 | +from pytask import build |
| 229 | + |
| 230 | + |
| 231 | +session = build( |
| 232 | + log_level="INFO", |
| 233 | + log_cli=True, |
| 234 | + log_cli_level="INFO", |
| 235 | + log_file="build.log", |
| 236 | + log_file_format="%(levelname)s:%(message)s", |
| 237 | +) |
| 238 | +``` |
0 commit comments