# Trace a function or script Kolo traces any Python code. There are three ways to turn it on for a script, a test run or a single function. For per-request traces in Django see [Trace Django requests](trace-django-requests.md), and for a process that is already running see [Attach to a running process](attach-running-process.md). ## KOLO=1 Set the `KOLO` environment variable to `1` and every Python process that starts with it is traced from start to finish: ```bash KOLO=1 python example.py KOLO=1 python -m mymodule KOLO=1 pytest tests/test_checkout.py ``` There is nothing to import or configure: `pip install kolo` installs a `.pth` file that activates Kolo at interpreter startup when `KOLO` is `1` or `true`. When the process exits, Kolo saves the trace and prints the path to `.kolo/kolo.txt`: ```text Trace captured using KOLO=1 /path/to/project/.kolo/kolo.txt ``` The text files in `.kolo/traces/` and `kolo.txt` are written by a background process, so they can appear a moment after the program exits. `kolo cat` works straight away. Each process gets its own trace, so a program that starts Python subprocesses produces one trace per process. Threads are recorded in the same trace as the process that started them. `KOLO=1` records one trace for the whole process. For a long-running process such as a worker or server, use [trace points](../reference/config.md#trace-points) to save a separate trace each time a chosen function returns (Python 3.12 or newer). Set `KOLO_DISABLE=1` to turn tracing off without unsetting `KOLO`. ## kolo run `kolo run` traces a single command without setting an environment variable: ```bash kolo run python example.py kolo run example.py kolo run python -m mymodule ``` Pass `--inline` to print the call tree to stderr when the program exits, and `--returns` to include arguments and return values in it. Unlike `KOLO=1`, `kolo run` does not trace Python subprocesses. ### Tests For tests, pass `--one-trace-per-test` to get one small trace per test instead of one large trace for the whole run: ```bash kolo run --one-trace-per-test pytest kolo run --one-trace-per-test python manage.py test kolo run --one-trace-per-test unittest ``` ## kolo.enable To trace one block of code, use `kolo.enable` as a context manager: ```python import kolo def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) if __name__ == "__main__": with kolo.enable(): print(fibonacci(6)) ``` Or as a decorator, to trace a function every time it is called: ```python import kolo @kolo.enable def checkout(cart): total = sum(item.price for item in cart) return charge(total) ``` `@kolo.enable` also works on `async def` functions and on generator and async generator functions: a coroutine is traced until it returns, and a generator from its first item until it is exhausted, closed or garbage-collected, which includes the code that runs between items. Kolo records function calls and returns, so a `with kolo.enable():` block records the functions called inside the block. ```{note} `kolo.enable` can be nested. A nested `kolo.enable` joins the trace that is already running: the outermost one produces the trace, and the `config` and `name` of nested ones are ignored. ``` Pass `name` to label the trace in `kolo trace list`, and a `config` dictionary to override [config](../reference/config.md) for this trace: ```python config = { "filters": { "include_frames": ["django/db"], "ignore_frames": ["/migrations/"], }, } with kolo.enable(config, name="checkout"): ... @kolo.enable(config=config) def example(): ... ``` ## Read the trace All three write to the same place. Grep `.kolo/traces/`, read `.kolo/kolo.txt`, or run: ```bash kolo cat # call tree of the most recent trace kolo cat --returns # the same, with arguments and return values kolo trace list # stored traces, newest first kolo trace node TRACE_ID INDEX # full details of one call, including locals ``` See the [CLI reference](../reference/cli.md) for every command.