Mark
05/18/2026, 12:44 PMlogging.basicConfig(level=<http://logging.INFO|logging.INFO>) but it seems like prefect is overwriting this, because I'm only seeing warning-level (and higher) logs from my flow runs. And I'd also like apply structured (json) formatting to the logs. Can you tell me how to configure my work to also log info-level logs lines and to format logs as structured json log linesMarvin
05/18/2026, 12:44 PMMarvin
05/18/2026, 12:46 PMlogging.basicConfig(...) is usually not the right way to configure logging with Prefect.
Prefect sets up its own logging config when it is imported, so your basicConfig(level=<http://logging.INFO|logging.INFO>) often gets overridden. That’s why you’re only seeing `WARNING`+ in worker/stdout logs.
What to do instead
For Prefect 3.x, configure logging with Prefect settings / logging config, not basicConfig.
Why you only see warnings
There are really two different log paths involved:
1. Flow/task run logs
These are emitted by get_run_logger() and sent to the Prefect API/UI.
2. Worker / console logs
These go through the root/console logger, which defaults to WARNING.
So it’s very common for:
- logs to exist in the Prefect UI
- but only `WARNING`+ to show up in the worker process output
If you want INFO in worker logs/stdout, you need to lower the root logger level.
Enable INFO-level logs in worker output
Set:
bash
export PREFECT_LOGGING_ROOT_LEVEL=INFO
You can also persist it with Prefect config:
bash
prefect config set PREFECT_LOGGING_ROOT_LEVEL=INFO
That’s the key setting for seeing INFO lines in worker/console output.
If you also want Prefect’s own loggers at INFO, that is already the default, but you can be explicit:
bash
export PREFECT_LOGGING_LEVEL=INFO
Important: set env vars before the worker starts.
Example:
bash
export PREFECT_LOGGING_ROOT_LEVEL=INFO
export PREFECT_LOGGING_LEVEL=INFO
prefect worker start --pool my-pool
Structured JSON logs
For JSON logs, the most reliable approach is to provide a custom Prefect logging config file and point Prefect at it.
Create a file like `~/.prefect/logging.yml`:
yaml
version: 1
disable_existing_loggers: false
formatters:
json:
class: prefect.logging.formatters.JsonFormatter
format: default
handlers:
console:
class: prefect.logging.handlers.PrefectConsoleHandler
level: 0
formatter: json
stream: <ext://sys.stderr>
api:
class: prefect.logging.handlers.APILogHandler
level: 0
worker_api:
class: prefect.logging.handlers.WorkerAPILogHandler
level: 0
loggers:
prefect:
level: INFO
handlers: [console]
propagate: false
prefect.flow_runs:
level: NOTSET
handlers: [api]
propagate: false
prefect.task_runs:
level: NOTSET
handlers: [api]
propagate: false
prefect.workers:
level: NOTSET
handlers: [worker_api, console]
propagate: false
root:
level: INFO
handlers: [console]
Then point Prefect at it:
bash
export PREFECT_LOGGING_SETTINGS_PATH=~/.prefect/logging.yml
Then start your worker.
What this does
- sets root logger to INFO
- formats console output as JSON
- keeps flow/task logs going to the API
- also sends worker logs to console as JSON
Notes on your application logs
If you log from inside flows/tasks, prefer:
python
from prefect import flow, task
from prefect.logging import get_run_logger
@task
def my_task():
logger = get_run_logger()
<http://logger.info|logger.info>("hello from task")
@flow
def my_flow():
logger = get_run_logger()
<http://logger.info|logger.info>("hello from flow")
my_task()
Using get_run_logger() ensures logs are attached to the flow/task run and show up properly in Prefect.
If you use plain logging.getLogger(__name__), those logs may only go to stdout/stderr unless you explicitly configure those loggers too.
If you want third-party library logs too
You can include extra loggers with:
bash
export PREFECT_LOGGING_EXTRA_LOGGERS=httpx,sqlalchemy
CLI reference
I’d use:
bash
prefect config set PREFECT_LOGGING_ROOT_LEVEL INFO
and for starting workers, the standard command is:
bash
prefect worker start --pool my-pool
Recommended setup
If your goal is “show INFO logs in worker logs and emit JSON lines”, I’d do this:
1. Create custom logging.yml
2. Set:
bash
export PREFECT_LOGGING_SETTINGS_PATH=~/.prefect/logging.ymlMarvin
05/18/2026, 12:46 PMbash
prefect worker start --pool my-pool
Helpful links
- Prefect logging customization docs: Logging customization
- Prefect settings reference: Settings reference
If you want, I can also give you:
- a minimal JSON logging config just for workers, or
- a config tailored for Kubernetes / Docker / CloudWatch / Datadog log collectors.Mark
05/18/2026, 1:12 PMMarvin
05/18/2026, 1:12 PMMarvin
05/18/2026, 1:14 PMget_run_logger().
But there’s an important distinction:
What Prefect can capture into the UI
- Python logging records from loggers that have Prefect’s API handler attached
- print() output if you enable log_prints=True
What Prefect does not automatically capture into the UI
- arbitrary stdout/stderr text written outside Python logging
- subprocess output unless you explicitly route it into logging/print
So if a third-party library uses the standard logging module, you can usually get those logs into the Prefect UI.
Best option for third-party libraries: PREFECT_LOGGING_EXTRA_LOGGERS
Prefect supports attaching its API log handler to additional logger names.
Example:
bash
export PREFECT_LOGGING_EXTRA_LOGGERS=requests,urllib3,sqlalchemy,dask
That tells Prefect to also capture those Python loggers and send them to the Prefect API/UI during flow/task runs.
This is probably the cleanest solution for your case.
If you use a custom logging.yml
You can also explicitly wire those loggers to the api handler in your config.
Example:
yaml
version: 1
disable_existing_loggers: false
formatters:
json:
class: prefect.logging.formatters.JsonFormatter
format: default
handlers:
console:
class: prefect.logging.handlers.PrefectConsoleHandler
level: 0
formatter: json
stream: <ext://sys.stderr>
api:
class: prefect.logging.handlers.APILogHandler
level: 0
loggers:
prefect:
level: INFO
handlers: [console]
propagate: false
prefect.flow_runs:
level: NOTSET
handlers: [api]
propagate: false
prefect.task_runs:
level: NOTSET
handlers: [api]
propagate: false
sqlalchemy:
level: INFO
handlers: [api, console]
propagate: false
urllib3:
level: INFO
handlers: [api, console]
propagate: false
root:
level: INFO
handlers: [console]
That would send those libraries both to:
- your JSON console logs
- the Prefect UI
Important limitation: only during a flow/task run context
Prefect’s API log capture for run logs depends on flow/task run context.
That means:
- logs emitted inside a running flow/task can go to the UI
- logs emitted by the worker process itself, outside the run context, generally won’t show up as flow run logs in the UI
So if you want logs visible on the flow run page, they need to happen while the flow/task is executing.
For print() output
If some code writes with print(...), you can capture that too:
python
from prefect import flow
@flow(log_prints=True)
def my_flow():
print("this will go to Prefect logs")
or globally:
bash
export PREFECT_LOGGING_LOG_PRINTS=true
But this only helps for print(), not arbitrary sys.stdout.write(...) or subprocess output.
What will not be automatically captured
- subprocess.run(...) output to stdout/stderr
- native extensions writing directly to stderr
- shell commands unless you capture and re-log them
- worker boot logs as run logs
For those, you’d need to:
- capture output in Python
- emit it through logging or print()
Recommended setup for your case
Since you already have structured JSON console logs, I’d suggest:
1. Keep your custom logging.yml
2. Add the third-party loggers you care about to either:
- PREFECT_LOGGING_EXTRA_LOGGERS, or
- explicit loggers: entries with handlers: [api, console]
3. Enable log_prints=True if relevant
Example env var approach:
bash
export PREFECT_LOGGING_ROOT_LEVEL=INFO
export PREFECT_LOGGING_EXTRA_LOGGERS=sqlalchemy,urllib3,requests
export PREFECT_LOGGING_LOG_PRINTS=true
export PREFECT_LOGGING_SETTINGS_PATH=~/.prefect/logging.yml
One gotcha: duplicate logs
If a third-party logger propagates upward and you attach both api and console, you may see duplicates. If that happens, set:
yaml
propagate: false
for those specific loggers.Marvin
05/18/2026, 1:14 PMlogging
- Yes for print() if log_prints=True
- No, not automatically for arbitrary stdout/stderr text or subprocess output
Docs:
- Logging customization
- Settings reference
If you want, I can help you turn your current logging.yml into a version that sends:
- JSON to stdout/stderr, and
- selected third-party loggers to the Prefect UI
without duplicating lines.