Skip to main content

How to Configure Logging

Enable debug logging for troubleshooting, capture audit events, and scrape Prometheus metrics.

Versions

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.

note

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
StateDefault filter (when RUST_LOG is unset)
no flaginfo
--debug / -ddebug
important

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"'
Audit files are a library API, not a CLI flag

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 + PathPurpose
GET /metricsPrometheus text exposition (version=0.0.4)
GET /healthLiveness probe, returns 200 OK
anything else404
The metrics endpoint is not behind --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.

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)

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

LevelUse CasePerformance Impact
errorProduction (critical only)Minimal
warnProduction (with warnings)Minimal
infoProduction (recommended, the default)Low
debugDevelopment / troubleshootingModerate
traceDeep debugging onlyHigh

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))?;
note

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 with RUST_LOG=target=level rather than enabling globally.
  • Audit entries are batched (flush threshold 100) to keep the hot path cheap.
  • Scraping /metrics is 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, and client_ip — treat them as sensitive and ship to a SIEM.
  • The /metrics and /health endpoints have no authentication; keep the metrics port off the public internet.
  • Avoid running with global trace in production — it can surface keys/values that appear in lower-level traces.

See Also