Logging
SereneDB implements a logging mechanism that provides users with detailed information about events such as query execution, performance metrics and system events.
Basics
The SereneDB logging mechanism can be enabled or disabled using a special function, enable_logging. Logs are exposed through a
table function named sdb_logs, which can be queried like any standard table.
Example:
CALL enable_logging();
-- Run some queries...SELECT * FROM sdb_logs;Success
To disable logging, run
CALL disable_logging();Success
To clear the current log, run
CALL truncate_sdb_logs();Success
Log Level
SereneDB supports different logging levels that control the verbosity of the logs:
ERROR: Only logs error messagesWARN: Logs warnings and errorsINFO: Logs general information, warnings and errors (default)DEBUG: Logs detailed debugging informationTRACE: Logs very detailed tracing information
The log level can be set using:
CALL enable_logging(level = 'debug');Success
At the default INFO level the log holds the server's timeline and what needs attention. The timeline is a few lines per lifecycle step: starting SereneDB <version>, one listening on … line per endpoint, a recovery summary when recovery replayed the WAL, the ready line, and at shutdown received shutdown signal and SereneDB is shut down. The first start of a data directory adds the lines for what it creates, such as the database directory, the initial password from POSTGRES_PASSWORD and the OpenTelemetry schema. What needs attention is warnings and errors from background work, such as index refresh and compaction, checkpoints, recovery and cleanup, and failures that no statement reports. Routine events are logged at DEBUG, among them per-index recovery when nothing was replayed, the authentication mode, extension loads and credential refreshes.
A warning about a client's own statement, such as a deprecated setting or a file a reader skipped, is sent to that client as a PostgreSQL WARNING notice instead of being written to the log.
Log Types
In SereneDB, log messages can have an associated log type. Log types allow two main things:
- Fine-grained control over log message generation
- Support for structured logging
Logging-Specific Types
To log only messages of a specific type:
CALL enable_logging('HTTP');Success
The above function will automatically set the correct log level and will add the HTTP type to the enabled_log_types settings. This ensures
only log messages of the 'HTTP' type will be written to the log.
To enable multiple log types, simply pass:
CALL enable_logging(['HTTP', 'QueryLog']);Success
Structured Logging
Some log types like HTTP will have an associated message schema. To make SereneDB automatically parse the message, use the sdb_logs_parsed(log_type) macro, passing the type positionally. For example:
SELECT request.headers FROM sdb_logs_parsed('HTTP');To view the schema of each structure log type simply run:
DESCRIBE FROM sdb_logs_parsed('HTTP');List of Available Log Types
This is a (non-exhaustive) list of the available log types in SereneDB.
| Log Type | Description | Structured |
|---|---|---|
QueryLog | Logs which queries are executed in SereneDB | No |
FileSystem | Logs all FileSystem interaction with SereneDB's Filesystem | Yes |
HTTP | Logs all HTTP traffic from SereneDB's internal HTTP client | Yes |
PostgresQueryLog | Logs every query sent to a PostgreSQL server, with query and duration_ms | Yes |
ClickHouseQueryLog | Logs every query sent to a ClickHouse server, with query and duration_ms; a failed query is logged too | Yes |
SereneDB Server Log Types
Beyond the core types above, the SereneDB server (serened) emits its own log types from its subsystems. These types are not accepted as a filter argument to enable_logging (which only recognizes the core types listed earlier). Instead, enable logging without a type filter and select the subsystem you are interested in through the type column of sdb_logs — for example SELECT * FROM sdb_logs WHERE type = 'Search' to see only search-engine activity.
| Log Type | Description |
|---|---|
Startup | Server startup and initialization: endpoints, role creation, readiness |
Search | Inverted-index (search engine) activity: background refresh and compaction, index maintenance |
IResearch | Low-level events from the underlying IResearch engine |
Storage | Storage-engine events |
SSL | TLS/SSL configuration and connection events |
HTTP | HTTP traffic (shared with the core HTTP type above) |
Server log messages that are not assigned a type fall into the default (empty) type, so they appear in sdb_logs with an empty type and are always shown when logging is enabled without a type filter.
Log Storages
By default, SereneDB logs to an in-memory log storage (memory). SereneDB supports different types of log storage. Currently,
the following log storage types are implemented in core SereneDB.
| Log Storage | Description |
|---|---|
memory | (default) Log to an in-memory buffer |
stdout | Log to the stdout of the current process (in CSV format) |
file | Log to (a) csv file(s) |
Note that the sdb_logs table function is automatically updated to target the currently active log storage. This means that switching
the log storage may influence what is returned by the sdb_logs function.
Logging to stdout
CALL enable_logging(storage = 'stdout');Success
Logging to File
CALL enable_logging(storage = 'file', storage_config = {'path': '${__TEST_DIR__}/path/to/store/logs'});Success
or using the equivalent shorthand:
CALL enable_logging(storage_path = '${__TEST_DIR__}/path/to/store/logs');Success
Advanced Usage
Normalized vs. Denormalized Logging
SereneDB's log storages can log in two ways: normalized vs. denormalized.
In denormalized logging, the log context information is appended directly to each log entry, while in normalized logging the log entries are stored separately with context_ids referencing the context information.
| Log Storage | Normalized |
|---|---|
memory | yes |
file | configurable |
stdout | no |
For file storage, you can switch between normalized and denormalized by providing a path ending in .csv (for normalized)
or without .csv (for denormalized). For file logging, denormalized is generally recommended since this increases performance
and reduces the total size of the logs. To configure normalization of file log storage:
-- normalized: creates `${__TEST_DIR__}/duckdb_log_contexts.csv` and `${__TEST_DIR__}/duckdb_log_entries.csv`CALL enable_logging(storage_path = '${__TEST_DIR__}');
-- denormalized: creates `${__TEST_DIR__}/logs.csv`CALL enable_logging(storage_path = '${__TEST_DIR__}/logs.csv');Success
Note that the difference between normalized and denormalized is typically hidden from users through the 'sdb_logs' function,
which automatically joins normalized tables into a single unified result. To illustrate, both configurations above will be
queryable using FROM sdb_logs; and will produce identical results.
Buffer Size
The log storage in SereneDB implements a buffering mechanism to optimize logging performance. This implementation introduces a potential delay between message logging and storage writing. This delay can obscure the actual message writing time, which is particularly problematic when debugging crashes, as messages generated immediately before a crash might not be written. To address this, the buffer size can be configured as follows:
CALL enable_logging(storage_config = {'buffer_size': 0});Success
or using the equivalent shorthand:
CALL enable_logging(storage_buffer_size = 0);Success
Note that the default buffer size is different for different log storages:
| Log Storage | Default buffer size |
|---|---|
memory | STANDARD_VECTOR_SIZE (2048) |
file | STANDARD_VECTOR_SIZE (2048) |
stdout | Disabled (0) |
So for example, if you want to increase your stdout logging performance, simply enable buffering to greatly (>10x) speed up
your logging:
CALL enable_logging(storage = 'stdout', storage_buffer_size = 2048);Success
Or imagine you are debugging a crash in SereneDB and you want to use the file logger to understand what's going on:
Simply disable the
buffering using:
CALL enable_logging(storage_path = '${__TEST_DIR__}/mylogs', storage_buffer_size = 0);Success
Syntactic Sugar
SereneDB contains some syntactic sugar to make common paths easier. For example, the following statements are all equal:
-- regular invocationCALL enable_logging(storage = 'file', storage_config = {'path': 'path/to/store/logs'});
-- using shorthand for common path storage config paramCALL enable_logging(storage = 'file', storage_path = 'path/to/store/logs');
-- omitting `storage = 'file'` -> is implied from presence of `storage_config`CALL enable_logging(storage_config = {'path': 'path/to/store/logs'});Success Success Success