add network_route collector

Signed-off-by: kamijin_fanta <kamijin@live.jp>
This commit is contained in:
kamijin_fanta 2020-08-13 15:57:48 +09:00
parent 8b466360a3
commit 1f5898999e
3 changed files with 178 additions and 0 deletions

View file

@ -0,0 +1,172 @@
// Copyright 2020 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !nonetworkroute
package collector
import (
"fmt"
"net"
"strconv"
"github.com/go-kit/kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/vishvananda/netlink"
)
type networkRouteCollector struct {
routeDesc *prometheus.Desc
routesTotalDesc *prometheus.Desc
logger log.Logger
}
func init() {
registerCollector("network_route", defaultDisabled, NewNetworkRouteCollector)
}
// NewSystemdCollector returns a new Collector exposing systemd statistics.
func NewNetworkRouteCollector(logger log.Logger) (Collector, error) {
const subsystem = "network"
routeDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "route"),
"network routing table", []string{"if", "src", "dest", "gw", "priority", "proto", "weight"}, nil,
)
routeTotalDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "routes_total"),
"network total routes", []string{"if"}, nil,
)
return &networkRouteCollector{
routeDesc: routeDesc,
routesTotalDesc: routeTotalDesc,
logger: logger,
}, nil
}
func (n networkRouteCollector) Update(ch chan<- prometheus.Metric) error {
deviceRoutes := make(map[string]int)
routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
if err != nil {
return fmt.Errorf("couldn't get route list: %w", err)
}
for _, route := range routes {
if len(route.MultiPath) != 0 { // route has multipath
for _, nexthop := range route.MultiPath {
link, err := netlink.LinkByIndex(nexthop.LinkIndex)
if err != nil {
return fmt.Errorf("couldn't get link by index: %w", err)
}
labels := []string{
link.Attrs().Name, // if
networkRouteIPToString(route.Src), // src
networkRouteIPNetToString(route.Dst), // dest
networkRouteIPToString(nexthop.Gw), // gw
strconv.Itoa(route.Priority), // priority(metrics)
networkRouteProtocolToString(route.Protocol), // proto
strconv.Itoa(nexthop.Hops + 1), // weight
}
ch <- prometheus.MustNewConstMetric(n.routeDesc, prometheus.GaugeValue, 1, labels...)
deviceRoutes[link.Attrs().Name]++
}
} else {
link, err := netlink.LinkByIndex(route.LinkIndex)
if err != nil {
return fmt.Errorf("couldn't get link by index: %w", err)
}
labels := []string{
link.Attrs().Name, // if
networkRouteIPToString(route.Src), // src
networkRouteIPNetToString(route.Dst), // dest
networkRouteIPToString(route.Gw), // gw
strconv.Itoa(route.Priority), // priority(metrics)
networkRouteProtocolToString(route.Protocol), // proto
"", // weight
}
ch <- prometheus.MustNewConstMetric(n.routeDesc, prometheus.GaugeValue, 1, labels...)
deviceRoutes[link.Attrs().Name]++
}
}
for dev, total := range deviceRoutes {
ch <- prometheus.MustNewConstMetric(n.routesTotalDesc, prometheus.GaugeValue, float64(total), dev)
}
return nil
}
func networkRouteIPNetToString(ip *net.IPNet) string {
if ip == nil {
return "default"
}
return ip.String()
}
func networkRouteIPToString(ip net.IP) string {
if len(ip) == 0 {
return ""
}
return ip.String()
}
func networkRouteProtocolToString(protocol int) string {
// from linux kernel 'include/uapi/linux/rtnetlink.h'
switch protocol {
case 0:
return "unspec"
case 1:
return "redirect"
case 2:
return "kernel"
case 3:
return "boot"
case 4:
return "static"
case 8:
return "gated"
case 9:
return "ra"
case 10:
return "mrt"
case 11:
return "zebra"
case 12:
return "bird"
case 13:
return "dnrouted"
case 14:
return "xorp"
case 15:
return "ntk"
case 16:
return "dhcp"
case 17:
return "mrouted"
case 42:
return "babel"
case 186:
return "bgp"
case 187:
return "isis"
case 188:
return "ospf"
case 189:
return "rip"
case 192:
return "eigrp"
}
return "unknown"
}

1
go.mod
View file

@ -19,6 +19,7 @@ require (
github.com/prometheus/procfs v0.2.0
github.com/siebenmann/go-kstat v0.0.0-20200303194639-4e8294f9e9d5
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a
github.com/vishvananda/netlink v1.1.0
go.uber.org/multierr v1.5.0 // indirect
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect

5
go.sum
View file

@ -329,6 +329,10 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@ -427,6 +431,7 @@ golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13 h1:tdsQdquKbTNMsSZLqnLELJGzCANp9oXhu6zFBW6ODx4=