1
0
Fork 0

add hotspot activity and rewards metrics

This commit is contained in:
Massaki Archambault 2021-09-17 16:45:01 -04:00
parent cc251b1041
commit 7f8b73055e
3 changed files with 128 additions and 60 deletions

View File

@ -27,15 +27,14 @@ type Exporter struct {
// Account represents a helium account // Account represents a helium account
type Account struct { type Account struct {
hotspots []Hotspot hotspots []Hotspot
hash string hash string
lastRewardsUpdate time.Time
} }
// Hotspot represent a helium hotspot // Hotspot represent a helium hotspot
type Hotspot struct { type Hotspot struct {
hash string name string
lastRewardsUpdate time.Time hash string
} }
const ( const (
@ -160,11 +159,11 @@ var (
} }
accountRewardsHnt = metricInfo{ accountRewardsHnt = metricInfo{
prometheus.NewDesc( prometheus.NewDesc(
prometheus.BuildFQName(namespace, "account", "rewards_hnt"), prometheus.BuildFQName(namespace, "account", "rewards_hnt_total"),
"The number of HNT token rewarded to an account.", "The number of HNT token rewarded to an account.",
commonAccountLabels, nil, commonAccountLabels, nil,
), ),
prometheus.GaugeValue, prometheus.CounterValue,
} }
// accountDepositsHnt = metricInfo{ // accountDepositsHnt = metricInfo{
// prometheus.NewDesc( // prometheus.NewDesc(
@ -192,25 +191,25 @@ var (
), ),
prometheus.GaugeValue, prometheus.GaugeValue,
} }
hotspotListening = metricInfo{ hotspotRelayed = metricInfo{
prometheus.NewDesc( prometheus.NewDesc(
prometheus.BuildFQName(namespace, "hotspot", "listening"), prometheus.BuildFQName(namespace, "hotspot", "relayed"),
"Whether a hotspot is listening (not relayed).", "Whether a hotspot is relayed.",
commonHotspotLabels, nil, commonHotspotLabels, nil,
), ),
prometheus.GaugeValue, prometheus.GaugeValue,
} }
hotspotBlockHeight = metricInfo{ hotspotBlocks = metricInfo{
prometheus.NewDesc( prometheus.NewDesc(
prometheus.BuildFQName(namespace, "hotspot", "block_height"), prometheus.BuildFQName(namespace, "hotspot", "blocks_total"),
"The block height of a Hotspot. Check on the hotspot itself for the most recent data.", "The block height of a hotspot. Check on the hotspot itself for the most recent data.",
commonHotspotLabels, nil, commonHotspotLabels, nil,
), ),
prometheus.CounterValue, prometheus.CounterValue,
} }
hotspotRewardScale = metricInfo{ hotspotRewardsScale = metricInfo{
prometheus.NewDesc( prometheus.NewDesc(
prometheus.BuildFQName(namespace, "hotspot", "reward_scale"), prometheus.BuildFQName(namespace, "hotspot", "rewards_scale"),
"The reward scale of a hotspot.", "The reward scale of a hotspot.",
commonHotspotLabels, nil, commonHotspotLabels, nil,
), ),
@ -227,7 +226,7 @@ var (
hotspotAntennaInfo = metricInfo{ hotspotAntennaInfo = metricInfo{
prometheus.NewDesc( prometheus.NewDesc(
prometheus.BuildFQName(namespace, "hotspot", "antenna_info"), prometheus.BuildFQName(namespace, "hotspot", "antenna_info"),
"Information on the location of a hotspot.", "Information on the antenna of a hotspot.",
append(commonHotspotLabels, "gain", "elevation"), nil, append(commonHotspotLabels, "gain", "elevation"), nil,
), ),
prometheus.GaugeValue, prometheus.GaugeValue,
@ -242,11 +241,11 @@ var (
} }
hotspotRewardsHnt = metricInfo{ hotspotRewardsHnt = metricInfo{
prometheus.NewDesc( prometheus.NewDesc(
prometheus.BuildFQName(namespace, "hotspot", "rewards_hnt"), prometheus.BuildFQName(namespace, "hotspot", "rewards_hnt_total"),
"The number of HNT token rewarded to a hotspot.", "The number of HNT token rewarded to a hotspot.",
commonHotspotLabels, nil, commonHotspotLabels, nil,
), ),
prometheus.GaugeValue, prometheus.CounterValue,
} }
) )
@ -280,9 +279,9 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
// ch <- accountWithdrawalsHnt.Desc // ch <- accountWithdrawalsHnt.Desc
ch <- hotspotUp.Desc ch <- hotspotUp.Desc
ch <- hotspotListening.Desc ch <- hotspotRelayed.Desc
ch <- hotspotBlockHeight.Desc ch <- hotspotBlocks.Desc
ch <- hotspotRewardScale.Desc ch <- hotspotRewardsScale.Desc
ch <- hotspotGeocodeInfo.Desc ch <- hotspotGeocodeInfo.Desc
ch <- hotspotAntennaInfo.Desc ch <- hotspotAntennaInfo.Desc
ch <- hotspotActivity.Desc ch <- hotspotActivity.Desc
@ -294,9 +293,9 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
func (e *Exporter) Collect(ch chan<- prometheus.Metric) { func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
e.collectOracleMetrics(ch) e.collectOracleMetrics(ch)
e.collectStatsMetrics(ch) e.collectStatsMetrics(ch)
for _, account := range e.Accounts { for i := range e.Accounts {
e.collectAccountMetrics(ch, &account) e.collectAccountMetrics(ch, &e.Accounts[i])
e.collectHotspotMetrics(ch, &account) e.collectHotspotMetrics(ch, &e.Accounts[i])
} }
} }
@ -367,7 +366,7 @@ func (e *Exporter) collectAccountMetrics(ch chan<- prometheus.Metric, account *A
return return
} }
accountRewardTotalsForAddress, err := heliumapi.GetRewardTotalsForAccount(account.hash, &account.lastRewardsUpdate, nil) accountRewardTotalsForAddress, err := heliumapi.GetRewardTotalsForAccount(account.hash, &time.Time{}, nil)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
@ -387,10 +386,6 @@ func (e *Exporter) collectAccountMetrics(ch chan<- prometheus.Metric, account *A
accountRewardsHnt.Desc, accountRewardsHnt.Type, accountRewardTotalsForAddress.Data.Sum, accountRewardsHnt.Desc, accountRewardsHnt.Type, accountRewardTotalsForAddress.Data.Sum,
account.hash, account.hash,
) )
account.lastRewardsUpdate, err = time.Parse(time.RFC3339, accountRewardTotalsForAddress.Meta.MaxTime)
if err != nil {
fmt.Printf("failed to parse time \"%v\", value of %v will be bad: %v\n", accountRewardTotalsForAddress.Meta.MaxTime, accountRewardsHnt.Desc.String(), err)
}
} }
// collectStatsMetrics collect metrics in the hotspot group from the helium api // collectStatsMetrics collect metrics in the hotspot group from the helium api
@ -402,20 +397,32 @@ func (e *Exporter) collectHotspotMetrics(ch chan<- prometheus.Metric, account *A
} }
for _, hotspotData := range hotspotsForAddress.Data { for _, hotspotData := range hotspotsForAddress.Data {
hotspotActivityForAddress, err := heliumapi.GetHotspotActivityCount(hotspotData.Address)
if err != nil {
fmt.Println(err)
return
}
hotspotRewardTotalsForAddress, err := heliumapi.GetRewardsTotalForHotspot(hotspotData.Address, &time.Time{}, nil)
if err != nil {
fmt.Println(err)
return
}
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
hotspotUp.Desc, hotspotUp.Type, bool2Float64(hotspotData.Status.Online == "online"), hotspotUp.Desc, hotspotUp.Type, bool2Float64(hotspotData.Status.Online == "online"),
account.hash, hotspotData.Address, hotspotData.Name, account.hash, hotspotData.Address, hotspotData.Name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
hotspotListening.Desc, hotspotListening.Type, bool2Float64(len(hotspotData.Status.ListenAddrs) != 0), hotspotRelayed.Desc, hotspotRelayed.Type, bool2Float64(len(hotspotData.Status.ListenAddrs) > 0 && strings.HasPrefix(hotspotData.Status.ListenAddrs[0], "/p2p")),
account.hash, hotspotData.Address, hotspotData.Name, account.hash, hotspotData.Address, hotspotData.Name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
hotspotBlockHeight.Desc, hotspotBlockHeight.Type, float64(hotspotData.Status.Height), hotspotBlocks.Desc, hotspotBlocks.Type, float64(hotspotData.Status.Height),
account.hash, hotspotData.Address, hotspotData.Name, account.hash, hotspotData.Address, hotspotData.Name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
hotspotRewardScale.Desc, hotspotRewardScale.Type, float64(hotspotData.RewardScale), hotspotRewardsScale.Desc, hotspotRewardsScale.Type, float64(hotspotData.RewardScale),
account.hash, hotspotData.Address, hotspotData.Name, account.hash, hotspotData.Address, hotspotData.Name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
@ -426,6 +433,16 @@ func (e *Exporter) collectHotspotMetrics(ch chan<- prometheus.Metric, account *A
hotspotAntennaInfo.Desc, hotspotAntennaInfo.Type, 1.0, hotspotAntennaInfo.Desc, hotspotAntennaInfo.Type, 1.0,
account.hash, hotspotData.Address, hotspotData.Name, strconv.Itoa(hotspotData.Gain), strconv.Itoa(hotspotData.Elevation), account.hash, hotspotData.Address, hotspotData.Name, strconv.Itoa(hotspotData.Gain), strconv.Itoa(hotspotData.Elevation),
) )
for accType, count := range hotspotActivityForAddress.Data {
ch <- prometheus.MustNewConstMetric(
hotspotActivity.Desc, hotspotActivity.Type, float64(count),
account.hash, hotspotData.Address, hotspotData.Name, accType,
)
}
ch <- prometheus.MustNewConstMetric(
hotspotRewardsHnt.Desc, hotspotRewardsHnt.Type, hotspotRewardTotalsForAddress.Data.Sum,
account.hash, hotspotData.Address, hotspotData.Name,
)
} }
} }
@ -444,8 +461,7 @@ func NewExporter(accountHashs []string) (*Exporter, error) {
func NewAccount(hash string) Account { func NewAccount(hash string) Account {
return Account{ return Account{
hash: hash, hash: hash,
lastRewardsUpdate: time.Now(),
} }
} }

View File

@ -19,37 +19,16 @@ type Account struct {
} `json:"data"` } `json:"data"`
} }
type ActivityCounts struct {
Data map[string]int
}
type RewardTotal struct {
Meta struct {
MinTime string `json:"min_time"`
MaxTime string `json:"max_time"`
} `json:"meta"`
Data struct {
Total float64 `json:"total"`
Sum float64 `json:"sum"`
Stddev float64 `json:"stddev"`
Min float64 `json:"min"`
Median float64 `json:"median"`
Max float64 `json:"max"`
Avg float64 `json:"avg"`
} `json:"data"`
}
type AccountHotspots struct { type AccountHotspots struct {
Data []struct { Data []struct {
Lng float64 `json:"lng"` Lng float64 `json:"lng"`
Lat float64 `json:"lat"` Lat float64 `json:"lat"`
TimestampAdded string `json:"timestamp_added"` TimestampAdded string `json:"timestamp_added"`
Status struct { Status struct {
Timestamp string `json:"timestamp"` Timestamp string `json:"timestamp"`
Online string `json:"online"` Online string `json:"online"`
ListenAddrs []string ListenAddrs []string `json:"listen_addrs"`
Height int Height int `json:"height"`
} `json:"status"` } `json:"status"`
RewardScale float64 `json:"reward_scale"` RewardScale float64 `json:"reward_scale"`
Payer string `json:"payer"` Payer string `json:"payer"`
@ -125,7 +104,7 @@ func GetRewardTotalsForAccount(account string, minTime *time.Time, maxTime *time
params["min_time"] = minTime.UTC().Format("2006-01-02T15:04:05Z") params["min_time"] = minTime.UTC().Format("2006-01-02T15:04:05Z")
} }
if maxTime != nil { if maxTime != nil {
params["max_time"] = minTime.UTC().Format("2006-01-02T15:04:05Z") params["max_time"] = maxTime.UTC().Format("2006-01-02T15:04:05Z")
} }
// query the api // query the api

73
heliumapi/hotspots.go Normal file
View File

@ -0,0 +1,73 @@
package heliumapi
import (
"encoding/json"
"fmt"
"time"
)
type ActivityCounts struct {
Data map[string]int
}
type RewardTotal struct {
Meta struct {
MinTime string `json:"min_time"`
MaxTime string `json:"max_time"`
} `json:"meta"`
Data struct {
Total float64 `json:"total"`
Sum float64 `json:"sum"`
Stddev float64 `json:"stddev"`
Min float64 `json:"min"`
Median float64 `json:"median"`
Max float64 `json:"max"`
Avg float64 `json:"avg"`
} `json:"data"`
}
func GetHotspotActivityCount(hotspot string) (*ActivityCounts, error) {
path := "/v1/hotspots/" + hotspot + "/activity/count"
// query the api
respBody, err := getHeliumApi(path, nil)
if err != nil {
return nil, err
}
// unmarshal the response
respobject := ActivityCounts{}
err = json.Unmarshal(respBody, &respobject)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
}
return &respobject, nil
}
func GetRewardsTotalForHotspot(hotspot string, minTime *time.Time, maxTime *time.Time) (*RewardTotal, error) {
path := "/v1/hotspots/" + hotspot + "/rewards/sum"
params := map[string]string{}
if minTime != nil {
params["min_time"] = minTime.UTC().Format("2006-01-02T15:04:05Z")
}
if maxTime != nil {
params["max_time"] = maxTime.UTC().Format("2006-01-02T15:04:05Z")
}
// query the api
respBody, err := getHeliumApi(path, &params)
if err != nil {
return nil, err
}
// unmarshal the response
respobject := RewardTotal{}
err = json.Unmarshal(respBody, &respobject)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response from path %v: %v", path, err)
}
return &respobject, nil
}