package metrics import ( "net/http" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" ) // Metrics holds all Prometheus collectors for the honeypot. type Metrics struct { registry *prometheus.Registry SSHConnectionsTotal *prometheus.CounterVec SSHConnectionsActive prometheus.Gauge AuthAttemptsTotal *prometheus.CounterVec SessionsTotal *prometheus.CounterVec SessionsActive prometheus.Gauge SessionDuration prometheus.Histogram BuildInfo *prometheus.GaugeVec } // New creates a new Metrics instance with all collectors registered. func New(version string) *Metrics { reg := prometheus.NewRegistry() m := &Metrics{ registry: reg, SSHConnectionsTotal: prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "oubliette_ssh_connections_total", Help: "Total SSH connections received.", }, []string{"outcome"}), SSHConnectionsActive: prometheus.NewGauge(prometheus.GaugeOpts{ Name: "oubliette_ssh_connections_active", Help: "Current active SSH connections.", }), AuthAttemptsTotal: prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "oubliette_auth_attempts_total", Help: "Total authentication attempts.", }, []string{"result", "reason"}), SessionsTotal: prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "oubliette_sessions_total", Help: "Total sessions created.", }, []string{"shell"}), SessionsActive: prometheus.NewGauge(prometheus.GaugeOpts{ Name: "oubliette_sessions_active", Help: "Current active sessions.", }), SessionDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ Name: "oubliette_session_duration_seconds", Help: "Session duration in seconds.", Buckets: []float64{1, 5, 10, 30, 60, 120, 300, 600, 1800, 3600}, }), BuildInfo: prometheus.NewGaugeVec(prometheus.GaugeOpts{ Name: "oubliette_build_info", Help: "Build information. Always 1.", }, []string{"version"}), } reg.MustRegister( collectors.NewGoCollector(), collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}), m.SSHConnectionsTotal, m.SSHConnectionsActive, m.AuthAttemptsTotal, m.SessionsTotal, m.SessionsActive, m.SessionDuration, m.BuildInfo, ) m.BuildInfo.WithLabelValues(version).Set(1) // Initialize label combinations so they appear in Gather/output. for _, outcome := range []string{"accepted", "rejected_handshake", "rejected_max_connections"} { m.SSHConnectionsTotal.WithLabelValues(outcome) } for _, reason := range []string{"static_credential", "remembered_credential", "threshold_reached", "rejected"} { m.AuthAttemptsTotal.WithLabelValues("accepted", reason) m.AuthAttemptsTotal.WithLabelValues("rejected", reason) } for _, shell := range []string{"bash", "fridge", "banking", "adventure"} { m.SessionsTotal.WithLabelValues(shell) } return m } // Handler returns an http.Handler that serves Prometheus metrics. func (m *Metrics) Handler() http.Handler { return promhttp.HandlerFor(m.registry, promhttp.HandlerOpts{}) }