metrics: add prometheus back
With a proper IpfsCollector object and tests, this time. The collector object makes it easy to add further metrics, like e.g. bitswap wants/provs. License: MIT Signed-off-by: Lars Gierth <larsg@systemli.org>
Lars Gierth committed
Apr 5, 2016 at 13:23 UTC
caec086c2853a6f4690d18cce360e94cbd088722
5 files changed
+113
-29
cmd/ipfs/daemon.go
+8
-3
@@ -27,6 +27,7 @@ import (
27
util "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
28
conn "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/net/conn"
29
peer "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/peer"
30
+ prometheus "gx/ipfs/QmdhsRK1EK2fvAz2i2SH5DEfkL6seDuyMYEsxKa9Braim3/client_golang/prometheus"
31
)
32
33
const (
@@ -314,6 +315,10 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
315
return
316
}
317
318
+ // initialize metrics collector
319
+ prometheus.MustRegisterOrGet(&corehttp.IpfsNodeCollector{Node: node})
320
+ prometheus.EnableCollectChecks(true)
321
+
322
fmt.Printf("Daemon is ready\n")
323
// collect long-running errors and block for shutdown
324
// TODO(cryptix): our fuse currently doesnt follow this pattern for graceful shutdown
@@ -376,15 +381,15 @@ func serveHTTPApi(req cmds.Request) (error, <-chan error) {
381
},
382
})
383
var opts = []corehttp.ServeOption{
379
- corehttp.PrometheusCollectorOption("api"),
384
+ corehttp.MetricsCollectionOption("api"),
385
corehttp.CommandsOption(*req.InvocContext()),
386
corehttp.WebUIOption,
387
apiGw.ServeOption(),
388
corehttp.VersionOption(),
389
defaultMux("/debug/vars"),
390
defaultMux("/debug/pprof/"),
391
+ corehttp.MetricsScrapingOption("/debug/metrics/prometheus"),
392
corehttp.LogOption(),
387
- corehttp.PrometheusOption("/debug/metrics/prometheus"),
393
}
394
395
if len(cfg.Gateway.RootRedirect) > 0 {
@@ -455,7 +460,7 @@ func serveHTTPGateway(req cmds.Request) (error, <-chan error) {
460
}
461
462
var opts = []corehttp.ServeOption{
458
- corehttp.PrometheusCollectorOption("gateway"),
463
+ corehttp.MetricsCollectionOption("gateway"),
464
corehttp.CommandsROOption(*req.InvocContext()),
465
corehttp.VersionOption(),
466
corehttp.IPNSHostnameOption(),
core/corehttp/metrics.go
new
+53
@@ -0,0 +1,53 @@
1
+package corehttp
2
+
3
+import (
4
+ "net"
5
+ "net/http"
6
+
7
+ prometheus "gx/ipfs/QmdhsRK1EK2fvAz2i2SH5DEfkL6seDuyMYEsxKa9Braim3/client_golang/prometheus"
8
+
9
+ core "github.com/ipfs/go-ipfs/core"
10
+)
11
+
12
+// This adds the scraping endpoint which Prometheus uses to fetch metrics.
13
+func MetricsScrapingOption(path string) ServeOption {
14
+ return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
15
+ mux.Handle(path, prometheus.UninstrumentedHandler())
16
+ return mux, nil
17
+ }
18
+}
19
+
20
+// This adds collection of net/http-related metrics
21
+func MetricsCollectionOption(handlerName string) ServeOption {
22
+ return func(_ *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
23
+ childMux := http.NewServeMux()
24
+ mux.HandleFunc("/", prometheus.InstrumentHandler(handlerName, childMux))
25
+ return childMux, nil
26
+ }
27
+}
28
+
29
+var (
30
+ peersTotalMetric = prometheus.NewDesc(
31
+ prometheus.BuildFQName("ipfs", "p2p", "peers_total"),
32
+ "Number of connected peers", nil, nil)
33
+)
34
+
35
+type IpfsNodeCollector struct {
36
+ Node *core.IpfsNode
37
+}
38
+
39
+func (_ IpfsNodeCollector) Describe(ch chan<- *prometheus.Desc) {
40
+ ch <- peersTotalMetric
41
+}
42
+
43
+func (c IpfsNodeCollector) Collect(ch chan<- prometheus.Metric) {
44
+ ch <- prometheus.MustNewConstMetric(
45
+ peersTotalMetric,
46
+ prometheus.GaugeValue,
47
+ c.PeersTotalValue(),
48
+ )
49
+}
50
+
51
+func (c IpfsNodeCollector) PeersTotalValue() float64 {
52
+ return float64(len(c.Node.PeerHost.Network().Conns()))
53
+}
core/corehttp/metrics_test.go
new
+46
@@ -0,0 +1,46 @@
1
+package corehttp
2
+
3
+import (
4
+ "testing"
5
+ "time"
6
+
7
+ core "github.com/ipfs/go-ipfs/core"
8
+ context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9
+ bhost "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/host/basic"
10
+ inet "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/net"
11
+ testutil "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/test/util"
12
+)
13
+
14
+// This test is based on go-libp2p/p2p/net/swarm.TestConnectednessCorrect
15
+// It builds 4 nodes and connects them, one being the sole center.
16
+// Then it checks that the center reports the correct number of peers.
17
+func TestPeersTotal(t *testing.T) {
18
+ ctx := context.Background()
19
+
20
+ hosts := make([]*bhost.BasicHost, 4)
21
+ for i := 0; i < 4; i++ {
22
+ hosts[i] = testutil.GenHostSwarm(t, ctx)
23
+ }
24
+
25
+ dial := func(a, b inet.Network) {
26
+ testutil.DivulgeAddresses(b, a)
27
+ if _, err := a.DialPeer(ctx, b.LocalPeer()); err != nil {
28
+ t.Fatalf("Failed to dial: %s", err)
29
+ }
30
+ }
31
+
32
+ dial(hosts[0].Network(), hosts[1].Network())
33
+ dial(hosts[0].Network(), hosts[2].Network())
34
+ dial(hosts[0].Network(), hosts[3].Network())
35
+
36
+ // there's something wrong with dial, i think. it's not finishing
37
+ // completely. there must be some async stuff.
38
+ <-time.After(100 * time.Millisecond)
39
+
40
+ node := &core.IpfsNode{PeerHost: hosts[0]}
41
+ collector := IpfsNodeCollector{Node: node}
42
+ actual := collector.PeersTotalValue()
43
+ if actual != 3 {
44
+ t.Fatalf("expected 3 peers, got %d", int(actual))
45
+ }
46
+}
core/corehttp/prometheus.go
deleted
-25
@@ -1,25 +0,0 @@
1
-package corehttp
2
-
3
-import (
4
- "net"
5
- "net/http"
6
-
7
- prom "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus"
8
-
9
- "github.com/ipfs/go-ipfs/core"
10
-)
11
-
12
-func PrometheusOption(path string) ServeOption {
13
- return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
14
- mux.Handle(path, prom.UninstrumentedHandler())
15
- return mux, nil
16
- }
17
-}
18
-
19
-func PrometheusCollectorOption(handlerName string) ServeOption {
20
- return func(_ *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
21
- childMux := http.NewServeMux()
22
- mux.HandleFunc("/", prom.InstrumentHandler(handlerName, childMux))
23
- return childMux, nil
24
- }
25
-}
package.json
+6
-1
@@ -30,6 +30,11 @@
30
"hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV",
31
"name": "gogo-protobuf",
32
"version": "0.0.0"
33
+ },
34
+ {
35
+ "hash": "QmdhsRK1EK2fvAz2i2SH5DEfkL6seDuyMYEsxKa9Braim3",
36
+ "name": "client_golang",
37
+ "version": "0.0.0"
38
}
39
],
40
"gxVersion": "0.4.0",
@@ -39,4 +44,4 @@
44
"license": "",
45
"name": "go-ipfs",
46
"version": "0.4.0"
42
-}
\ No newline at end of file
47
+}