Files
zeekayandHanzo Dev 64519916bf the corporate name is Lux Industries Inc
Lux Partners Limited is not the entity behind this work. Every place the
old name stood — copyright lines, site footers, brand config, legal and
compliance text — now names the company that actually holds it.

lux.fund is the exception and is not renamed to match: that site belongs
to Lux Assets Management LLC, a different company, and it says so.

Two kinds of line were left for a person rather than rewritten. A dated
news item recording that Lux Partners Limited was established in the Isle
of Man is a historical fact, and renaming it would falsify the record. And
a sentence asserting that the company is domiciled in the Isle of Man is a
claim about a jurisdiction, not a name — an Inc or an LLC is not an Isle
of Man company, so swapping the name there would assert something untrue.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-28 13:01:04 -07:00

167 lines
6.2 KiB
Go

// Copyright (c) 2025 Lux Industries Inc
// SPDX-License-Identifier: MIT
// Package stats provides Prometheus metrics export for blockchain statistics.
package stats
import (
"context"
"fmt"
"net/http"
"sync"
"time"
)
// MetricsExporter exports statistics as Prometheus metrics
type MetricsExporter struct {
service *Service
mu sync.RWMutex
metrics map[string]float64
}
// NewMetricsExporter creates a new Prometheus metrics exporter
func NewMetricsExporter(service *Service) *MetricsExporter {
return &MetricsExporter{
service: service,
metrics: make(map[string]float64),
}
}
// UpdateMetrics refreshes all metric values
func (m *MetricsExporter) UpdateMetrics(ctx context.Context) error {
// Get counters
counters, err := m.service.GetCounters(ctx)
if err != nil {
return fmt.Errorf("get counters: %w", err)
}
// Get gas prices
gasPrices, err := m.service.GetGasPrices(ctx)
if err != nil {
return fmt.Errorf("get gas prices: %w", err)
}
// Get block time
blockTime, err := m.service.GetAverageBlockTime(ctx)
if err != nil {
return fmt.Errorf("get block time: %w", err)
}
m.mu.Lock()
defer m.mu.Unlock()
// Counter metrics
m.metrics["lux_indexer_blocks_total"] = float64(counters.TotalBlocks)
m.metrics["lux_indexer_transactions_total"] = float64(counters.TotalTransactions)
m.metrics["lux_indexer_addresses_total"] = float64(counters.TotalAddresses)
m.metrics["lux_indexer_contracts_total"] = float64(counters.TotalContracts)
m.metrics["lux_indexer_tokens_total"] = float64(counters.TotalTokens)
m.metrics["lux_indexer_token_transfers_total"] = float64(counters.TotalTokenTransfers)
m.metrics["lux_indexer_verified_contracts_total"] = float64(counters.VerifiedContracts)
m.metrics["lux_indexer_tps_24h"] = counters.TPS24h
m.metrics["lux_indexer_gas_used_24h"] = float64(counters.GasUsed24h)
// Gas price metrics
if gasPrices.Slow != nil {
m.metrics["lux_indexer_gas_price_slow_gwei"] = gasPrices.Slow.Price
m.metrics["lux_indexer_gas_time_slow_ms"] = gasPrices.Slow.Time
}
if gasPrices.Average != nil {
m.metrics["lux_indexer_gas_price_average_gwei"] = gasPrices.Average.Price
m.metrics["lux_indexer_gas_time_average_ms"] = gasPrices.Average.Time
}
if gasPrices.Fast != nil {
m.metrics["lux_indexer_gas_price_fast_gwei"] = gasPrices.Fast.Price
m.metrics["lux_indexer_gas_time_fast_ms"] = gasPrices.Fast.Time
}
m.metrics["lux_indexer_gas_used_ratio"] = gasPrices.GasUsedRatio
// Block time metrics
m.metrics["lux_indexer_block_time_seconds"] = blockTime.AverageBlockTime.Seconds()
m.metrics["lux_indexer_block_time_min_seconds"] = blockTime.MinBlockTime.Seconds()
m.metrics["lux_indexer_block_time_max_seconds"] = blockTime.MaxBlockTime.Seconds()
return nil
}
// ServeHTTP implements http.Handler for Prometheus metrics endpoint
func (m *MetricsExporter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
m.mu.RLock()
defer m.mu.RUnlock()
w.Header().Set("Content-Type", "text/plain; version=0.0.4; charset=utf-8")
// Write metrics in Prometheus exposition format
for name, value := range m.metrics {
fmt.Fprintf(w, "%s %g\n", name, value)
}
// Add metadata metrics
fmt.Fprintf(w, "lux_indexer_last_update_timestamp %d\n", time.Now().Unix())
}
// StartBackgroundUpdater starts a goroutine to periodically update metrics
func (m *MetricsExporter) StartBackgroundUpdater(ctx context.Context, interval time.Duration) {
ticker := time.NewTicker(interval)
go func() {
// Initial update
m.UpdateMetrics(ctx)
for {
select {
case <-ctx.Done():
ticker.Stop()
return
case <-ticker.C:
m.UpdateMetrics(ctx)
}
}
}()
}
// MetricDefinition describes a Prometheus metric
type MetricDefinition struct {
Name string
Type string // counter, gauge, histogram
Help string
}
// GetMetricDefinitions returns all metric definitions
func GetMetricDefinitions() []MetricDefinition {
return []MetricDefinition{
// Counters
{Name: "lux_indexer_blocks_total", Type: "counter", Help: "Total number of indexed blocks"},
{Name: "lux_indexer_transactions_total", Type: "counter", Help: "Total number of indexed transactions"},
{Name: "lux_indexer_addresses_total", Type: "counter", Help: "Total number of unique addresses"},
{Name: "lux_indexer_contracts_total", Type: "counter", Help: "Total number of contract addresses"},
{Name: "lux_indexer_tokens_total", Type: "counter", Help: "Total number of token contracts"},
{Name: "lux_indexer_token_transfers_total", Type: "counter", Help: "Total number of token transfers"},
{Name: "lux_indexer_verified_contracts_total", Type: "counter", Help: "Total number of verified contracts"},
// Gauges
{Name: "lux_indexer_tps_24h", Type: "gauge", Help: "Transactions per second over last 24 hours"},
{Name: "lux_indexer_gas_used_24h", Type: "gauge", Help: "Total gas used in last 24 hours"},
{Name: "lux_indexer_gas_price_slow_gwei", Type: "gauge", Help: "Slow gas price in gwei"},
{Name: "lux_indexer_gas_price_average_gwei", Type: "gauge", Help: "Average gas price in gwei"},
{Name: "lux_indexer_gas_price_fast_gwei", Type: "gauge", Help: "Fast gas price in gwei"},
{Name: "lux_indexer_gas_time_slow_ms", Type: "gauge", Help: "Estimated confirmation time for slow gas price (ms)"},
{Name: "lux_indexer_gas_time_average_ms", Type: "gauge", Help: "Estimated confirmation time for average gas price (ms)"},
{Name: "lux_indexer_gas_time_fast_ms", Type: "gauge", Help: "Estimated confirmation time for fast gas price (ms)"},
{Name: "lux_indexer_gas_used_ratio", Type: "gauge", Help: "Recent block gas usage ratio (0-1)"},
{Name: "lux_indexer_block_time_seconds", Type: "gauge", Help: "Average block time in seconds"},
{Name: "lux_indexer_block_time_min_seconds", Type: "gauge", Help: "Minimum observed block time in seconds"},
{Name: "lux_indexer_block_time_max_seconds", Type: "gauge", Help: "Maximum observed block time in seconds"},
{Name: "lux_indexer_last_update_timestamp", Type: "gauge", Help: "Unix timestamp of last metrics update"},
}
}
// GetMetricsHelp returns Prometheus-formatted HELP and TYPE lines
func GetMetricsHelp() string {
var output string
for _, def := range GetMetricDefinitions() {
output += fmt.Sprintf("# HELP %s %s\n", def.Name, def.Help)
output += fmt.Sprintf("# TYPE %s %s\n", def.Name, def.Type)
}
return output
}