From 71f7a444398275923246e1bc8283938a63a8267a Mon Sep 17 00:00:00 2001 From: bndw Date: Sun, 15 Feb 2026 08:22:03 -0800 Subject: feat: add metrics for blocked events Track and display blocked event counts with per-kind breakdown. - Add events_blocked_total counter with kind label - Add RecordBlockedEvent method to metrics - Display blocked count in dashboard Storage section - Call metric when rejecting non-core protocol kinds Allows monitoring spam patterns and verifying kind filter effectiveness. Raw metrics show breakdown by kind (e.g., kind=20001, kind=30311). --- internal/handler/websocket/handler.go | 4 ++++ internal/metrics/dashboard.html | 7 +++++++ internal/metrics/metrics.go | 17 +++++++++++++++++ 3 files changed, 28 insertions(+) (limited to 'internal') diff --git a/internal/handler/websocket/handler.go b/internal/handler/websocket/handler.go index 8daa89f..35d0aea 100644 --- a/internal/handler/websocket/handler.go +++ b/internal/handler/websocket/handler.go @@ -33,6 +33,7 @@ type MetricsRecorder interface { DecrementSubscriptions() SetActiveSubscriptions(count int) RecordRequest(method, status string, duration float64) + RecordBlockedEvent(kind int32) } type RateLimiter interface { @@ -302,6 +303,9 @@ func (h *Handler) handleEvent(ctx context.Context, conn *websocket.Conn, raw []j // Reject non-core protocol kinds (spam, ephemeral, chat) if !isAllowedKind(pbEvent.Kind) { status = "ok" + if h.metrics != nil { + h.metrics.RecordBlockedEvent(pbEvent.Kind) + } h.sendOK(ctx, conn, event.ID, true, "rejected: kind not supported") return nil } diff --git a/internal/metrics/dashboard.html b/internal/metrics/dashboard.html index 9538ac6..1fa1ddf 100644 --- a/internal/metrics/dashboard.html +++ b/internal/metrics/dashboard.html @@ -199,6 +199,10 @@ Deletions 0 +
+ Blocked + 0 +
@@ -317,6 +321,9 @@ document.getElementById('event_deletions').textContent = sumMetric(metrics, `${prefix}_relay_event_deletions_total`); + document.getElementById('events_blocked').textContent = + sumMetric(metrics, `${prefix}_relay_events_blocked_total`); + const durationSum = sumMetric(metrics, `${prefix}_relay_request_duration_seconds_sum`); const durationCount = sumMetric(metrics, `${prefix}_relay_request_duration_seconds_count`); const avgLatencyMs = durationCount > 0 ? (durationSum / durationCount * 1000) : 0; diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 74f9ffb..dea0748 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -2,6 +2,7 @@ package metrics import ( _ "embed" + "fmt" "net/http" "github.com/prometheus/client_golang/prometheus" @@ -30,6 +31,7 @@ type Metrics struct { eventsTotal prometheus.Gauge dbSizeBytes prometheus.Gauge eventDeletionsTotal prometheus.Counter + eventsBlockedTotal *prometheus.CounterVec // Config config *Config @@ -195,6 +197,16 @@ func New(config *Config) *Metrics { }, ) + m.eventsBlockedTotal = promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: config.Namespace, + Subsystem: config.Subsystem, + Name: "events_blocked_total", + Help: "Total events blocked by kind filter", + }, + []string{"kind"}, + ) + return m } @@ -274,6 +286,11 @@ func (m *Metrics) RecordEventDeletion() { m.eventDeletionsTotal.Inc() } +// RecordBlockedEvent records an event blocked by kind filter. +func (m *Metrics) RecordBlockedEvent(kind int32) { + m.eventsBlockedTotal.WithLabelValues(fmt.Sprintf("%d", kind)).Inc() +} + // RequestStatus represents the status of a request for metrics. type RequestStatus string -- cgit v1.2.3