-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
166 lines (156 loc) · 5.07 KB
/
main.go
File metadata and controls
166 lines (156 loc) · 5.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package main
import (
"fmt"
"net/http"
"os"
"sync"
"time"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/prometheus/client_golang/prometheus/promhttp"
log "github.com/sirupsen/logrus"
"github.com/ybbus/jsonrpc"
"gitlab.com/zcash/zcashd_exporter/version"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
listenAddress = kingpin.Flag(
"web.listen-address",
"Address on which to expose metrics and web interface.",
).Default(":9100").String()
rpcProvider = kingpin.Flag(
"rpc.provider",
"Address for RPC provider.",
).Default("http://127.0.0.1:8545").String()
networkLabel = kingpin.Flag(
"label.network",
"Label to apply to the metrics to identify the network.",
).Default("mainnet").String()
versionFlag = kingpin.Flag(
"version",
"Display binary version.",
).Default("False").Bool()
unhealthyTimePeriod = kingpin.Flag(
"wait.minutes",
"Number of minutes to wait for the next block before marking provider unhealthy.",
).Default("10").Int()
//unhealthyTimePeriod = time.Minute * 10
)
type healthCheck struct {
mu *sync.RWMutex
height uint64
healthy bool
updateTime time.Time
}
func healthHandler(health *healthCheck) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
health.mu.RLock()
defer health.mu.RUnlock()
w.Write([]byte(fmt.Sprintf(`{ "healthy": "%t" }`, health.healthy)))
}
}
func main() {
kingpin.HelpFlag.Short('h')
kingpin.Parse()
if *versionFlag {
fmt.Printf("(version=%s, gitcommit=%s)\n", version.Version, version.GitCommit)
fmt.Printf("(go=%s, user=%s, date=%s)\n", version.GoVersion, version.BuildUser, version.BuildDate)
os.Exit(0)
}
log.Infoln("exporter config", *listenAddress, *rpcProvider, *networkLabel)
log.Infoln("Starting op_exporter", version.Info())
log.Infoln("Build context", version.BuildContext())
health := healthCheck{
mu: new(sync.RWMutex),
height: 0,
healthy: false,
updateTime: time.Now(),
}
http.Handle("/metrics", promhttp.Handler())
http.Handle("/health", healthHandler(&health))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`<html>
<head><title>OP Exporter</title></head>
<body>
<h1>OP Exporter</h1>
<p><a href="/metrics">Metrics</a></p>
<p><a href="/health">Health</a></p>
</body>
</html>`))
})
go getRollupGasPrices()
go getBlockNumber(&health)
log.Infoln("Listening on", *listenAddress)
if err := http.ListenAndServe(*listenAddress, nil); err != nil {
log.Fatal(err)
}
}
func getBlockNumber(health *healthCheck) {
rpcClient := jsonrpc.NewClientWithOpts(*rpcProvider, &jsonrpc.RPCClientOpts{})
var blockNumberResponse *string
for {
if err := rpcClient.CallFor(&blockNumberResponse, "eth_blockNumber"); err != nil {
health.mu.Lock()
health.healthy = false
health.mu.Unlock()
log.Warnln("Error calling eth_blockNumber, setting unhealthy", err)
} else {
log.Infoln("Got block number: ", *blockNumberResponse)
health.mu.Lock()
currentHeight, err := hexutil.DecodeUint64(*blockNumberResponse)
blockNumber.WithLabelValues(
*networkLabel, "layer2").Set(float64(currentHeight))
if err != nil {
log.Warnln("Error decoding block height", err)
continue
}
lastHeight := health.height
// If the currentHeight is the same as the lastHeight, check that
// the unhealthyTimePeriod has passed and update health.healthy
if currentHeight == lastHeight {
currentTime := time.Now()
lastTime := health.updateTime
log.Warnln(fmt.Sprintf("Heights are the same, %v, %v", currentTime, lastTime))
if lastTime.Add(time.Duration(*unhealthyTimePeriod) * time.Minute).Before(currentTime) {
health.healthy = false
log.Warnln("Heights are the same for the unhealthyTimePeriod, setting unhealthy")
}
} else {
log.Warnln("New block height detected, setting healthy")
health.height = currentHeight
health.updateTime = time.Now()
health.healthy = true
}
health.mu.Unlock()
}
time.Sleep(time.Duration(30) * time.Second)
}
}
func getRollupGasPrices() {
rpcClient := jsonrpc.NewClientWithOpts(*rpcProvider, &jsonrpc.RPCClientOpts{})
var rollupGasPrices *GetRollupGasPrices
for {
if err := rpcClient.CallFor(&rollupGasPrices, "rollup_gasPrices"); err != nil {
log.Warnln("Error calling rollup_gasPrices", err)
} else {
l1GasPriceString := rollupGasPrices.L1GasPrice
l1GasPrice, err := hexutil.DecodeUint64(l1GasPriceString)
if err != nil {
log.Warnln("Error converting gasPrice " + l1GasPriceString)
}
gasPrice.WithLabelValues(
*networkLabel, "layer1").Set(float64(l1GasPrice))
l2GasPriceString := rollupGasPrices.L2GasPrice
l2GasPrice, err := hexutil.DecodeUint64(l2GasPriceString)
if err != nil {
log.Warnln("Error converting gasPrice " + l2GasPriceString)
}
gasPrice.WithLabelValues(
*networkLabel, "layer2").Set(float64(l2GasPrice))
log.Infoln("Got L1 gas string: ", l1GasPriceString)
log.Infoln("Got L1 gas prices: ", l1GasPrice)
log.Infoln("Got L2 gas string: ", l2GasPriceString)
log.Infoln("Got L2 gas prices: ", l2GasPrice)
}
time.Sleep(time.Duration(30) * time.Second)
}
}