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>
This commit is contained in:
Lars Gierth 2016-04-05 13:23:00 -04:00
parent daaa69e276
commit caec086c28
5 changed files with 113 additions and 29 deletions

View File

@ -27,6 +27,7 @@ import (
util "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
conn "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/net/conn"
peer "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/peer"
prometheus "gx/ipfs/QmdhsRK1EK2fvAz2i2SH5DEfkL6seDuyMYEsxKa9Braim3/client_golang/prometheus"
)
const (
@ -314,6 +315,10 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
return
}
// initialize metrics collector
prometheus.MustRegisterOrGet(&corehttp.IpfsNodeCollector{Node: node})
prometheus.EnableCollectChecks(true)
fmt.Printf("Daemon is ready\n")
// collect long-running errors and block for shutdown
// TODO(cryptix): our fuse currently doesnt follow this pattern for graceful shutdown
@ -376,15 +381,15 @@ func serveHTTPApi(req cmds.Request) (error, <-chan error) {
},
})
var opts = []corehttp.ServeOption{
corehttp.PrometheusCollectorOption("api"),
corehttp.MetricsCollectionOption("api"),
corehttp.CommandsOption(*req.InvocContext()),
corehttp.WebUIOption,
apiGw.ServeOption(),
corehttp.VersionOption(),
defaultMux("/debug/vars"),
defaultMux("/debug/pprof/"),
corehttp.MetricsScrapingOption("/debug/metrics/prometheus"),
corehttp.LogOption(),
corehttp.PrometheusOption("/debug/metrics/prometheus"),
}
if len(cfg.Gateway.RootRedirect) > 0 {
@ -455,7 +460,7 @@ func serveHTTPGateway(req cmds.Request) (error, <-chan error) {
}
var opts = []corehttp.ServeOption{
corehttp.PrometheusCollectorOption("gateway"),
corehttp.MetricsCollectionOption("gateway"),
corehttp.CommandsROOption(*req.InvocContext()),
corehttp.VersionOption(),
corehttp.IPNSHostnameOption(),

53
core/corehttp/metrics.go Normal file
View File

@ -0,0 +1,53 @@
package corehttp
import (
"net"
"net/http"
prometheus "gx/ipfs/QmdhsRK1EK2fvAz2i2SH5DEfkL6seDuyMYEsxKa9Braim3/client_golang/prometheus"
core "github.com/ipfs/go-ipfs/core"
)
// This adds the scraping endpoint which Prometheus uses to fetch metrics.
func MetricsScrapingOption(path string) ServeOption {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
mux.Handle(path, prometheus.UninstrumentedHandler())
return mux, nil
}
}
// This adds collection of net/http-related metrics
func MetricsCollectionOption(handlerName string) ServeOption {
return func(_ *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
childMux := http.NewServeMux()
mux.HandleFunc("/", prometheus.InstrumentHandler(handlerName, childMux))
return childMux, nil
}
}
var (
peersTotalMetric = prometheus.NewDesc(
prometheus.BuildFQName("ipfs", "p2p", "peers_total"),
"Number of connected peers", nil, nil)
)
type IpfsNodeCollector struct {
Node *core.IpfsNode
}
func (_ IpfsNodeCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- peersTotalMetric
}
func (c IpfsNodeCollector) Collect(ch chan<- prometheus.Metric) {
ch <- prometheus.MustNewConstMetric(
peersTotalMetric,
prometheus.GaugeValue,
c.PeersTotalValue(),
)
}
func (c IpfsNodeCollector) PeersTotalValue() float64 {
return float64(len(c.Node.PeerHost.Network().Conns()))
}

View File

@ -0,0 +1,46 @@
package corehttp
import (
"testing"
"time"
core "github.com/ipfs/go-ipfs/core"
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
bhost "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/host/basic"
inet "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/net"
testutil "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/test/util"
)
// This test is based on go-libp2p/p2p/net/swarm.TestConnectednessCorrect
// It builds 4 nodes and connects them, one being the sole center.
// Then it checks that the center reports the correct number of peers.
func TestPeersTotal(t *testing.T) {
ctx := context.Background()
hosts := make([]*bhost.BasicHost, 4)
for i := 0; i < 4; i++ {
hosts[i] = testutil.GenHostSwarm(t, ctx)
}
dial := func(a, b inet.Network) {
testutil.DivulgeAddresses(b, a)
if _, err := a.DialPeer(ctx, b.LocalPeer()); err != nil {
t.Fatalf("Failed to dial: %s", err)
}
}
dial(hosts[0].Network(), hosts[1].Network())
dial(hosts[0].Network(), hosts[2].Network())
dial(hosts[0].Network(), hosts[3].Network())
// there's something wrong with dial, i think. it's not finishing
// completely. there must be some async stuff.
<-time.After(100 * time.Millisecond)
node := &core.IpfsNode{PeerHost: hosts[0]}
collector := IpfsNodeCollector{Node: node}
actual := collector.PeersTotalValue()
if actual != 3 {
t.Fatalf("expected 3 peers, got %d", int(actual))
}
}

View File

@ -1,25 +0,0 @@
package corehttp
import (
"net"
"net/http"
prom "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus"
"github.com/ipfs/go-ipfs/core"
)
func PrometheusOption(path string) ServeOption {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
mux.Handle(path, prom.UninstrumentedHandler())
return mux, nil
}
}
func PrometheusCollectorOption(handlerName string) ServeOption {
return func(_ *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
childMux := http.NewServeMux()
mux.HandleFunc("/", prom.InstrumentHandler(handlerName, childMux))
return childMux, nil
}
}

View File

@ -30,6 +30,11 @@
"hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV",
"name": "gogo-protobuf",
"version": "0.0.0"
},
{
"hash": "QmdhsRK1EK2fvAz2i2SH5DEfkL6seDuyMYEsxKa9Braim3",
"name": "client_golang",
"version": "0.0.0"
}
],
"gxVersion": "0.4.0",
@ -39,4 +44,4 @@
"license": "",
"name": "go-ipfs",
"version": "0.4.0"
}
}