Resolves naming conflict with RelayHealthState::Degraded by using a more explicit name that clearly indicates the connection status relates to historic sync failures, not connection health degradation. Changes: - ConnectionStatus::ConnectedDegraded → ConnectedHistoricSyncFailures - Updated all documentation and comments - Updated Prometheus metric descriptions - Metric value remains 4 for backward compatibility This makes it clear that: - ConnectedHistoricSyncFailures = connection lifecycle (missing historic data) - RelayHealthState::Degraded = connection health (reliability issues) These are orthogonal concerns - a relay can be ConnectedHistoricSyncFailures but Healthy, or Connected but Degraded.
7.4 KiB
Monitoring
ngit-grasp exposes Prometheus metrics at /metrics for monitoring WebSocket connections, Git operations, Nostr events, and system health.
Architecture
flowchart TB
subgraph ngit-grasp
HTTP[HTTP Service]
WS[WebSocket Handler]
GIT[Git Handlers]
RELAY[Nostr Relay]
subgraph Metrics Module
REG[Prometheus Registry]
CT[ConnectionTracker]
MC[Metric Counters]
end
ME[/metrics endpoint]
end
subgraph External
PROM[Prometheus Server]
GRAF[Grafana]
ADMIN[Admin Browser]
end
HTTP --> ME
WS --> CT
WS --> MC
GIT --> MC
RELAY --> MC
CT --> REG
MC --> REG
REG --> ME
PROM -->|scrape /metrics| ME
GRAF -->|query| PROM
ADMIN -->|view dashboards| GRAF
Configuration
| Option | CLI Flag | Environment Variable | Default | Description |
|---|---|---|---|---|
| Metrics enabled | --metrics-enabled |
NGIT_METRICS_ENABLED |
true |
Enable /metrics endpoint |
| Abuse threshold | --abuse-threshold |
NGIT_ABUSE_THRESHOLD |
10 |
Max connections per IP before flagging |
| Top N repos | --top-n-repos |
NGIT_TOP_N_REPOS |
10 |
Number of top bandwidth repos to track |
Privacy Model
IP addresses are never exposed in Prometheus metrics. The connection tracker maintains per-IP counts internally only for abuse detection:
| Data | Exposed in Metrics? |
|---|---|
| Total connections | ✅ Yes |
| Unique IP count | ✅ Yes |
| Flagged abuser count | ✅ Yes |
| Actual IP addresses | ❌ No (internal only) |
| IP + abuse flag | ⚠️ Logs only (when flagged) |
When an IP exceeds the abuse threshold, a warning is logged but the IP is never exposed via Prometheus.
Deployment
See Prometheus Setup Guide for NixOS configuration and Grafana dashboard provisioning.
Future: Load-Based Sync Scheduling (GRASP-02)
The metrics infrastructure enables future load-based scheduling for GRASP-02 sync jobs:
flowchart TD
SYNC[Sync Manager] --> CHECK{Check Load}
CHECK --> MET[Query Metrics]
MET --> CONN{Connections > N?}
CONN -->|Yes| DELAY[Delay 5 min]
CONN -->|No| RUN[Run Sync Job]
DELAY --> CHECK
Future: Loki for Detailed Logging
For detailed per-repository investigation at scale, consider adding Loki (log aggregation):
- Structured logging with tracing crate already in place
- Loki queries enable ad-hoc deep dives (e.g., find all transfers > 10MB)
- Pairs with Prometheus for long-term trends
Sync Metrics (GRASP-02)
When GRASP-02 proactive sync is implemented, the following metrics will be added to track relay synchronization health. These metrics use in-memory tracking with Prometheus for operator visibility (no database persistence needed for <100 relays).
Sync Metrics Overview
| Metric | Type | Labels | Description |
|---|---|---|---|
ngit_sync_relay_connected |
Gauge | relay | Connection status (0=disconnected, 1=connecting, 2=syncing, 3=connected, 4=connected_historic_sync_failures) |
ngit_sync_connection_attempts_total |
Counter | relay, result | Connection attempt outcomes |
ngit_sync_relay_status |
Gauge | relay | Health status (1=healthy, 2=disconnected, 3=degraded, 4=dead, 5=rate_limited) |
ngit_sync_relay_failures |
Gauge | relay | Current consecutive failure count |
ngit_sync_events_synced_total |
Counter | - | Events synced (newly saved events only) |
ngit_sync_relays_tracked_total |
Gauge | - | Total relays discovered |
ngit_sync_relays_connected_total |
Gauge | - | Currently connected relay count |
ngit_sync_relays_dead_total |
Gauge | - | Relays marked as dead |
Connection Status Values
The ngit_sync_relay_connected metric tracks the connection lifecycle:
0= Disconnected - Not currently connected1= Connecting - Connection attempt in progress2= Syncing - Connected, historic sync in progress3= Connected - Connected, historic sync complete, live sync active4= ConnectedHistoricSyncFailures - Connected, historic sync had failures, live sync active, partial data
This allows operators to distinguish between "connected but still catching up" (Syncing) vs "fully synced and live" (Connected) vs "historic sync failures - missing historic data" (ConnectedHistoricSyncFailures).
Relay Health States
The ngit_sync_relay_status metric tracks relay health:
1= Healthy - Connected and stable2= Disconnected - Not connected, but no issues detected3= Degraded - Connection problems or unstable after recovery4= Dead - 24h+ of continuous failures5= RateLimited - Rate limit cooldown active (65s)
Example Grafana Queries
# Relay connection status overview - count by status
sum by (relay) (ngit_sync_relay_connected == 0) # Disconnected
sum by (relay) (ngit_sync_relay_connected == 1) # Connecting
sum by (relay) (ngit_sync_relay_connected == 2) # Syncing
sum by (relay) (ngit_sync_relay_connected == 3) # Connected
sum by (relay) (ngit_sync_relay_connected == 4) # ConnectedHistoricSyncFailures
# Relays still syncing (not yet fully caught up)
count(ngit_sync_relay_connected == 2)
# Relays with historic sync failures (missing historic data)
count(ngit_sync_relay_connected == 4)
# Connection success rate over last hour
sum(rate(ngit_sync_connection_attempts_total{result="success"}[1h]))
/ sum(rate(ngit_sync_connection_attempts_total[1h]))
# Event sync rate (newly saved events)
rate(ngit_sync_events_synced_total[5m])
# Relays with high failure counts (potential issues)
topk(10, ngit_sync_relay_failures)
# Relay health overview - count by health state
sum(ngit_sync_relay_status == 1) # Healthy
sum(ngit_sync_relay_status == 2) # Disconnected
sum(ngit_sync_relay_status == 3) # Degraded
sum(ngit_sync_relay_status == 4) # Dead
sum(ngit_sync_relay_status == 5) # RateLimited
Example Alerts
# Alert if relay stuck in dead state for > 1 day
- alert: SyncRelayDead
expr: ngit_sync_relay_status == 4 # Dead state
for: 1d
labels:
severity: warning
annotations:
summary: "Sync relay {{ $labels.relay }} is dead (24h+ failures)"
# Alert if relay stuck in syncing state for > 1 hour
- alert: SyncRelaySlow
expr: ngit_sync_relay_connected == 2 # Syncing state
for: 1h
labels:
severity: info
annotations:
summary: "Sync relay {{ $labels.relay }} taking >1h to complete historic sync"
# Alert if too many relays are degraded
- alert: SyncManyDegraded
expr: sum(ngit_sync_relay_status == 3) > 5 # Degraded state
for: 15m
labels:
severity: warning
annotations:
summary: "{{ $value }} relays in degraded state"
Design Rationale
In-memory health tracking with Prometheus visibility was chosen over database persistence because:
- Scale: <100 relays means per-relay labels have acceptable cardinality
- Simplicity: No database schema, migrations, or cleanup needed
- Operator visibility: Prometheus + Grafana provide better dashboards than custom queries
- Restart behavior: Conservative initial backoff (5s + jitter) avoids thundering herd on restart
- Historical data: Prometheus retains health history; in-memory state only needs current status
See GRASP-02 Proactive Sync for full architecture details.