// Package observability provides logging and metrics infrastructure package observability import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) // Metrics defines the metrics collection interface type Metrics interface { // RecordSwapEvent records a swap event being processed RecordSwapEvent(protocol string, success bool) // RecordParseLatency records parsing latency in seconds RecordParseLatency(protocol string, latencySeconds float64) // RecordArbitrageOpportunity records an arbitrage opportunity RecordArbitrageOpportunity(profit float64) // RecordExecution records a trade execution RecordExecution(success bool, netProfit float64) // IncrementPoolCacheSize increments the pool cache size IncrementPoolCacheSize() // DecrementPoolCacheSize decrements the pool cache size DecrementPoolCacheSize() } // prometheusMetrics implements Metrics using Prometheus type prometheusMetrics struct { swapEventsTotal *prometheus.CounterVec parseLatency *prometheus.HistogramVec arbitrageOpportunities *prometheus.CounterVec arbitrageProfit *prometheus.HistogramVec executionsTotal *prometheus.CounterVec executionProfit *prometheus.HistogramVec poolCacheSize prometheus.Gauge } // NewMetrics creates a new Prometheus metrics collector func NewMetrics(namespace string) Metrics { return &prometheusMetrics{ swapEventsTotal: promauto.NewCounterVec( prometheus.CounterOpts{ Namespace: namespace, Name: "swap_events_total", Help: "Total number of swap events processed", }, []string{"protocol", "status"}, ), parseLatency: promauto.NewHistogramVec( prometheus.HistogramOpts{ Namespace: namespace, Name: "parse_latency_seconds", Help: "Latency of parsing swap events in seconds", Buckets: []float64{0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0}, }, []string{"protocol"}, ), arbitrageOpportunities: promauto.NewCounterVec( prometheus.CounterOpts{ Namespace: namespace, Name: "arbitrage_opportunities_total", Help: "Total number of arbitrage opportunities detected", }, []string{"status"}, ), arbitrageProfit: promauto.NewHistogramVec( prometheus.HistogramOpts{ Namespace: namespace, Name: "arbitrage_profit_eth", Help: "Arbitrage profit in ETH", Buckets: []float64{0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0}, }, []string{"status"}, ), executionsTotal: promauto.NewCounterVec( prometheus.CounterOpts{ Namespace: namespace, Name: "executions_total", Help: "Total number of trade executions", }, []string{"status"}, ), executionProfit: promauto.NewHistogramVec( prometheus.HistogramOpts{ Namespace: namespace, Name: "execution_profit_eth", Help: "Execution profit in ETH (after gas)", Buckets: []float64{-1.0, -0.1, -0.01, 0, 0.01, 0.1, 1.0, 10.0}, }, []string{"status"}, ), poolCacheSize: promauto.NewGauge( prometheus.GaugeOpts{ Namespace: namespace, Name: "pool_cache_size", Help: "Current number of pools in cache", }, ), } } func (m *prometheusMetrics) RecordSwapEvent(protocol string, success bool) { status := "success" if !success { status = "failure" } m.swapEventsTotal.WithLabelValues(protocol, status).Inc() } func (m *prometheusMetrics) RecordParseLatency(protocol string, latencySeconds float64) { m.parseLatency.WithLabelValues(protocol).Observe(latencySeconds) } func (m *prometheusMetrics) RecordArbitrageOpportunity(profit float64) { m.arbitrageOpportunities.WithLabelValues("detected").Inc() m.arbitrageProfit.WithLabelValues("detected").Observe(profit) } func (m *prometheusMetrics) RecordExecution(success bool, netProfit float64) { status := "success" if !success { status = "failure" } m.executionsTotal.WithLabelValues(status).Inc() m.executionProfit.WithLabelValues(status).Observe(netProfit) } func (m *prometheusMetrics) IncrementPoolCacheSize() { m.poolCacheSize.Inc() } func (m *prometheusMetrics) DecrementPoolCacheSize() { m.poolCacheSize.Dec() }