Skip to main content
Logging is essential for debugging your fal App during development and monitoring it after deployment. Every message your app writes to stdout or stderr is captured by fal and made available through the dashboard, CLI, and queue status API. This means print() statements, Python logging output, and even error tracebacks are all collected automatically. The most important thing to understand about logging on fal is that logs exist at different scopes, and each scope determines who can see them and where they appear. Runner logs capture everything a runner does across its lifetime. Request logs are the subset visible to callers. Playground logs appear in real-time during testing. Knowing which scope you are working with helps you decide what information is safe to log and where to look when debugging.

Runner Logs

Runner logs capture the full output of a runner process from the moment it starts until it shuts down. This includes output from setup() (model loading, initialization), every request the runner handles, and any background output between requests. Runner logs are visible only to the app owner through the dashboard and CLI. Use runner logs for internal diagnostics: model loading times, memory usage, cache behavior, and anything that spans the runner’s lifetime rather than a single request.
You can view runner logs in the CLI with fal runners logs <runner-id>, or in the dashboard filtered by runner ID.

Request Logs

Request logs are the portion of runner logs emitted while a specific request is being processed. They are time-scoped: fal captures the start and end of each request and extracts the log messages in between. These are the logs that callers see when they poll for queue status with with_logs=True (Python) or logs: true (JavaScript).
Because request logs are visible to anyone calling your app, be careful about what you log during request handling. Avoid logging secrets, user data, or internal model details that should not be exposed.

Private Logs

If your request logs contain sensitive information, you can make them private so only you (the app owner) can see them. Callers polling the queue will see no log output — logs are still captured and visible in the dashboard and CLI, but non-owners receive empty log arrays in their status responses. There are two ways to make logs private: per-app via the private_logs option, or account-wide via the Log Privacy setting.

Per-app

Set private_logs=True in the class definition to make logs private for that app only:
A per-app private_logs=True always makes that app’s logs private, regardless of the account-level default.

Account-wide default

Under Dashboard → Settings → Log Privacy, the Default Private Logs toggle controls the default visibility of logs across all your apps. When enabled, log visibility for non-owners is restricted on newly deployed apps — they inherit private_logs=True at registration time without needing to set it explicitly in code. Existing apps retain their current setting until redeployed; redeploy an app to pick up the current account default. An app that explicitly sets private_logs=True is always private. An app that does not set private_logs at all follows the account default in effect when it was deployed.

Playground Logs

When you test your app in the Playground, logs appear in real-time in the output panel as your endpoint processes the request. The Playground shows request logs (the same logs callers would see via the queue API), so you can verify exactly what output your users will receive. During development with fal run, logs also stream directly to your terminal, giving you immediate feedback without needing the dashboard.

Writing Logs

For quick debugging, print() is the simplest approach. Both stdout and stderr are captured.
For production apps, use Python’s standard logging module to control log levels and message format. A good pattern is to route INFO and WARNING to stdout and ERROR and above to stderr, so you can filter by severity when reviewing logs.
Include the request ID in your log output for easier debugging. You can access it via self.current_request.request_id in your endpoint handler. See Request Headers for all available per-request context including caller identity and custom headers.
Avoid logging secrets, API keys, or large raw payloads. Log IDs, sizes, and high-level status instead.

Log Sources

When filtering logs in the dashboard or CLI, the source field tells you where the logs came from:
  • run - logs from runners created by fal run during development
  • gateway - logs from runners serving deployed apps in production
  • deploy - logs emitted by the deployment process itself when using fal deploy

Where to View Logs