How to Configure Logging
Enable debug logging for troubleshooting, capture audit events, and scrape Prometheus metrics.
This page targets core engine 2.0.3 (the sochdb-grpc-server binary). SDK logging snippets use Python SDK 0.5.9 and Node.js SDK 0.5.3.
Problem
You need to see what SochDB is doing internally for debugging, capture audit logs for compliance, or expose runtime metrics to Prometheus.
Solution
1. RUST_LOG (the engine's only log filter)
The sochdb-grpc-server binary uses tracing with an EnvFilter built from the RUST_LOG environment variable. There is no [logging] config-file section and no JSON/file/rotation options in the server today — RUST_LOG (plus the --debug flag below) is the control surface.
# Everything at debug
export RUST_LOG=debug
# Just the gRPC server crate at debug
export RUST_LOG=sochdb_grpc=debug
# A specific module only (note: Rust targets use underscores)
export RUST_LOG=sochdb_storage::wal=debug
# Mix per-crate levels
export RUST_LOG=info,sochdb_grpc=debug,sochdb_index::hnsw=trace
# Trace everything (very verbose)
export RUST_LOG=trace
Workspace crates you can target (directory names use hyphens, but RUST_LOG targets use underscores): sochdb_grpc, sochdb_kernel, sochdb_storage, sochdb_index, sochdb_query, sochdb_memory, sochdb_mcp.
RUST_LOG must be set before the process starts. If RUST_LOG is unset, the server falls back to a default level (see --debug below). The standard tracing_subscriber::EnvFilter syntax applies: target=level, comma-separated, with an optional bare default level.
2. The --debug flag
The server exposes a single boolean flag that changes the default filter:
# Default filter becomes "info"
sochdb-grpc-server
# Default filter becomes "debug" (-d is the short form)
sochdb-grpc-server --debug
| State | Default filter (when RUST_LOG is unset) |
|---|---|
| no flag | info |
--debug / -d | debug |
RUST_LOG always wins. If RUST_LOG is set, it overrides whatever --debug would have chosen. Use --debug for a quick bump and RUST_LOG for fine-grained, per-module control.
3. Audit logging
Audit logging is on by default in the server's security layer (audit_enabled: true). Each entry is emitted through tracing under the audit target, so audit records show up in the same stdout/stderr stream as normal logs — there is no separate audit file in the default binary.
Entries are buffered and flushed every audit_flush_threshold (default 100) records. The AuditLogEntry JSON shape is fixed:
{"timestamp":1733911932,"principal_id":"app_service","tenant_id":"default","action":"kv_put","resource":"users","result":"success","request_id":"req-42","client_ip":"10.0.0.7"}
result is one of success, failure, or denied. To isolate audit records, filter on the target:
export RUST_LOG=info,audit=info
sochdb-grpc-server | grep '"action"'
The AuditLogger::with_log_path(threshold, path) constructor can persist audit entries to a dedicated file, but the sochdb-grpc-server binary does not expose a CLI flag for it — it always uses the in-memory + tracing logger. There is also no configurable list of audited event types; the logger records whatever actions the security layer reports.
4. Prometheus metrics (/metrics on port 9090)
The server runs a dedicated Prometheus HTTP endpoint on its own OS thread (sochdb-metrics-http), separate from the gRPC port.
# Default metrics port is 9090
sochdb-grpc-server
# Override the port
sochdb-grpc-server --metrics-port 9100
# Disable the metrics endpoint entirely
sochdb-grpc-server --metrics-port 0
Endpoints (bound to 0.0.0.0:<metrics-port>):
| Method + Path | Purpose |
|---|---|
GET /metrics | Prometheus text exposition (version=0.0.4) |
GET /health | Liveness probe, returns 200 OK |
| anything else | 404 |
--auth/metrics and /health are served by a plain HTTP listener with no authentication, intended for in-cluster scraping and probes. Keep the metrics port on a trusted network or behind your ingress.
Scrape config:
scrape_configs:
- job_name: sochdb
static_configs:
- targets: ["sochdb:9090"]
A representative sample of exported series (HNSW index metrics are auto-included via the default registry):
sochdb_grpc_requests_total{service,method}
sochdb_grpc_errors_total{service,method,code}
sochdb_grpc_request_duration_seconds
sochdb_grpc_active_connections
sochdb_sql_queries_total{statement_type}
sochdb_sql_query_duration_seconds
sochdb_transactions_total{outcome}
sochdb_tables_count
sochdb_storage_bytes
sochdb_wal_bytes
sochdb_wal_writes_total
sochdb_wal_fsync_total
sochdb_cache_operations_total{result}
sochdb_uptime_seconds
sochdb_build_info{version,rustc}
Use sochdb_build_info to confirm the running engine version (it carries a version label, e.g. 2.0.3).
5. SDK-side logging
The language SDKs log through their host runtime's standard logging facilities — they do not read RUST_LOG.
- Python (SDK 0.5.9)
- Node.js (SDK 0.5.3)
- Rust (in-process engine)
import logging
# Turn on debug logging for the sochdb SDK logger
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("sochdb")
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler("sochdb-client.log")
handler.setFormatter(logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
))
logger.addHandler(handler)
// The Node SDK logs via console; raise verbosity at the app level.
// When running an embedded engine build, RUST_LOG controls the native layer.
process.env.RUST_LOG = "sochdb_grpc=debug";
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
fn setup_logging() {
let filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::registry()
.with(filter)
.with(tracing_subscriber::fmt::layer())
.init();
}
Example Output
Default (info) startup
2026-06-13T10:15:30.001Z INFO sochdb_grpc::metrics_server: Prometheus metrics server listening on http://0.0.0.0:9090/metrics
2026-06-13T10:15:30.010Z INFO sochdb_grpc: Authentication disabled (use --auth to enable)
2026-06-13T10:15:30.011Z INFO sochdb_grpc: Starting SochDB gRPC server on 127.0.0.1:50051
2026-06-13T10:15:30.011Z INFO sochdb_grpc: Server version: 2.0.3
Debug (--debug or RUST_LOG=debug)
2026-06-13T10:15:32.123Z DEBUG sochdb_storage::wal: Appending record: txn_id=42, size=1024
2026-06-13T10:15:32.124Z DEBUG sochdb_kernel: Snapshot created: ts=1000042
2026-06-13T10:15:32.125Z DEBUG sochdb_index::hnsw: Search: k=10, ef=500, candidates=127
Audit record (emitted on the audit target)
{"timestamp":1733911932,"principal_id":"app_service","tenant_id":"default","action":"transaction_commit","resource":"orders","result":"success","request_id":"req-42","client_ip":null}
Discussion
Log Levels
| Level | Use Case | Performance Impact |
|---|---|---|
error | Production (critical only) | Minimal |
warn | Production (with warnings) | Minimal |
info | Production (recommended, the default) | Low |
debug | Development / troubleshooting | Moderate |
trace | Deep debugging only | High |
The sochdb-plugin-logging crate
The workspace ships an example plugin, sochdb-plugin-logging (JsonLoggingPlugin), that implements the kernel's ObservabilityExtension trait and emits structured JSON logs, metrics, and spans. It demonstrates the plugin architecture and is registered programmatically:
use sochdb_kernel::PluginManager;
use sochdb_plugin_logging::JsonLoggingPlugin;
use std::sync::Arc;
let plugins = PluginManager::new();
let logging = JsonLoggingPlugin::new();
plugins.register_observability(Arc::new(logging))?;
sochdb-plugin-logging is an embedded-engine plugin, not part of the sochdb-grpc-server binary's request logging. The server itself logs via tracing (see above). The plugin is AGPL-3.0-or-later, like the rest of the core engine.
Performance Considerations
- Higher verbosity (
debug/trace) adds overhead; scope it to specific modules withRUST_LOG=target=levelrather than enabling globally. - Audit entries are batched (flush threshold 100) to keep the hot path cheap.
- Scraping
/metricsis cheap, but very high scrape frequencies still cost CPU to encode the registry — 10–15s intervals are typical.
Security Notes
- Audit logs include
principal_id,tenant_id, andclient_ip— treat them as sensitive and ship to a SIEM. - The
/metricsand/healthendpoints have no authentication; keep the metrics port off the public internet. - Avoid running with global
tracein production — it can surface keys/values that appear in lower-level traces.
See Also
- gRPC Server — Server flags and ports
- Profiling Guide — Performance analysis
- Deployment Guide — Production setup
- Performance Guide — Optimization tips