Skip to main content
Cognee writes structured logs to two destinations simultaneously: the console and a log file. A new log file is created each time Cognee starts. The file captures everything from DEBUG upward. The console shows only the level you configure.

How Logging Works in Cognee

When you import or start Cognee, setup_logging() is called automatically. The first call in a process configures two handlers:
  • Console handler — writes colored output to stderr, filtered by LOG_LEVEL (default: INFO)
  • File handler — writes plain text to a timestamped .log file, always at DEBUG level
One log file is created per startup and shared across all sub-processes. Cognee keeps the 10 most recent log files and deletes older ones automatically. The active file is also capped by size and rotated — see Size-Based Rotation below.

Logging Is Configured Once Per Process

setup_logging() is idempotent. Cognee calls it from four places during a normal server start — importing cognee, importing cognee.api.client, importing the vector embeddings utilities, and server startup — but only the first call does any configuration work. That call installs the console and file handlers, sets up the sys.excepthook, opens the log file, and emits the startup messages. Every later call, including one you write yourself, returns a structlog logger and changes nothing: the handlers, log file, and excepthook from the first call stay in place, and the startup banner is not repeated. Because the first call wins, arguments you pass to a later setup_logging(log_level=...) call are ignored — see Setting the Log Level for the supported way to control verbosity. The guard is per interpreter. A sub-process starts fresh, configures its own handlers, and appends to the same log file, which is how one file ends up holding output from all of them.
The default logs/ directory is created next to the cognee package directory, one level above it. The exact path depends on how Cognee is installed.Installed via pip (e.g. pip install cognee):
Running from source (cloned repository):
Using the MCP server: The MCP server uses the same logging setup. The log directory is the same as above, depending on your environment. When a background task is launched, the MCP server returns the full path to the active log file in its response.
When Cognee is installed via pip or used as an MCP server, log files end up inside your virtual environment’s site-packages/ directory. Set COGNEE_LOGS_DIR to write logs to a predictable location instead.

Size-Based Rotation

The file handler also caps how large a single startup’s log can grow. Before writing each record it checks the current file size, and once the file has reached COGNEE_LOG_MAX_BYTES (default 50 MB) it rolls over: the active file is renamed to <name>.log.1, any existing backups shift up by one, and logging continues in a fresh file under the original name. At most COGNEE_LOG_BACKUP_COUNT backups (default 5) are kept, so on the defaults one startup’s logs occupy roughly 300 MB at the ceiling — one active 50 MB file plus five 50 MB backups. Rotation and the keep-10 cleanup are independent mechanisms. Rotation bounds the size of one startup’s log; the keep-10 cleanup prunes old startups’ files. The cleanup only matches files ending in .log, so numbered rotation backups (.log.1, .log.2, …) are not counted by it and are not removed when their originating startup’s .log file is pruned. If you run with a large COGNEE_LOG_BACKUP_COUNT and restart often, prune the log directory yourself.
Rotation is a recent fix. In earlier releases COGNEE_LOG_MAX_BYTES and COGNEE_LOG_BACKUP_COUNT were accepted and handed to the file handler, but the handler never acted on them — a startup’s log file grew without bound. If you set those variables before and saw no rotation, upgrading is what makes them take effect, and disk usage will now behave as the values describe.

Controlling Logging

Environment Variables

  • COGNEE_LOGS_DIR — Absolute path to a custom log directory. Cognee creates it if it does not exist. Must be an absolute path — relative paths cause a startup error. Default: logs/ next to the cognee package.
  • LOG_LEVEL — Console log verbosity. One of DEBUG, INFO, WARNING, ERROR, CRITICAL. Default: INFO. Does not affect the log file, which always captures DEBUG and above.
  • COGNEE_LOG_MAX_BYTES — Size in bytes at which the active log file is rotated. Default: 52428800 (50 MB). Set it to 0 to turn size-based rotation off and let a startup’s log file grow without a cap.
  • COGNEE_LOG_BACKUP_COUNT — How many rotated backups to keep alongside the active file. Default: 5. Backups are named <name>.log.1 through <name>.log.<count>, oldest last.

Setting the Log Level

LOG_LEVEL is read when logging is configured, which happens on the first setup_logging() call — and import cognee makes that call for you. So the level must be in place before the import:
Setting it in the .env file works too, and takes precedence: Cognee loads .env with override=True at import time, just before configuring logging. If LOG_LEVEL is in your .env, change it there rather than in the shell or in code.
Calling setup_logging(log_level=...) yourself after import cognee has no effect on verbosity. Logging is already configured at that point, so the call returns a logger and leaves the console level untouched. Older examples that adjusted the level this way need to set LOG_LEVEL before importing Cognee instead.

Configuration Examples

Fallback Behavior

If Cognee cannot write to COGNEE_LOGS_DIR, it falls back to /tmp/cognee_logs. If that also fails, file logging is skipped silently and only console output is produced.

Log Files and Their Content

File Format

Log files use plain text, one entry per line. Timestamps are in UTC:

Console Format

The console uses structlog’s colored renderer, written to stderr. Level colors: DEBUG blue, INFO green, WARNING yellow, ERROR and CRITICAL red. Logged exception tracebacks are rendered without per-frame local variables (show_locals=False). The traceback itself is still shown, but the values of locals in each frame are omitted. This keeps memory bounded when exceptions are logged in the retrieval/search path, where frame locals can hold graph objects carrying embedding vectors and deep node/edge references — rendering those recursively could spike memory to multiple GB and OOM-kill the process. Cognee also installs a safe sys.excepthook, so uncaught non-KeyboardInterrupt exceptions are logged through structlog before Python’s default traceback is printed. If rich traceback rendering fails, Cognee falls back to plain traceback output.

Exception Details

When an exception is logged, the structured log event includes the exception type in exception_type alongside the exception message. This makes error entries easier to interpret because they show both what failed and the exception class that raised it, for example ValueError.

What to Expect at Startup

Cognee initializes logging once per process, and that initialization logs the following four messages in order:
  1. INFO — The full path to the log file created for this session.
  2. WARNING — The Cognee 1.0 changes banner: the new remember/recall/forget/improve API, session memory on by default, multi-user access control on by default, and agents auto-verified on registration. This is expected and not an error.
  3. INFOLogging initialized, with system metadata attached as structured fields: Python version, structlog version, Cognee version, OS, and the database storage path.
  4. INFO — The database storage path again, as a plain-text line.
If the log file path message is missing from the console, file logging may have failed. Check whether the log directory is writable or set COGNEE_LOGS_DIR to a path you control. The active graph, vector, and relational providers are not part of these messages. Cognee defers that configuration logging to the first actual pipeline call, because importing those configs pulls in heavy dependencies.

File Naming

Each log file is named after the startup timestamp:
Example: 2025-02-14_15-32-47.log When that file hits the size cap it is rotated, so a long-running startup leaves numbered backups next to it — 2025-02-14_15-32-47.log.1 is the most recent rotated segment, .log.2 the one before it, and so on.

Troubleshooting

Run this snippet after importing cognee to get the exact path:
Cognee falls back to console-only logging if the log directory is not writable. This is common in managed environments where site-packages/ is read-only.Set COGNEE_LOGS_DIR to an absolute path you own:
Cognee used to redo the whole configuration on every setup_logging() call: each call replaced the root logger’s handlers, reopened the log file, and re-emitted the startup messages — a server start could log the “Cognee 1.0 changes” warning four times.Logging is now configured exactly once per process, so the banner is logged once. If you see it more than once, more than one process is writing to the same file: sub-processes share the parent’s log file by design, and each one configures its own handlers.
Logging is configured on the first setup_logging() call, which import cognee triggers. If you set LOG_LEVEL after that import — or call setup_logging(log_level=...) yourself — the level is already fixed and your change does nothing. Set LOG_LEVEL in your .env file or in the environment before importing Cognee. See Setting the Log Level.

Overview

Return to setup configuration overview

Relational Databases

Configure metadata and state storage

Installation

Install Cognee and set up your environment