Skip to content

Commit 05ff334

Browse files
committed
feat:support custom labels
1 parent 2d51acb commit 05ff334

File tree

6 files changed

+98
-43
lines changed

6 files changed

+98
-43
lines changed

config.toml

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
name_server = "223.5.5.5"
33

44
[web]
5-
address = "0.0.0.0:8080"
5+
address = "0.0.0.0:9113"
66

77
[[targets]]
88
addr = "223.5.5.5"
9+
[targets.labels]
10+
"some_label" = "test"
11+
912

1013
[[targets]]
1114
addr = "114.114.114.114"
15+
[targets.labels]
16+
"custom_label" = "hihihihi"
1217

1318
[global_labels]
1419
"from" = "192.168.2.1"

config/config.go

+21-19
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (c *Config) Verify() {
7272
}
7373

7474
if len(c.Targets) == 0 {
75-
log.Panic().Msg("No targets specified")
75+
log.Panic().Msg("no targets specified")
7676
}
7777
}
7878

@@ -105,13 +105,11 @@ func (cfg *Config) TargetConfigByAddr(addr string) TargetConfig {
105105
func (c *Config) GenMonitor() (*mon.Monitor, error) {
106106
var bind4, bind6 string
107107
if ln, err := net.Listen("tcp4", "127.0.0.1:0"); err == nil {
108-
// ipv4 enabled
109-
ln.Close()
108+
_ = ln.Close()
110109
bind4 = "0.0.0.0"
111110
}
112111
if ln, err := net.Listen("tcp6", "[::1]:0"); err == nil {
113-
// ipv6 enabled
114-
ln.Close()
112+
_ = ln.Close()
115113
bind6 = "::"
116114
}
117115
pinger, err := ping.New(bind4, bind6)
@@ -129,17 +127,17 @@ func (c *Config) GenMonitor() (*mon.Monitor, error) {
129127
monitor.HistorySize = c.Ping.History
130128
resolver := c.SetupResolver()
131129
for i, target := range c.Targets {
132-
addrs, err := resolver.LookupIPAddr(context.Background(), target.Addr)
130+
ipAddrs, err := resolver.LookupIPAddr(context.Background(), target.Addr)
133131
if err != nil {
134132
log.Error(err).Str("target", target.Addr).Msg("cannot resolve target address")
135133
continue
136134
}
137-
for j, addr := range addrs {
138-
key := genPingMonitorKey(target.Addr, addr)
139-
if err := monitor.AddTargetDelayed(key, addr,
135+
for j, ipAddr := range ipAddrs {
136+
key := genPingMonitorKey(target.Addr, ipAddr)
137+
if err := monitor.AddTargetDelayed(key, ipAddr,
140138
time.Duration(10*i+j)*time.Millisecond,
141139
); err != nil {
142-
log.Error(err).Str("target", target.Addr).
140+
log.Error(err).Str("addr", target.Addr).
143141
Str("key", key).
144142
Msg("cannot add target")
145143
}
@@ -149,22 +147,21 @@ func (c *Config) GenMonitor() (*mon.Monitor, error) {
149147
return monitor, nil
150148
}
151149

152-
// genPingMonitorKey returns a unique key for the monitor based on target and addr
150+
// genPingMonitorKey returns a unique key for the monitor based on addr and ipAddr
153151
// for example: "test.host.com 192.168.2.1 v4"
154-
func genPingMonitorKey(target string, addr net.IPAddr) string {
155-
if addr.IP.To4() == nil {
156-
return fmt.Sprintf("%s %s v6", target, addr.String())
152+
func genPingMonitorKey(addr string, ipAddr net.IPAddr) string {
153+
if ipAddr.IP.To4() == nil {
154+
return fmt.Sprintf("%s %s v6", addr, ipAddr.String())
157155
}
158-
return fmt.Sprintf("%s %s v4", target, addr.String())
156+
return fmt.Sprintf("%s %s v4", addr, ipAddr.String())
159157
}
160158

161-
func ParseMonitorKey(key string) (string, net.IPAddr) {
162-
159+
func ParseMonitorKey(key string) (addr string, ipAddr net.IPAddr, version string) {
163160
parts := strings.Split(key, " ")
164161
if len(parts) != 3 {
165162
log.Panic().Str("key", key).Msg("cannot parse monitor key")
166163
}
167-
host := parts[0]
164+
addr = parts[0]
168165
ip := net.ParseIP(parts[1])
169166
if ip == nil {
170167
log.Panic().Str("key", key).Msg("unexpected ip in monitor key")
@@ -176,5 +173,10 @@ func ParseMonitorKey(key string) (string, net.IPAddr) {
176173
if parts[2] == "v6" && ip.To4() != nil {
177174
log.Panic().Str("key", key).Msg("unexpected ip version in monitor key")
178175
}
179-
return host, net.IPAddr{IP: ip}
176+
if ip.To4() == nil {
177+
version = "v4"
178+
} else {
179+
version = "v6"
180+
}
181+
return addr, net.IPAddr{IP: ip}, version
180182
}

config/custom_lable.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package config
2+
3+
type CustomLabel struct {
4+
label []string
5+
labelKey map[string]struct{}
6+
}
7+
8+
func NewCustomLabel(targets []TargetConfig) *CustomLabel {
9+
cl := CustomLabel{
10+
label: make([]string, 0),
11+
labelKey: make(map[string]struct{}),
12+
}
13+
14+
for _, t := range targets {
15+
if t.Labels == nil {
16+
continue
17+
}
18+
19+
for k := range t.Labels {
20+
if _, ok := cl.labelKey[k]; ok {
21+
continue
22+
}
23+
cl.label = append(cl.label, k)
24+
cl.labelKey[k] = struct{}{}
25+
}
26+
}
27+
return &cl
28+
29+
}
30+
31+
func (cl *CustomLabel) Labels() []string {
32+
return cl.label
33+
}
34+
35+
func (cl *CustomLabel) Values(target TargetConfig) []string {
36+
values := make([]string, len(cl.label))
37+
if target.Labels == nil {
38+
return values
39+
}
40+
for i, l := range cl.label {
41+
if _, ok := target.Labels[l]; ok {
42+
values[i] = target.Labels[l]
43+
}
44+
}
45+
return values
46+
}

config/target.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package config
22

33
type TargetConfig struct {
4-
Addr string `yaml:"addr"`
5-
// TODO support labels
6-
// Labels map[string]string `yaml:"labels"`
4+
Addr string `yaml:"addr"`
5+
Labels map[string]string `yaml:"labels"`
76
}

main.go

+4-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package main
22

33
import (
4-
"fmt"
54
"net/http"
65
"os"
76

@@ -33,12 +32,8 @@ func main() {
3332
prometheus.MustRegister(ping)
3433
http.Handle("/metrics", promhttp.Handler())
3534

36-
go func() {
37-
log.Info().Str("address", cfg.Web.Address).Msg("starting web server")
38-
if err := http.ListenAndServe(cfg.Web.Address, nil); err != nil {
39-
fmt.Println(err)
40-
}
41-
}()
42-
43-
select {}
35+
log.Info().Str("address", cfg.Web.Address).Msg("starting web server")
36+
if err := http.ListenAndServe(cfg.Web.Address, nil); err != nil {
37+
log.Panic(err).Msg("listen failed")
38+
}
4439
}

metrics/ping.go

+19-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package metrics
22

33
import (
44
"sort"
5-
"strings"
65

76
mon "github.com/digineo/go-ping/monitor"
87
"github.com/jimyag/log"
@@ -14,6 +13,7 @@ import (
1413
type Ping struct {
1514
monitor *mon.Monitor
1615
cfg *config.Config
16+
cl *config.CustomLabel
1717
globalKey []string
1818
metrics map[string]*mon.Metrics
1919
bestDesc *prometheus.Desc
@@ -28,9 +28,11 @@ func New(cfg *config.Config) *Ping {
2828
if err != nil {
2929
log.Panic(err).Msg("gen monitor")
3030
}
31+
cl := config.NewCustomLabel(cfg.Targets)
3132
p := &Ping{
3233
monitor: m,
3334
cfg: cfg,
35+
cl: cl,
3436
}
3537
p.init()
3638
return p
@@ -40,22 +42,25 @@ func (p *Ping) Collect(ch chan<- prometheus.Metric) {
4042
if m := p.monitor.Export(); len(m) > 0 {
4143
p.metrics = m
4244
}
43-
for target, metrics := range p.metrics {
44-
// target ip version
45-
l := strings.Split(target, " ")
45+
for key, metrics := range p.metrics {
46+
// addr ipAddr version
47+
addr, ipAddr, version := config.ParseMonitorKey(key)
48+
labelValues := []string{addr, ipAddr.String(), version}
4649
if p.globalKey != nil {
4750
for _, k := range p.globalKey {
48-
l = append(l, p.cfg.GlobalLabels[k])
51+
labelValues = append(labelValues, p.cfg.GlobalLabels[k])
4952
}
5053
}
54+
customLabelVal := p.cl.Values(p.cfg.TargetConfigByAddr(addr))
55+
labelValues = append(labelValues, customLabelVal...)
5156
if metrics.PacketsSent > metrics.PacketsLost {
52-
ch <- prometheus.MustNewConstMetric(p.bestDesc, prometheus.GaugeValue, float64(metrics.Best), l...)
53-
ch <- prometheus.MustNewConstMetric(p.worstDesc, prometheus.GaugeValue, float64(metrics.Worst), l...)
54-
ch <- prometheus.MustNewConstMetric(p.meanDesc, prometheus.GaugeValue, float64(metrics.Mean), l...)
55-
ch <- prometheus.MustNewConstMetric(p.stdDevDesc, prometheus.GaugeValue, float64(metrics.StdDev), l...)
57+
ch <- prometheus.MustNewConstMetric(p.bestDesc, prometheus.GaugeValue, float64(metrics.Best), labelValues...)
58+
ch <- prometheus.MustNewConstMetric(p.worstDesc, prometheus.GaugeValue, float64(metrics.Worst), labelValues...)
59+
ch <- prometheus.MustNewConstMetric(p.meanDesc, prometheus.GaugeValue, float64(metrics.Mean), labelValues...)
60+
ch <- prometheus.MustNewConstMetric(p.stdDevDesc, prometheus.GaugeValue, float64(metrics.StdDev), labelValues...)
5661
}
5762
loss := float64(metrics.PacketsLost) / float64(metrics.PacketsSent)
58-
ch <- prometheus.MustNewConstMetric(p.lossDesc, prometheus.GaugeValue, loss, l...)
63+
ch <- prometheus.MustNewConstMetric(p.lossDesc, prometheus.GaugeValue, loss, labelValues...)
5964
}
6065
}
6166

@@ -68,14 +73,17 @@ func (p *Ping) Describe(ch chan<- *prometheus.Desc) {
6873
}
6974

7075
func (p *Ping) init() {
71-
label := []string{"target", "ip", "version"}
76+
// base labels
77+
label := []string{"addr", "ip", "version"}
7278
if p.cfg.GlobalLabels != nil {
7379
p.globalKey = make([]string, 0, len(p.cfg.GlobalLabels))
7480
for k := range p.cfg.GlobalLabels {
7581
p.globalKey = append(p.globalKey, k)
7682
}
7783
sort.Strings(p.globalKey)
7884
label = append(label, p.globalKey...)
85+
// set custom labels
86+
label = append(label, p.cl.Labels()...)
7987
}
8088
p.bestDesc = newDesc("rtt_best", "best round trip time", label, nil)
8189
p.worstDesc = newDesc("rtt_worst", "worst round trip time", label, nil)

0 commit comments

Comments
 (0)