Framework utility

Logging

Those tidy, coloured [WF] lines you've seen since the very first wf run come from the framework's log factory. It's a small shared logger you can write to as well, so your messages sit right alongside the framework's in the same format and the same files.

Writing to the log

Grab the factory and log at the level you need. The API is what you'd expect — log (info), debug, warning, error, critical — plus an exception helper that formats a traceback for you:

fluid/services/notify.py python
from webfluid.utils.logging import factory as log


def welcome(address: str, value: str):
    try:
        # ... send the mail ...
        log.log(f"Welcome mail queued for {address}.")
    except Exception as e:
        log.exception(e, "Failed to queue welcome mail.")

Each line is rendered as [WF] [timestamp] [LEVEL] message, coloured by level on the console. exception takes the caught error and an optional message, and appends the full traceback at error level.

It only speaks during execution

The factory stays quiet unless your app is actually being run by the CLI. Concretely, it logs only when the IN_EXECUTION flag is set — which wf run sets for you. That's why importing your modules, scaffolding, or running migration commands doesn't spam framework log lines: there's no live session to log into.

 

The verbosity follows the LOG_LEVEL the CLI passes through. wf run app -l debug surfaces the debug lines; the default is info. You don't configure handlers yourself — the session is set up when the app starts.

Where the lines go

When you run an app, the CLI also tees everything into a timestamped file under logs/<app>/, so each run keeps its own record:

logs/ text
logs/
└── app/
    ├── 2026-05-28_18-04-29.log
    └── 2026-05-28_19-11-02.log

Additive-aware logging

There's one nice touch for modular apps: anything logged from within an Additive is routed through a dedicated webfluid.additives logger. The framework wraps Additive routes and hooks in that context automatically, so when you call the same factory from inside an Additive, its lines are attributed to the Additive rather than the host app — no extra work on your side.

Continue reading

From here you can continue straight with the CLI.