When Odoo misbehaves in a container, the Odoo Docker logs are the first place to look. Odoo writes every request, module load, cron run and traceback to standard error, and Docker keeps that output for you. This guide shows how to read and filter those logs with docker compose logs, what common Odoo errors look like, how to turn on debug logging for one module, and how to inspect a container that keeps restarting.
The examples assume the service names from the Odoo Docker Compose guide: web for Odoo and db for PostgreSQL.
Read Odoo Docker logs with docker compose logs
| What you want | Command |
|---|---|
| Everything from Odoo so far | docker compose logs web |
| Follow new lines live | docker compose logs -f web |
| Last 200 lines, then follow | docker compose logs -f --tail 200 web |
| Odoo and PostgreSQL together | docker compose logs -f web db |
| The last 15 minutes | docker compose logs --since 15m web |
| A fixed time window | docker compose logs --since 2026-11-10T14:00:00 --until 2026-11-10T14:10:00 web |
| Add Docker's timestamps | docker compose logs -t web |
Drop the web-1 | prefix (for grep or a file) | docker compose logs --no-log-prefix web |
--tail counts per container, so --tail 200 web db can print 400 lines. The arguments are service names from your compose file, not container names. --since and --until take a relative duration (42m, 2h) or a timestamp.
How to read an Odoo log line
2026-11-10 14:03:12,481 1 INFO mydb odoo.modules.loading: 112 modules loaded in 1.94s
2026-11-10 14:03:40,027 1 ERROR mydb odoo.http: Exception during request handling.
Each line holds the time, the process ID, the level, the database name and the logger, followed by the message. With workers above 0 you see several process IDs, one per worker. The logger name tells you where the message came from: odoo.addons.my_module is your module, odoo.http is request handling and odoo.addons.base.models.ir_cron is the scheduler.
Filter with standard tools once the prefix is gone:
docker compose logs --no-log-prefix --since 1h web | grep -E " (ERROR|CRITICAL|WARNING) "
docker compose logs --no-log-prefix web | grep -A 30 "Traceback"
docker compose logs --no-log-prefix --since 1h web > odoo-incident.log
Common Odoo errors in Docker logs
| Log message | Usual cause | Fix |
|---|---|---|
psycopg2.OperationalError: connection to server at "db" ... failed | PostgreSQL not ready, wrong host, or wrong password | Check docker compose logs db. Make sure PASSWORD on web matches POSTGRES_PASSWORD on db, and that odoo.conf has no stale db_password |
Using the database user 'postgres' is a security risk, aborting. | Odoo was given the postgres superuser | Use a dedicated role such as odoo |
ModuleNotFoundError: No module named '...' | A custom module needs a Python library the image lacks | Add it to your image; see building a custom Odoo Docker image |
| Module missing from Apps, no error | Wrong addons_path, missing __manifest__.py, or unreadable files | Check the addons paths: line Odoo prints at startup and the file permissions |
| Worker lines about a virtual memory or real time limit reached | A request or cron exceeded limit_memory_* or limit_time_real | Find the slow request above it; raise limits only if the work is legitimate. See Odoo server configuration |
| No output at all | logfile is set in odoo.conf, so Odoo writes to a file instead of standard error | Remove logfile so Docker captures the logs |
Debug Odoo in Docker: more detail for one module
Raising the global level to debug floods the log. Turn it up for one logger instead. Odoo's --log-handler option takes LOGGER:LEVEL and can be repeated. Add it as the service command. The image's entrypoint still adds the database arguments when the command starts with a dash:
services:
web:
command: ["--log-handler=odoo.addons.my_module:DEBUG"]docker compose up -d web
docker compose logs -f web
For SQL, use the pseudo-level --log-level=debug_sql for a short time only. It logs every query. Remove the override when you are done; it is meant for development, not production.
To test code against live data, open an Odoo shell in a one-off container:
docker compose run --rm --no-deps web odoo shell -d mydb
The shell runs in a transaction that is rolled back on exit unless you call env.cr.commit().
When the Odoo container keeps restarting
A crash loop often leaves little in the log. Check the container state:
docker compose ps -a
docker inspect --format '{{.State.ExitCode}} OOMKilled={{.State.OOMKilled}}' $(docker compose ps -aq web)
docker compose events web
- Exit code 137 with
OOMKilled=truemeans the kernel killed Odoo for using too much memory. Lowerworkersor raise the memory limit; see Odoo Docker memory limits. docker compose eventsstreams create, start, die and health status events as they happen.- Check that the final configuration is what you expect:
docker compose configprints the merged file with variables filled in. It prints secrets too, so do not paste it anywhere public.
Connectivity between the containers can be tested from inside Odoo's container, which ships the PostgreSQL client:
docker compose exec web pg_isready -h db -U odoo
docker compose exec db psql -U odoo -d postgres -c "select datname from pg_database;"
Keep logs from filling the disk
Docker's default json-file log driver keeps everything unless you set limits. A busy Odoo instance can fill a disk this way. Cap it per service:
services:
web:
logging:
driver: json-file
options:
max-size: "20m"
max-file: "5"This keeps at most five 20 MB files for Odoo. docker compose logs still works with these settings. If you ship logs to a central system, keep a local copy this way too, so you can still debug when the shipper is down.
Odoo logs on Easy Instance
On Easy Instance, each instance has a Logs tab with a level filter, text search, live refresh and a button that copies the filtered lines. Its browser terminal includes an odoo-shell alias, so you can debug without setting up Docker yourself. Plans are $30 per worker a month, and the 10-day free trial needs no credit card.