From 20a4ba578ab75c962ce68d0669b5b3029d1bdc84 Mon Sep 17 00:00:00 2001 From: K Rin Date: Sun, 10 Nov 2024 09:15:41 +0800 Subject: [PATCH] Add collector for netstats tcp packet counters for FreeBSD. Signed-off-by: K Rin --- collector/netstat_freebsd.go | 103 ++++++++++++++++++++++++++++++ collector/netstat_freebsd_test.go | 59 +++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 collector/netstat_freebsd.go create mode 100644 collector/netstat_freebsd_test.go diff --git a/collector/netstat_freebsd.go b/collector/netstat_freebsd.go new file mode 100644 index 0000000000..b0b1f70ca8 --- /dev/null +++ b/collector/netstat_freebsd.go @@ -0,0 +1,103 @@ +// Copyright 2015 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. + +//go:build freebsd +// +build freebsd + +package collector + +import ( + "errors" + "fmt" + "github.com/prometheus/client_golang/prometheus" + "golang.org/x/sys/unix" + "log/slog" + "unsafe" +) + +/* +#include +#include +#include +#include +#include +#include +*/ +import "C" + +var metrics = []string{ + "tcp_send_packet_total", + "tcp_recv_packet_total", +} + +type netStatCollector struct { + netStatMetric *prometheus.Desc +} + +func init() { + registerCollector("netstat", defaultEnabled, NewNetStatCollector) +} + +func NewNetStatCollector(logger *slog.Logger) (Collector, error) { + return &netStatCollector{}, nil +} + +func (c *netStatCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- c.netStatMetric +} + +func (c *netStatCollector) Collect(ch chan<- prometheus.Metric) { + _ = c.Update(ch) +} + +func getData(queryString string) ([]byte, error) { + data, err := unix.SysctlRaw(queryString) + if err != nil { + fmt.Println("Error:", err) + return nil, err + } + + if len(data) < int(unsafe.Sizeof(C.struct_tcpstat{})) { + return nil, errors.New("Data Size mismatch") + } + return data, nil +} + +func (c *netStatCollector) Update(ch chan<- prometheus.Metric) error { + + var result []float64 + + tcpData, err := getData("net.inet.tcp.stats") + if err != nil { + return err + } + + tcpStats := *(*C.struct_tcpstat)(unsafe.Pointer(&tcpData[0])) + + result = append(result, float64(tcpStats.tcps_sndtotal)) + result = append(result, float64(tcpStats.tcps_rcvtotal)) + + for index, value := range metrics { + ch <- prometheus.MustNewConstMetric( + prometheus.NewDesc( + value, + value, + nil, nil, + ), + prometheus.UntypedValue, + result[index], + ) + } + + return nil +} diff --git a/collector/netstat_freebsd_test.go b/collector/netstat_freebsd_test.go new file mode 100644 index 0000000000..7d88458a59 --- /dev/null +++ b/collector/netstat_freebsd_test.go @@ -0,0 +1,59 @@ +// Copyright 2015 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. + +//go:build freebsd +// +build freebsd + +package collector + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/assert" + "golang.org/x/sys/unix" + "testing" +) + +func TestNetStatCollectorDescribe(t *testing.T) { + ch := make(chan *prometheus.Desc, 1) + collector := &netStatCollector{ + netStatMetric: prometheus.NewDesc("dummy_metric", "dummy", nil, nil), + } + collector.Describe(ch) + desc := <-ch + assert.Equal(t, "dummy_metric", desc.String()) +} + +func TestGetData(t *testing.T) { + data, err := getData("net.inet.tcp.stats") + assert.NoError(t, err) + assert.GreaterOrEqual(t, len(data), int(unsafe.Sizeof(C.struct_tcpstat{}))) +} + +func TestNetStatCollectorUpdate(t *testing.T) { + ch := make(chan prometheus.Metric, len(metrics)) + collector := &netStatCollector{ + netStatMetric: prometheus.NewDesc("netstat_metric", "NetStat Metric", nil, nil), + } + err := collector.Update(ch) + assert.NoError(t, err) + assert.Equal(t, len(metrics), len(ch)) + for range metrics { + <-ch + } +} + +func TestNewNetStatCollector(t *testing.T) { + collector, err := NewNetStatCollector(nil) + assert.NoError(t, err) + assert.NotNil(t, collector) +}