2021-09-12 14:17:31 +00:00
|
|
|
package main
|
|
|
|
|
2021-09-13 03:25:47 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"github.com/helium-blockchain-exporter/heliumapi"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
|
|
)
|
|
|
|
|
|
|
|
// metricInfo is a metric exported by the helium blockchain exporter
|
|
|
|
type metricInfo struct {
|
|
|
|
Desc *prometheus.Desc
|
|
|
|
Type prometheus.ValueType
|
|
|
|
}
|
|
|
|
|
|
|
|
// Exporter collect metrics from the helium blockchain api and exports them as prometheus metrics.
|
|
|
|
type Exporter struct {
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
namespace = "helium"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// exporter metrics
|
|
|
|
|
|
|
|
// helium oracle metrics
|
|
|
|
oraclePrice = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "oracle", "price_usd"),
|
|
|
|
"The oracle price of an HNT token in USD.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
|
|
|
|
// helium stats metrics
|
|
|
|
statsValidators = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "stats", "validators"),
|
|
|
|
"The number of hotspots.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
statsOuis = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "stats", "ouis"),
|
|
|
|
"The number of organization unique identifiers.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
statsHotspotsDataOnly = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "stats", "hotspots_dataonly"),
|
|
|
|
"The number of data only hotspots.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
statsBlocks = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "stats", "blocks"),
|
|
|
|
"The height/number of blocks in the blockchain.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
statsChallenges = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "stats", "challenges"),
|
|
|
|
"The number of challenges.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
statsCities = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "stats", "cities"),
|
|
|
|
"The number of cities with at least one helium hotspot.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
statsConsensusGroups = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "stats", "consensus_groups"),
|
|
|
|
"The number of consensus groups.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
statsCountries = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "stats", "countries"),
|
|
|
|
"The number of countries with at least on helium hotspot.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
statsHotspots = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "stats", "hotspots"),
|
|
|
|
"The number of hotspots.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
statsTokenSupply = metricInfo{
|
|
|
|
prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, "stats", "token_supply"),
|
|
|
|
"The total supply of HNT tokens in circulation.",
|
|
|
|
nil, nil,
|
|
|
|
),
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
}
|
|
|
|
|
|
|
|
// helium account metrics
|
|
|
|
|
|
|
|
// helium hotspot metrics
|
|
|
|
)
|
|
|
|
|
|
|
|
// Describe describes all the metrics ever exported by the helium blockchain exporter.
|
|
|
|
// implements prometheus.Collector.
|
|
|
|
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
|
|
|
|
ch <- oraclePrice.Desc
|
|
|
|
|
|
|
|
ch <- statsValidators.Desc
|
|
|
|
ch <- statsOuis.Desc
|
|
|
|
ch <- statsHotspotsDataOnly.Desc
|
|
|
|
ch <- statsBlocks.Desc
|
|
|
|
ch <- statsChallenges.Desc
|
|
|
|
ch <- statsCities.Desc
|
|
|
|
ch <- statsConsensusGroups.Desc
|
|
|
|
ch <- statsCountries.Desc
|
|
|
|
ch <- statsHotspots.Desc
|
|
|
|
ch <- statsTokenSupply.Desc
|
|
|
|
}
|
|
|
|
|
|
|
|
// Collect fetches the data from the helium blockchain api and delivers them as Prometheus metrics.
|
|
|
|
// implements prometheus.Collector.
|
|
|
|
func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
|
|
|
e.collectOracleMetrics(ch)
|
|
|
|
e.collectStatsMetrics(ch)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Exporter) collectOracleMetrics(ch chan<- prometheus.Metric) {
|
|
|
|
currentOraclePrice, err := heliumapi.GetCurrentOraclePrice()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
oraclePrice.Desc, oraclePrice.Type, float64(currentOraclePrice.Data.Price)/100000000,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Exporter) collectStatsMetrics(ch chan<- prometheus.Metric) {
|
|
|
|
blockchainStats, err := heliumapi.GetBlockchainStats()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
statsValidators.Desc, statsValidators.Type, float64(blockchainStats.Data.Counts.Validators),
|
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
statsOuis.Desc, statsOuis.Type, float64(blockchainStats.Data.Counts.Ouis),
|
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
statsHotspotsDataOnly.Desc, statsHotspotsDataOnly.Type, float64(blockchainStats.Data.Counts.HotspotsDataonly),
|
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
statsBlocks.Desc, statsBlocks.Type, float64(blockchainStats.Data.Counts.Blocks),
|
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
statsChallenges.Desc, statsChallenges.Type, float64(blockchainStats.Data.Counts.Challenges),
|
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
statsCities.Desc, statsCities.Type, float64(blockchainStats.Data.Counts.Cities),
|
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
statsConsensusGroups.Desc, statsConsensusGroups.Type, float64(blockchainStats.Data.Counts.ConsensusGroups),
|
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
statsCountries.Desc, statsCountries.Type, float64(blockchainStats.Data.Counts.Countries),
|
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
statsHotspots.Desc, statsHotspots.Type, float64(blockchainStats.Data.Counts.Hotspots),
|
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
statsTokenSupply.Desc, statsTokenSupply.Type, blockchainStats.Data.TokenSupply,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewExporter returns an initialized Exporter
|
|
|
|
func NewExporter() (*Exporter, error) {
|
|
|
|
return &Exporter{}, nil
|
|
|
|
}
|
2021-09-12 14:17:31 +00:00
|
|
|
|
|
|
|
func main() {
|
2021-09-13 03:25:47 +00:00
|
|
|
metricsPath := "/metrics"
|
|
|
|
|
|
|
|
e, err := NewExporter()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("failed to start exporter: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
r := prometheus.NewRegistry()
|
|
|
|
r.MustRegister(e)
|
|
|
|
|
|
|
|
// setup http route
|
|
|
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
_, _ = w.Write([]byte(`<html>
|
|
|
|
<head><title>Helium blockchain exporter</title></head>
|
|
|
|
<body>
|
|
|
|
<h1>Helium blockchain exporter</h1>
|
|
|
|
<p><a href='` + metricsPath + `'>Metrics</a></p>
|
|
|
|
</body>
|
|
|
|
</html>`))
|
|
|
|
})
|
|
|
|
|
|
|
|
http.Handle(metricsPath, promhttp.HandlerFor(r, promhttp.HandlerOpts{}))
|
|
|
|
http.ListenAndServe(":9111", nil)
|
2021-09-12 14:17:31 +00:00
|
|
|
}
|