Skip to content

Commit 3898b6d

Browse files
committed
metrics: collect and export smb metrics via prometheus
Using 'smbstatus' collect shares and locks metrics end export it via Prometheus. Signed-off-by: Shachar Sharon <[email protected]>
1 parent b3cac3d commit 3898b6d

File tree

4 files changed

+607
-0
lines changed

4 files changed

+607
-0
lines changed

internal/metrics/collectors.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package metrics
4+
5+
import (
6+
"github.com/prometheus/client_golang/prometheus"
7+
)
8+
9+
var (
10+
collectorsNamespace = "smb"
11+
)
12+
13+
func (sme *smbMetricsExporter) register() error {
14+
cols := []prometheus.Collector{
15+
sme.newSmbSharesCollector(),
16+
sme.newSmbLocksCollector(),
17+
}
18+
for _, c := range cols {
19+
if err := sme.reg.Register(c); err != nil {
20+
sme.log.Error(err, "failed to register collector")
21+
return err
22+
}
23+
}
24+
return nil
25+
}
26+
27+
type smbCollector struct {
28+
// nolint:structcheck
29+
sme *smbMetricsExporter
30+
dsc []*prometheus.Desc
31+
}
32+
33+
func (col *smbCollector) Describe(ch chan<- *prometheus.Desc) {
34+
for _, d := range col.dsc {
35+
ch <- d
36+
}
37+
}
38+
39+
type smbSharesCollector struct {
40+
smbCollector
41+
}
42+
43+
func (col *smbSharesCollector) Collect(ch chan<- prometheus.Metric) {
44+
sharesTotal := 0
45+
sharesMap, _ := SmbStatusSharesByMachine()
46+
for machine, share := range sharesMap {
47+
sharesCount := len(share)
48+
ch <- prometheus.MustNewConstMetric(col.dsc[0],
49+
prometheus.GaugeValue, float64(sharesCount), machine)
50+
sharesTotal += sharesCount
51+
}
52+
53+
ch <- prometheus.MustNewConstMetric(col.dsc[1],
54+
prometheus.GaugeValue, float64(sharesTotal))
55+
}
56+
57+
func (sme *smbMetricsExporter) newSmbSharesCollector() prometheus.Collector {
58+
col := &smbSharesCollector{}
59+
col.sme = sme
60+
col.dsc = []*prometheus.Desc{
61+
prometheus.NewDesc(
62+
collectorName("shares", "machine"),
63+
"Number of shares by host-machine ip",
64+
[]string{"machine"}, nil),
65+
66+
prometheus.NewDesc(
67+
collectorName("shares", "total"),
68+
"Total number of active shares",
69+
[]string{}, nil),
70+
}
71+
return col
72+
}
73+
74+
type smbLocksCollector struct {
75+
smbCollector
76+
}
77+
78+
func (col *smbLocksCollector) Collect(ch chan<- prometheus.Metric) {
79+
locks, _ := RunSmbStatusLocks()
80+
ch <- prometheus.MustNewConstMetric(col.dsc[0],
81+
prometheus.GaugeValue, float64(len(locks)))
82+
}
83+
84+
func (sme *smbMetricsExporter) newSmbLocksCollector() prometheus.Collector {
85+
col := &smbLocksCollector{}
86+
col.sme = sme
87+
col.dsc = []*prometheus.Desc{
88+
prometheus.NewDesc(
89+
collectorName("locks", "total"),
90+
"Total number of active locks",
91+
[]string{}, nil),
92+
}
93+
return col
94+
}
95+
96+
func collectorName(subsystem, name string) string {
97+
return prometheus.BuildFQName(collectorsNamespace, subsystem, name)
98+
}

internal/metrics/exporter.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package metrics
4+
5+
import (
6+
"fmt"
7+
"net"
8+
"net/http"
9+
10+
"github.com/go-logr/logr"
11+
"github.com/prometheus/client_golang/prometheus"
12+
"github.com/prometheus/client_golang/prometheus/promhttp"
13+
)
14+
15+
var (
16+
// DefaultMetricsPort is the default port used to export prometheus metrics
17+
DefaultMetricsPort = int(8080)
18+
// DefaultMetricsPath is the default HTTP path to export prometheus metrics
19+
DefaultMetricsPath = "/metrics"
20+
)
21+
22+
type smbMetricsExporter struct {
23+
log logr.Logger
24+
reg *prometheus.Registry
25+
mux *http.ServeMux
26+
port int
27+
}
28+
29+
func newSmbMetricsExporter(log logr.Logger, port int) *smbMetricsExporter {
30+
return &smbMetricsExporter{
31+
log: log,
32+
reg: prometheus.NewRegistry(),
33+
mux: http.NewServeMux(),
34+
port: port,
35+
}
36+
}
37+
38+
func (sme *smbMetricsExporter) init() error {
39+
sme.log.Info("register collectors")
40+
return sme.register()
41+
}
42+
43+
func (sme *smbMetricsExporter) serve() error {
44+
addr := fmt.Sprintf(":%d", sme.port)
45+
sme.log.Info("serve metrics", "addr", addr)
46+
47+
handler := promhttp.HandlerFor(sme.reg, promhttp.HandlerOpts{})
48+
sme.mux.Handle(DefaultMetricsPath, handler)
49+
50+
listener, err := net.Listen("tcp", addr)
51+
if err != nil {
52+
sme.log.Error(err, "failed to listen", "addr", addr)
53+
return err
54+
}
55+
defer listener.Close()
56+
57+
if err := http.Serve(listener, sme.mux); err != nil {
58+
sme.log.Error(err, "HTTP server failure", "addr", addr)
59+
return err
60+
}
61+
return nil
62+
}
63+
64+
// RunSmbMetricsExporter executes an HTTP server and exports SMB metrics to
65+
// Prometheus.
66+
func RunSmbMetricsExporter(log logr.Logger) error {
67+
sme := newSmbMetricsExporter(log, DefaultMetricsPort)
68+
err := sme.init()
69+
if err != nil {
70+
return err
71+
}
72+
return sme.serve()
73+
}

0 commit comments

Comments
 (0)