Observability

NeuralCleave exposes 13 Prometheus metrics at /api/v1/metrics and emits structured JSON logs via ContextLogger. Both are available from startup with no extra configuration.

Prometheus metrics

All metrics are available at GET /api/v1/metrics in standard Prometheus text/plain format. Scrape it directly from prometheus.yml:

yaml
# prometheus.yml
scrape_configs:
  - job_name: neuralcleave
    static_configs:
      - targets: ["localhost:7432"]
    metrics_path: /api/v1/metrics
MetricTypeDescription
nc_requests_totalCounterTotal chat requests processed, labelled by channel and provider
nc_request_duration_secondsHistogramEnd-to-end request latency from receive to response delivery
nc_llm_tokens_input_totalCounterTotal input (prompt) tokens sent to LLM providers
nc_llm_tokens_output_totalCounterTotal output (completion) tokens received from LLM providers
nc_llm_errors_totalCounterLLM call failures, labelled by provider and error_type
nc_reflection_scoreGaugeMost recent ReflectionEngine quality score (0–100)
nc_reflection_retries_totalCounterResponses regenerated due to low reflection score
nc_memory_rows_totalGaugeCurrent SQLite long-term memory row count
nc_memory_compactions_totalCounterSession compaction events triggered
nc_active_sessionsGaugeWebSocket sessions currently connected
nc_plugin_tool_calls_totalCounterPlugin tool invocations, labelled by plugin and tool
nc_channel_messages_totalCounterInbound messages per channel adapter
nc_orchestrator_routes_totalCounterOrchestrator routing decisions, labelled by node and task_type

Example metric output

text
# HELP nc_requests_total Total chat requests processed
# TYPE nc_requests_total counter
nc_requests_total{channel="telegram",provider="anthropic"} 1432
nc_requests_total{channel="discord",provider="anthropic"} 87

# HELP nc_request_duration_seconds Request duration
# TYPE nc_request_duration_seconds histogram
nc_request_duration_seconds_bucket{le="0.5"} 112
nc_request_duration_seconds_bucket{le="1.0"} 876
nc_request_duration_seconds_bucket{le="2.0"} 1401
nc_request_duration_seconds_sum 2843.7
nc_request_duration_seconds_count 1519

# HELP nc_reflection_score Latest reflection quality score
# TYPE nc_reflection_score gauge
nc_reflection_score 91

Structured logging

The gateway uses ContextLogger, which wraps Python's standard logging with a JsonFormatter. Every log line is a JSON object with standard fields:

json
{
  "time":       "2026-07-21T14:23:01.412Z",
  "level":      "INFO",
  "logger":     "neuralcleave.gateway",
  "message":    "Chat request complete",
  "session_id": "abc123",
  "channel":    "telegram",
  "provider":   "anthropic",
  "duration_ms": 847,
  "tokens":     {"input": 143, "output": 89},
  "quality":    91
}

Log level

Set in config.toml under [gateway]:

toml
[gateway]
log_level = "DEBUG"  # DEBUG | INFO | WARNING | ERROR

Or pass at launch:

bash
neuralcleave start --log-level DEBUG

Using ContextLogger in plugins

Plugins get a pre-configured logger via the setup() context. Use it to emit structured fields alongside the message:

python
from neuralcleave.logging import get_logger

logger = get_logger("neuralcleave_weather")

async def execute(self, city: str):
    logger.info("weather_lookup", city=city)
    result = await fetch_weather(city)
    logger.info("weather_result", city=city, temp=result["temp"])
    return ToolResult(success=True, data=result)

Grafana dashboard

A pre-built Grafana dashboard JSON is in deploy/grafana/neuralcleave-dashboard.json. Import it into any Grafana instance pointed at the Prometheus scrape target above. The dashboard includes panels for: request rate, p50/p99 latency, token usage, reflection score distribution, and per-channel message volume.