watchdog/internal/aggregate/metrics.go
NotAShelf bc4d3fed53
internal: initial metrics aggregator
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I9cdd6e2b33bb65182568db9db4460bc46a6a6964
2026-03-02 22:37:53 +03:00

101 lines
2.5 KiB
Go

package aggregate
import (
"github.com/prometheus/client_golang/prometheus"
"notashelf.dev/watchdog/internal/config"
)
// Records analytics events as Prometheus metrics
type MetricsAggregator struct {
registry *PathRegistry
cfg config.Config
pageviews *prometheus.CounterVec
customEvents *prometheus.CounterVec
pathOverflow prometheus.Counter
}
// Creates a new metrics aggregator with dynamic labels based on config
func NewMetricsAggregator(registry *PathRegistry, cfg config.Config) *MetricsAggregator {
// Build label names based on what's enabled in config
labels := []string{"path"} // path is always included
if cfg.Site.Collect.Country {
labels = append(labels, "country")
}
if cfg.Site.Collect.Device {
labels = append(labels, "device")
}
if cfg.Site.Collect.Referrer != "off" {
labels = append(labels, "referrer")
}
pageviews := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "web_pageviews_total",
Help: "Total number of pageviews",
},
labels,
)
customEvents := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "web_custom_events_total",
Help: "Total number of custom events",
},
[]string{"event"},
)
pathOverflow := prometheus.NewCounter(
prometheus.CounterOpts{
Name: "web_path_overflow_total",
Help: "Paths rejected due to cardinality limit",
},
)
return &MetricsAggregator{
registry: registry,
cfg: cfg,
pageviews: pageviews,
customEvents: customEvents,
pathOverflow: pathOverflow,
}
}
// Records a pageview with the configured dimensions
func (m *MetricsAggregator) RecordPageview(path, country, device, referrer string) {
// Build label values in the same order as label names
labels := prometheus.Labels{"path": path}
if m.cfg.Site.Collect.Country {
labels["country"] = country
}
if m.cfg.Site.Collect.Device {
labels["device"] = device
}
if m.cfg.Site.Collect.Referrer != "off" {
labels["referrer"] = referrer
}
m.pageviews.With(labels).Inc()
}
// Records a custom event
func (m *MetricsAggregator) RecordCustomEvent(eventName string) {
m.customEvents.With(prometheus.Labels{"event": eventName}).Inc()
}
// Records a path that was rejected due to cardinality limits
func (m *MetricsAggregator) RecordPathOverflow() {
m.pathOverflow.Inc()
}
// Registers all metrics with the provided Prometheus registry
func (m *MetricsAggregator) MustRegister(reg prometheus.Registerer) {
reg.MustRegister(m.pageviews)
reg.MustRegister(m.customEvents)
reg.MustRegister(m.pathOverflow)
}