mirror of
https://github.com/ClusterCockpit/cc-metric-collector.git
synced 2025-09-16 21:34:32 +02:00
Compare commits
124 Commits
snmp_recei
...
nvidia_run
Author | SHA1 | Date | |
---|---|---|---|
|
2505b2f20b | ||
|
656e5899b0 | ||
|
9b671ce68f | ||
|
226e8425cb | ||
|
a37f6603c8 | ||
|
78902305e8 | ||
|
c8a91903f6 | ||
|
5d19c31fa8 | ||
|
4bee75d4b5 | ||
|
78fac33a06 | ||
|
0b509ca9e4 | ||
|
595399e7d9 | ||
|
f059d52d43 | ||
|
b618e81cbb | ||
|
8837400bf2 | ||
|
3be11984f2 | ||
|
dd40c852ca | ||
|
39ae211530 | ||
|
a4d7593af5 | ||
|
fd1cdc5c07 | ||
|
94c88f23df | ||
|
9dae829f9d | ||
|
b0f0462995 | ||
|
778bb62602 | ||
|
5aa9603c01 | ||
|
0db1cda27f | ||
|
013ae7ec6d | ||
|
9f65365f9d | ||
|
1e606a1aa1 | ||
|
19ec6d06db | ||
|
553fcff468 | ||
|
7b5a4caf6a | ||
|
a401e4cdd1 | ||
|
94d5822426 | ||
|
f6b5f7fb07 | ||
|
0c95db50ad | ||
|
75b705aa87 | ||
|
8da5c692bb | ||
|
42a9423203 | ||
|
c87c77a810 | ||
|
c472029c2d | ||
|
9e73849081 | ||
|
d1a960e6e1 | ||
|
9530c489b5 | ||
|
64ffa3d23e | ||
|
3f4b11db47 | ||
|
fd227ed8b3 | ||
|
2d41531b51 | ||
|
e34b0166f9 | ||
|
baa45b833b | ||
|
aac475fc98 | ||
|
2dfeac8ce8 | ||
|
6a4731ab7e | ||
|
be68aeb44f | ||
|
9975ee6e00 | ||
|
38478ce8c2 | ||
|
9c9fd59ed0 | ||
|
5895490b53 | ||
|
4e08acf509 | ||
|
e1bb3dbef6 | ||
|
562bcbf486 | ||
|
262a119413 | ||
|
609cafeb2c | ||
|
6dc4e7708a | ||
|
3fdb60d708 | ||
|
12130361fd | ||
|
faad23ed64 | ||
|
674e78b3d0 | ||
|
302e42d1d0 | ||
|
1aca1b6caf | ||
|
1b60935f38 | ||
|
188f0261b5 | ||
|
1b06270e9b | ||
|
f3ffa29a37 | ||
|
7246278745 | ||
|
e5173bb9a2 | ||
|
fd56a14eb6 | ||
|
35c20110ca | ||
|
a871753bdf | ||
|
fbf178326a | ||
|
8fedef9024 | ||
|
094f124a18 | ||
|
1f5856c671 | ||
|
ae106566dd | ||
|
b3922b3255 | ||
|
5fa53a7ab8 | ||
|
3ac1ada204 | ||
|
2dc78ee0aa | ||
|
4b16ca4a30 | ||
|
6a2b74b0dc | ||
|
3171792bd6 | ||
|
99ccc04933 | ||
|
34436ac261 | ||
|
ae44b7f826 | ||
|
0cf32d5988 | ||
|
013aa9ec92 | ||
|
62720dec13 | ||
|
c64943a954 | ||
|
6eea1325bf | ||
|
e205c16cdb | ||
|
fa755ae401 | ||
|
1b97953cdb | ||
|
fc19b2b9a5 | ||
|
e425b2c38e | ||
|
f5d2d27090 | ||
|
41ea9139c6 | ||
|
da946472df | ||
|
0ffbedb3ec | ||
|
eafeea1a76 | ||
|
fcda7a6921 | ||
|
a25f4f8b8d | ||
|
ceff67085b | ||
|
ec86a83a27 | ||
|
89c93185d4 | ||
|
c3004f8c6d | ||
|
a1c2c3856d | ||
|
fa8dd5992d | ||
|
0b28c55162 | ||
|
fb480993ed | ||
|
ef49701f14 | ||
|
34bc23fbbd | ||
|
a7e8a1dfb5 | ||
|
547e2546c7 | ||
|
e7b77f7721 |
2
.github/workflows/Release.yml
vendored
2
.github/workflows/Release.yml
vendored
@@ -195,7 +195,7 @@ jobs:
|
||||
Release:
|
||||
runs-on: ubuntu-latest
|
||||
# We need the RPMs, so add dependency
|
||||
needs: [AlmaLinux-RPM-build, UBI-8-RPM-build, Ubuntu-jammy-build]
|
||||
needs: [AlmaLinux-RPM-build, UBI-8-RPM-build, Ubuntu-focal-build]
|
||||
|
||||
steps:
|
||||
# See: https://github.com/actions/download-artifact
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
cclog "github.com/ClusterCockpit/cc-metric-collector/pkg/ccLogger"
|
||||
@@ -24,6 +25,81 @@ type NvidiaCollectorConfig struct {
|
||||
ProcessMigDevices bool `json:"process_mig_devices,omitempty"`
|
||||
UseUuidForMigDevices bool `json:"use_uuid_for_mig_device,omitempty"`
|
||||
UseSliceForMigDevices bool `json:"use_slice_for_mig_device,omitempty"`
|
||||
AveragePowerInterval string `json:"average_power_interval,omitempty"`
|
||||
}
|
||||
|
||||
type powerAverager struct {
|
||||
device nvml.Device
|
||||
interval time.Duration
|
||||
done chan bool
|
||||
wg sync.WaitGroup
|
||||
powerSum float64
|
||||
powerSamples int
|
||||
ticker *time.Ticker
|
||||
running bool
|
||||
}
|
||||
|
||||
type PowerAverager interface {
|
||||
Start()
|
||||
IsRunning() bool
|
||||
Get() float64
|
||||
Close()
|
||||
}
|
||||
|
||||
func (pa *powerAverager) IsRunning() bool {
|
||||
return pa.running
|
||||
}
|
||||
|
||||
func (pa *powerAverager) Start() {
|
||||
pa.wg.Add(1)
|
||||
|
||||
go func(avger *powerAverager) {
|
||||
avger.running = true
|
||||
avger.ticker = time.NewTicker(avger.interval)
|
||||
for {
|
||||
select {
|
||||
case <-avger.done:
|
||||
avger.wg.Done()
|
||||
avger.running = false
|
||||
return
|
||||
case <-avger.ticker.C:
|
||||
power, ret := nvml.DeviceGetPowerUsage(avger.device)
|
||||
if ret == nvml.SUCCESS {
|
||||
avger.powerSum += float64(power) / 1000
|
||||
avger.powerSamples += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}(pa)
|
||||
}
|
||||
|
||||
func (pa *powerAverager) Get() float64 {
|
||||
avg := float64(0)
|
||||
if pa.powerSamples > 0 {
|
||||
pa.ticker.Stop()
|
||||
avg = pa.powerSum / float64(pa.powerSamples)
|
||||
pa.powerSum = 0
|
||||
pa.powerSamples = 0
|
||||
pa.ticker.Reset(pa.interval)
|
||||
}
|
||||
return avg
|
||||
}
|
||||
|
||||
func (pa *powerAverager) Close() {
|
||||
pa.done <- true
|
||||
pa.wg.Wait()
|
||||
pa.running = false
|
||||
}
|
||||
|
||||
func NewPowerAverager(device nvml.Device, interval time.Duration) (PowerAverager, error) {
|
||||
pa := new(powerAverager)
|
||||
pa.device = device
|
||||
pa.interval = interval
|
||||
pa.done = make(chan bool)
|
||||
pa.powerSamples = 0
|
||||
pa.powerSum = 0
|
||||
pa.running = false
|
||||
return pa, nil
|
||||
}
|
||||
|
||||
type NvidiaCollectorDevice struct {
|
||||
@@ -31,6 +107,8 @@ type NvidiaCollectorDevice struct {
|
||||
excludeMetrics map[string]bool
|
||||
tags map[string]string
|
||||
meta map[string]string
|
||||
powerInterval time.Duration
|
||||
averager PowerAverager
|
||||
}
|
||||
|
||||
type NvidiaCollector struct {
|
||||
@@ -55,6 +133,7 @@ func (m *NvidiaCollector) Init(config json.RawMessage) error {
|
||||
m.config.ProcessMigDevices = false
|
||||
m.config.UseUuidForMigDevices = false
|
||||
m.config.UseSliceForMigDevices = false
|
||||
m.config.AveragePowerInterval = ""
|
||||
m.setup()
|
||||
if len(config) > 0 {
|
||||
err = json.Unmarshal(config, &m.config)
|
||||
@@ -93,6 +172,16 @@ func (m *NvidiaCollector) Init(config json.RawMessage) error {
|
||||
return err
|
||||
}
|
||||
|
||||
powerDur := time.Duration(0)
|
||||
if len(m.config.AveragePowerInterval) > 0 {
|
||||
d, err := time.ParseDuration(m.config.AveragePowerInterval)
|
||||
if err != nil {
|
||||
cclog.ComponentError(m.name, "Unable to parse average_power_interval ", m.config.AveragePowerInterval, ":", err.Error())
|
||||
return err
|
||||
}
|
||||
powerDur = d
|
||||
}
|
||||
|
||||
// For all GPUs
|
||||
idx := 0
|
||||
m.gpus = make([]NvidiaCollectorDevice, num_gpus)
|
||||
@@ -197,6 +286,15 @@ func (m *NvidiaCollector) Init(config json.RawMessage) error {
|
||||
g.excludeMetrics[e] = true
|
||||
}
|
||||
|
||||
if powerDur > 0 {
|
||||
a, err := NewPowerAverager(g.device, powerDur)
|
||||
if err != nil {
|
||||
cclog.ComponentError(m.name, "Failed to initialize power averager for device at index", i, ":", err.Error())
|
||||
} else {
|
||||
g.averager = a
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the index for the next device
|
||||
idx++
|
||||
}
|
||||
@@ -436,6 +534,21 @@ func readPerfState(device NvidiaCollectorDevice, output chan lp.CCMetric) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func readPowerUsageAverage(device NvidiaCollectorDevice, output chan lp.CCMetric) error {
|
||||
if !device.excludeMetrics["nv_power_usage_avg"] && device.averager != nil {
|
||||
if !device.averager.IsRunning() {
|
||||
device.averager.Start()
|
||||
} else {
|
||||
y, err := lp.New("nv_power_usage_avg", device.tags, device.meta, map[string]interface{}{"value": device.averager.Get()}, time.Now())
|
||||
if err == nil {
|
||||
y.AddMeta("unit", "watts")
|
||||
output <- y
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readPowerUsage(device NvidiaCollectorDevice, output chan lp.CCMetric) error {
|
||||
if !device.excludeMetrics["nv_power_usage"] {
|
||||
// Retrieves power usage for this GPU in milliwatts and its associated circuitry (e.g. memory)
|
||||
@@ -1022,95 +1135,100 @@ func (m *NvidiaCollector) Read(interval time.Duration, output chan lp.CCMetric)
|
||||
if ret != nvml.SUCCESS {
|
||||
name = "NoName"
|
||||
}
|
||||
err = readMemoryInfo(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readMemoryInfo for device", name, "failed")
|
||||
}
|
||||
// err = readMemoryInfo(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readMemoryInfo for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readUtilization(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readUtilization for device", name, "failed")
|
||||
}
|
||||
// err = readUtilization(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readUtilization for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readTemp(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readTemp for device", name, "failed")
|
||||
}
|
||||
// err = readTemp(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readTemp for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readFan(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readFan for device", name, "failed")
|
||||
}
|
||||
// err = readFan(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readFan for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readEccMode(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readEccMode for device", name, "failed")
|
||||
}
|
||||
// err = readEccMode(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readEccMode for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readPerfState(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readPerfState for device", name, "failed")
|
||||
}
|
||||
// err = readPerfState(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readPerfState for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readPowerUsage(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readPowerUsage for device", name, "failed")
|
||||
}
|
||||
|
||||
err = readClocks(device, output)
|
||||
err = readPowerUsageAverage(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readClocks for device", name, "failed")
|
||||
cclog.ComponentDebug(m.name, "readPowerUsageAverage for device", name, "failed")
|
||||
}
|
||||
|
||||
err = readMaxClocks(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readMaxClocks for device", name, "failed")
|
||||
}
|
||||
// err = readClocks(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readClocks for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readEccErrors(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readEccErrors for device", name, "failed")
|
||||
}
|
||||
// err = readMaxClocks(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readMaxClocks for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readPowerLimit(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readPowerLimit for device", name, "failed")
|
||||
}
|
||||
// err = readEccErrors(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readEccErrors for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readEncUtilization(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readEncUtilization for device", name, "failed")
|
||||
}
|
||||
// err = readPowerLimit(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readPowerLimit for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readDecUtilization(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readDecUtilization for device", name, "failed")
|
||||
}
|
||||
// err = readEncUtilization(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readEncUtilization for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readRemappedRows(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readRemappedRows for device", name, "failed")
|
||||
}
|
||||
// err = readDecUtilization(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readDecUtilization for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readBarMemoryInfo(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readBarMemoryInfo for device", name, "failed")
|
||||
}
|
||||
// err = readRemappedRows(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readRemappedRows for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readProcessCounts(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readProcessCounts for device", name, "failed")
|
||||
}
|
||||
// err = readBarMemoryInfo(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readBarMemoryInfo for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readViolationStats(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readViolationStats for device", name, "failed")
|
||||
}
|
||||
// err = readProcessCounts(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readProcessCounts for device", name, "failed")
|
||||
// }
|
||||
|
||||
err = readNVLinkStats(device, output)
|
||||
if err != nil {
|
||||
cclog.ComponentDebug(m.name, "readNVLinkStats for device", name, "failed")
|
||||
}
|
||||
// err = readViolationStats(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readViolationStats for device", name, "failed")
|
||||
// }
|
||||
|
||||
// err = readNVLinkStats(device, output)
|
||||
// if err != nil {
|
||||
// cclog.ComponentDebug(m.name, "readNVLinkStats for device", name, "failed")
|
||||
// }
|
||||
}
|
||||
|
||||
// Actual read loop over all attached Nvidia GPUs
|
||||
@@ -1198,6 +1316,9 @@ func (m *NvidiaCollector) Read(interval time.Duration, output chan lp.CCMetric)
|
||||
|
||||
func (m *NvidiaCollector) Close() {
|
||||
if m.init {
|
||||
for i := 0; i < m.num_gpus; i++ {
|
||||
m.gpus[i].averager.Close()
|
||||
}
|
||||
nvml.Shutdown()
|
||||
m.init = false
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@@ -9,7 +9,6 @@ require (
|
||||
github.com/PaesslerAG/gval v1.2.2
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gosnmp/gosnmp v1.37.0
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.12.3
|
||||
github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf
|
||||
github.com/influxdata/line-protocol/v2 v2.2.1
|
||||
|
38
go.sum
38
go.sum
@@ -8,7 +8,6 @@ github.com/ClusterCockpit/cc-units v0.4.0 h1:zP5DOu99GmErW0tCDf0gcLrlWt42RQ9dpoO
|
||||
github.com/ClusterCockpit/cc-units v0.4.0/go.mod h1:3S3PAhAayS3pbgcT4q9Vn9VJw22Op51X0YimtG77zBw=
|
||||
github.com/ClusterCockpit/go-rocm-smi v0.3.0 h1:1qZnSpG7/NyLtc7AjqnUL9Jb8xtqG1nMVgp69rJfaR8=
|
||||
github.com/ClusterCockpit/go-rocm-smi v0.3.0/go.mod h1:+I3UMeX3OlizXDf1WpGD43W4KGZZGVSGmny6rTeOnWA=
|
||||
github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
|
||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||
github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk=
|
||||
github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
|
||||
@@ -17,12 +16,10 @@ github.com/NVIDIA/go-nvml v0.12.0-1 h1:6mdjtlFo+17dWL7VFPfuRMtf0061TF4DKls9pkSw6
|
||||
github.com/NVIDIA/go-nvml v0.12.0-1/go.mod h1:hy7HYeQy335x6nEss0Ne3PYqleRa6Ct+VKD9RQ4nyFs=
|
||||
github.com/PaesslerAG/gval v1.2.2 h1:Y7iBzhgE09IGTt5QgGQ2IdaYYYOU134YGHBThD+wm9E=
|
||||
github.com/PaesslerAG/gval v1.2.2/go.mod h1:XRFLwvmkTEdYziLdaCeCa5ImcGVrfQbeNUbVR+C6xac=
|
||||
github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI=
|
||||
github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
|
||||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
|
||||
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
@@ -36,6 +33,7 @@ github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1
|
||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
|
||||
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
@@ -46,18 +44,15 @@ github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo
|
||||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deepmap/oapi-codegen v1.15.0 h1:SQqViaeb4k2vMul8gx12oDOIadEtoRqTdLkxjzqtQ90=
|
||||
github.com/deepmap/oapi-codegen v1.15.0/go.mod h1:a6KoHV7lMRwsPoEg2C6NDHiXYV3EQfiFocOlJ8dgJQE=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
|
||||
github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
|
||||
github.com/frankban/quicktest v1.11.0/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s=
|
||||
github.com/frankban/quicktest v1.11.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s=
|
||||
github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk=
|
||||
github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
@@ -67,14 +62,12 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24=
|
||||
github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -87,8 +80,6 @@ github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 h1:EcQR3gusLHN
|
||||
github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -96,22 +87,16 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
||||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gosnmp/gosnmp v1.37.0 h1:/Tf8D3b9wrnNuf/SfbvO+44mPrjVphBhRtcGg22V07Y=
|
||||
github.com/gosnmp/gosnmp v1.37.0/go.mod h1:GDH9vNqpsD7f2HvZhKs5dlqSEcAS6s6Qp099oZRCR+M=
|
||||
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.12.3 h1:28nRlNMRIV4QbtIUvxhWqaxn0IpXeMSkY/uJa/O/vC4=
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.12.3/go.mod h1:IrrLUbCjjfkmRuaCiGQg4m2GbkaeJDcuWoxiWdQEbA0=
|
||||
github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf h1:7JTmneyiNEwVBOHSjoMxiWAqB992atOeepeFYegn5RU=
|
||||
github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
|
||||
github.com/influxdata/line-protocol-corpus v0.0.0-20210519164801-ca6fa5da0184/go.mod h1:03nmhxzZ7Xk2pdG+lmMd7mHDfeVOYFyhOgwO61qWU98=
|
||||
github.com/influxdata/line-protocol-corpus v0.0.0-20210922080147-aa28ccfb8937 h1:MHJNQ+p99hFATQm6ORoLmpUCF7ovjwEFshs/NHzAbig=
|
||||
github.com/influxdata/line-protocol-corpus v0.0.0-20210922080147-aa28ccfb8937/go.mod h1:BKR9c0uHSmRgM/se9JhFHtTT7JTO67X23MtKMHtZcpo=
|
||||
github.com/influxdata/line-protocol/v2 v2.0.0-20210312151457-c52fdecb625a/go.mod h1:6+9Xt5Sq1rWx+glMgxhcg2c0DUaehK+5TDcPZ76GypY=
|
||||
github.com/influxdata/line-protocol/v2 v2.1.0/go.mod h1:QKw43hdUBg3GTk2iC3iyCxksNj7PX9aUSeYOYE/ceHY=
|
||||
github.com/influxdata/line-protocol/v2 v2.2.1 h1:EAPkqJ9Km4uAxtMRgUubJyqAr6zgWM0dznKMLRauQRE=
|
||||
github.com/influxdata/line-protocol/v2 v2.2.1/go.mod h1:DmB3Cnh+3oxmG6LOBIxce4oaL4CPj3OmMPgvauXh+tM=
|
||||
github.com/iris-contrib/httpexpect/v2 v2.15.2 h1:T9THsdP1woyAqKHwjkEsbCnMefsAFvk8iJJKokcJ3Go=
|
||||
github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw=
|
||||
github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
@@ -138,10 +123,8 @@ github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/q
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4=
|
||||
github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ=
|
||||
@@ -164,15 +147,11 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zk
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
|
||||
github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
|
||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/nats-io/jwt/v2 v2.5.0 h1:WQQ40AAlqqfx+f6ku+i0pOVm+ASirD4fUh+oQsiE9Ak=
|
||||
github.com/nats-io/nats-server/v2 v2.8.4 h1:0jQzze1T9mECg8YZEl8+WYUXb9JKluJfCBriPUtluB4=
|
||||
github.com/nats-io/nats-server/v2 v2.8.4/go.mod h1:8zZa+Al3WsESfmgSs98Fi06dRWLH5Bnq90m5bKD/eT4=
|
||||
github.com/nats-io/nats.go v1.30.2 h1:aloM0TGpPorZKQhbAkdCzYDj+ZmsJDyeo3Gkbr72NuY=
|
||||
github.com/nats-io/nats.go v1.30.2/go.mod h1:dcfhUgmQNN4GJEfIb2f9R7Fow+gzBF4emzDHrVBd5qM=
|
||||
@@ -185,7 +164,6 @@ github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6
|
||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
@@ -195,13 +173,10 @@ github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdO
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
@@ -220,13 +195,11 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tdewolff/minify/v2 v2.12.9 h1:dvn5MtmuQ/DFMwqf5j8QhEVpPX6fi3WGImhv8RUB4zA=
|
||||
github.com/tdewolff/minify/v2 v2.12.9/go.mod h1:qOqdlDfL+7v0/fyymB+OP497nIxJYSvX4MQWA8OoiXU=
|
||||
github.com/tdewolff/parse/v2 v2.6.8 h1:mhNZXYCx//xG7Yq2e/kVLNZw4YfYmeHbhx+Zc0OvFMA=
|
||||
github.com/tdewolff/parse/v2 v2.6.8/go.mod h1:XHDhaU6IBgsryfdnpzUXBlT6leW/l25yrFBTEb4eIyM=
|
||||
github.com/tdewolff/test v1.0.9 h1:SswqJCmeN4B+9gEAi/5uqT0qpi1y2/2O47V/1hhGZT0=
|
||||
github.com/tdewolff/test v1.0.9/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
@@ -245,14 +218,8 @@ github.com/vmihailenco/msgpack/v5 v5.4.0 h1:hRM0digJwyR6vll33NNAwCFguy5JuBD6jxDm
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.0/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
|
||||
github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
|
||||
github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
|
||||
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.design/x/thread v0.0.0-20210122121316-335e9adffdf1 h1:P7S/GeHBAFEZIYp0ePPs2kHXoazz8q2KsyxHyQVGCJg=
|
||||
golang.design/x/thread v0.0.0-20210122121316-335e9adffdf1/go.mod h1:9CWpnTUmlQkfdpdutA1nNf4iE5lAVt3QZOu0Z6hahBE=
|
||||
@@ -316,16 +283,13 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
@@ -24,7 +24,6 @@ This allows to specify
|
||||
- [`http`](./httpReceiver.md): Listen for HTTP Post requests transporting metrics in InfluxDB line protocol
|
||||
- [`ipmi`](./ipmiReceiver.md): Read IPMI sensor readings
|
||||
- [`redfish`](redfishReceiver.md) Use the Redfish (specification) to query thermal and power metrics
|
||||
- [`snmp`](./snmpReceiver.md) Query SNMP endpoints in the network
|
||||
|
||||
## Contributing own receivers
|
||||
|
||||
|
@@ -15,7 +15,6 @@ var AvailableReceivers = map[string]func(name string, config json.RawMessage) (R
|
||||
"ipmi": NewIPMIReceiver,
|
||||
"nats": NewNatsReceiver,
|
||||
"redfish": NewRedfishReceiver,
|
||||
"snmp": NewSNMPReceiver,
|
||||
}
|
||||
|
||||
type receiveManager struct {
|
||||
|
@@ -1,294 +0,0 @@
|
||||
package receivers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
cclog "github.com/ClusterCockpit/cc-metric-collector/pkg/ccLogger"
|
||||
lp "github.com/ClusterCockpit/cc-metric-collector/pkg/ccMetric"
|
||||
"github.com/gosnmp/gosnmp"
|
||||
)
|
||||
|
||||
type SNMPReceiverTargetConfig struct {
|
||||
Hostname string `json:"hostname"`
|
||||
Port int `json:"port,omitempty"`
|
||||
Community string `json:"community,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty"`
|
||||
timeout time.Duration
|
||||
Version string `json:"version,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
TypeId string `json:"type-id,omitempty"`
|
||||
SubType string `json:"subtype,omitempty"`
|
||||
SubTypeId string `json:"subtype-id,omitempty"`
|
||||
}
|
||||
|
||||
type SNMPReceiverMetricConfig struct {
|
||||
Name string `json:"name"`
|
||||
OID string `json:"oid"`
|
||||
Unit string `json:"unit,omitempty"`
|
||||
}
|
||||
|
||||
// SNMPReceiver configuration: receiver type, listen address, port
|
||||
type SNMPReceiverConfig struct {
|
||||
Type string `json:"type"`
|
||||
Targets []SNMPReceiverTargetConfig `json:"targets"`
|
||||
Metrics []SNMPReceiverMetricConfig `json:"metrics"`
|
||||
ReadInterval string `json:"read_interval,omitempty"`
|
||||
}
|
||||
|
||||
type SNMPReceiver struct {
|
||||
receiver
|
||||
config SNMPReceiverConfig
|
||||
|
||||
// Storage for static information
|
||||
meta map[string]string
|
||||
tags map[string]string
|
||||
// Use in case of own go routine
|
||||
done chan bool
|
||||
wg sync.WaitGroup
|
||||
interval time.Duration
|
||||
}
|
||||
|
||||
func validOid(oid string) bool {
|
||||
// Regex from https://github.com/BornToBeRoot/NETworkManager/blob/6805740762bf19b95051c7eaa73cf2b4727733c3/Source/NETworkManager.Utilities/RegexHelper.cs#L88
|
||||
// Match on leading dot added by Thomas Gruber <thomas.gruber@fau.de>
|
||||
match, err := regexp.MatchString(`^[\.]?[012]\.(?:[0-9]|[1-3][0-9])(\.\d+)*$`, oid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
func (r *SNMPReceiver) readTarget(target SNMPReceiverTargetConfig, output chan lp.CCMetric) {
|
||||
port := uint16(161)
|
||||
comm := "public"
|
||||
timeout := time.Duration(1) * time.Second
|
||||
version := gosnmp.Version2c
|
||||
timestamp := time.Now()
|
||||
if target.Port > 0 {
|
||||
port = uint16(target.Port)
|
||||
}
|
||||
if len(target.Community) > 0 {
|
||||
comm = target.Community
|
||||
}
|
||||
if target.timeout > 0 {
|
||||
timeout = target.timeout
|
||||
}
|
||||
if len(target.Version) > 0 {
|
||||
switch target.Version {
|
||||
case "1":
|
||||
version = gosnmp.Version1
|
||||
case "2c":
|
||||
version = gosnmp.Version2c
|
||||
case "3":
|
||||
version = gosnmp.Version3
|
||||
default:
|
||||
cclog.ComponentError(r.name, "Invalid SNMP version ", target.Version)
|
||||
return
|
||||
}
|
||||
}
|
||||
params := &gosnmp.GoSNMP{
|
||||
Target: target.Hostname,
|
||||
Port: port,
|
||||
Community: comm,
|
||||
Version: version,
|
||||
Timeout: timeout,
|
||||
}
|
||||
err := params.Connect()
|
||||
if err != nil {
|
||||
cclog.ComponentError(r.name, err.Error())
|
||||
return
|
||||
}
|
||||
for _, metric := range r.config.Metrics {
|
||||
if !validOid(metric.OID) {
|
||||
cclog.ComponentDebug(r.name, "Skipping ", metric.Name, ", not valid OID: ", metric.OID)
|
||||
continue
|
||||
}
|
||||
oids := make([]string, 0)
|
||||
name := gosnmp.SnmpPDU{
|
||||
Value: metric.Name,
|
||||
Name: metric.Name,
|
||||
}
|
||||
nameidx := -1
|
||||
value := gosnmp.SnmpPDU{
|
||||
Value: nil,
|
||||
Name: metric.OID,
|
||||
}
|
||||
valueidx := -1
|
||||
unit := gosnmp.SnmpPDU{
|
||||
Value: metric.Unit,
|
||||
Name: metric.Unit,
|
||||
}
|
||||
unitidx := -1
|
||||
idx := 0
|
||||
if validOid(metric.Name) {
|
||||
oids = append(oids, metric.Name)
|
||||
nameidx = idx
|
||||
idx = idx + 1
|
||||
}
|
||||
if validOid(metric.OID) {
|
||||
oids = append(oids, metric.OID)
|
||||
valueidx = idx
|
||||
idx = idx + 1
|
||||
}
|
||||
if len(metric.Unit) > 0 && validOid(metric.Unit) {
|
||||
oids = append(oids, metric.Unit)
|
||||
unitidx = idx
|
||||
}
|
||||
//cclog.ComponentDebug(r.name, len(oids), oids)
|
||||
result, err := params.Get(oids)
|
||||
if err != nil {
|
||||
cclog.ComponentError(r.name, "failed to get data for OIDs ", strings.Join(oids, ","), ": ", err.Error())
|
||||
continue
|
||||
}
|
||||
if nameidx >= 0 && len(result.Variables) > nameidx {
|
||||
name = result.Variables[nameidx]
|
||||
}
|
||||
if valueidx >= 0 && len(result.Variables) > valueidx {
|
||||
value = result.Variables[valueidx]
|
||||
}
|
||||
if unitidx >= 0 && len(result.Variables) > unitidx {
|
||||
unit = result.Variables[unitidx]
|
||||
}
|
||||
tags := r.tags
|
||||
if len(target.Type) > 0 {
|
||||
tags["type"] = target.Type
|
||||
}
|
||||
if len(target.TypeId) > 0 {
|
||||
tags["type-id"] = target.TypeId
|
||||
}
|
||||
if len(target.SubType) > 0 {
|
||||
tags["stype"] = target.SubType
|
||||
}
|
||||
if len(target.SubTypeId) > 0 {
|
||||
tags["stype-id"] = target.SubTypeId
|
||||
}
|
||||
if value.Value != nil {
|
||||
y, err := lp.New(name.Value.(string), tags, r.meta, map[string]interface{}{"value": value.Value}, timestamp)
|
||||
if err == nil {
|
||||
if len(unit.Name) > 0 && unit.Value != nil {
|
||||
y.AddMeta("unit", unit.Value.(string))
|
||||
}
|
||||
output <- y
|
||||
}
|
||||
}
|
||||
}
|
||||
params.Conn.Close()
|
||||
}
|
||||
|
||||
// Implement functions required for Receiver interface
|
||||
// Start(), Close()
|
||||
// See: metricReceiver.go
|
||||
|
||||
func (r *SNMPReceiver) Start() {
|
||||
cclog.ComponentDebug(r.name, "START")
|
||||
|
||||
r.done = make(chan bool)
|
||||
r.wg.Add(1)
|
||||
go func() {
|
||||
defer r.wg.Done()
|
||||
|
||||
// Create ticker
|
||||
ticker := time.NewTicker(r.interval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
// process ticker event -> continue
|
||||
if r.sink != nil {
|
||||
for _, t := range r.config.Targets {
|
||||
select {
|
||||
case <-r.done:
|
||||
return
|
||||
default:
|
||||
r.readTarget(t, r.sink)
|
||||
}
|
||||
}
|
||||
}
|
||||
continue
|
||||
case <-r.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Close receiver: close network connection, close files, close libraries, ...
|
||||
func (r *SNMPReceiver) Close() {
|
||||
cclog.ComponentDebug(r.name, "CLOSE")
|
||||
|
||||
r.done <- true
|
||||
r.wg.Wait()
|
||||
}
|
||||
|
||||
// New function to create a new instance of the receiver
|
||||
// Initialize the receiver by giving it a name and reading in the config JSON
|
||||
func NewSNMPReceiver(name string, config json.RawMessage) (Receiver, error) {
|
||||
var err error = nil
|
||||
r := new(SNMPReceiver)
|
||||
|
||||
// Set name of SNMPReceiver
|
||||
// The name should be chosen in such a way that different instances of SNMPReceiver can be distinguished
|
||||
r.name = fmt.Sprintf("SNMPReceiver(%s)", name)
|
||||
|
||||
// Set static information
|
||||
r.meta = map[string]string{"source": r.name, "group": "SNMP"}
|
||||
r.tags = map[string]string{"type": "node"}
|
||||
|
||||
// Set defaults in r.config
|
||||
r.interval = time.Duration(30) * time.Second
|
||||
|
||||
// Read the sample receiver specific JSON config
|
||||
if len(config) > 0 {
|
||||
err := json.Unmarshal(config, &r.config)
|
||||
if err != nil {
|
||||
cclog.ComponentError(r.name, "Error reading config:", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all required fields in the configuration are set
|
||||
if len(r.config.Targets) == 0 {
|
||||
err = fmt.Errorf("no targets configured, exiting")
|
||||
cclog.ComponentError(r.name, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(r.config.Metrics) == 0 {
|
||||
err = fmt.Errorf("no metrics configured, exiting")
|
||||
cclog.ComponentError(r.name, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(r.config.ReadInterval) > 0 {
|
||||
d, err := time.ParseDuration(r.config.ReadInterval)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to parse read interval, exiting")
|
||||
cclog.ComponentError(r.name, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
r.interval = d
|
||||
}
|
||||
newtargets := make([]SNMPReceiverTargetConfig, 0)
|
||||
for _, t := range r.config.Targets {
|
||||
t.timeout = time.Duration(1) * time.Second
|
||||
if len(t.Timeout) > 0 {
|
||||
d, err := time.ParseDuration(t.Timeout)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to parse interval for target %s", t.Hostname)
|
||||
cclog.ComponentError(r.name, err.Error())
|
||||
continue
|
||||
}
|
||||
t.timeout = d
|
||||
}
|
||||
newtargets = append(newtargets, t)
|
||||
}
|
||||
r.config.Targets = newtargets
|
||||
|
||||
return r, nil
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
# SNMP Receiver
|
||||
|
||||
```json
|
||||
"<name>": {
|
||||
"type": "snmp",
|
||||
"read_interval": "30s",
|
||||
"targets" : [{
|
||||
"hostname" : "host1.example.com",
|
||||
"port" : 161,
|
||||
"community": "public",
|
||||
"timeout" : 1,
|
||||
}],
|
||||
"metrics" : [
|
||||
{
|
||||
"name": "sensor1",
|
||||
"value": "1.3.6.1.2.1.1.4.0",
|
||||
"unit": "1.3.6.1.2.1.1.7.0",
|
||||
},
|
||||
{
|
||||
"name": "1.3.6.1.2.1.1.2.0",
|
||||
"value": "1.3.6.1.2.1.1.4.0",
|
||||
"unit": "mb/s",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `snmp` receiver uses [gosnmp](https://github.com/gosnmp/gosnmp) to read metrics from network-attached devices.
|
||||
|
||||
The configuration of SNMP is quite extensive due to it's flexibility.
|
||||
|
||||
## Configuration
|
||||
|
||||
- `type` has to be `snmp`
|
||||
- `read_interval` as duration like '1s' or '20s' (default '30s')
|
||||
|
||||
For the receiver, the configuration is split in two parts:
|
||||
### Target configuration
|
||||
|
||||
Each network-attached device that should be queried. A target consits of
|
||||
- `hostname`
|
||||
- `port` (default 161)
|
||||
- `community` (default `public`)
|
||||
- `timeout` as duration like '1s' or '20s' (default '1s')
|
||||
- `version` SNMP version `X` (`X` in `1`, `2c`, `3`) (default `2c`)
|
||||
- `type` to specify `type` tag for the target (default `node`)
|
||||
- `type-id` to specify `type-id` tag for the target
|
||||
- `stype` to specify `stype` tag (sub type) for the target
|
||||
- `stype-id` to specify `stype-id` tag for the target
|
||||
|
||||
### Metric configuration
|
||||
- `name` can be an OID or a user-given string
|
||||
- `value` has to be an OID
|
||||
- `unit` can be empty, an OID or a user-given string
|
||||
|
||||
If a OID is used for `name` or `unit`, the receiver will use the returned values to create the output metric. If there are any issues with the returned values, it uses the `OID`.
|
||||
|
||||
## Testing
|
||||
|
||||
For testing an SNMP endpoint and OIDs, you can use [`scripts/snmpReceiverTest`](../scripts/snmpReceiverTest)
|
@@ -25,7 +25,7 @@ CC_USER=clustercockpit
|
||||
CC_GROUP=clustercockpit
|
||||
CONF_DIR=/etc/cc-metric-collector
|
||||
PID_FILE=/var/run/$NAME.pid
|
||||
DAEMON=/usr/sbin/$NAME
|
||||
DAEMON=/usr/bin/$NAME
|
||||
CONF_FILE=${CONF_DIR}/cc-metric-collector.json
|
||||
|
||||
umask 0027
|
||||
|
@@ -1,37 +0,0 @@
|
||||
# snmpReceiverTest
|
||||
|
||||
This script is a basic implementation of how the SNMPReceiver to test the connection before configuring
|
||||
the collector to get the data periodically.
|
||||
|
||||
It does not support the specification of the `type`, `type-id`, `stype` and `stype-id` but since they are
|
||||
not required to test the functionality, they are left out.
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
$ go run snmpReceiverTest -h
|
||||
Usage of snmpReceiverTest:
|
||||
-community string
|
||||
SNMP community (default "public")
|
||||
-hostname string
|
||||
Hostname (default "127.0.0.1")
|
||||
-name string
|
||||
Name of metric or OID
|
||||
-port string
|
||||
Port number (default "161")
|
||||
-timeout string
|
||||
Timeout for SNMP request (default "1s")
|
||||
-unit string
|
||||
Unit of metric or OID
|
||||
-value string
|
||||
Value OID
|
||||
-version string
|
||||
SNMP version (default "2c")
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```sh
|
||||
$ go run scripts/snmpReceiverTest/snmpReceiverTest.go -name serialNumber -value .1.3.6.1.4.1.6574.1.5.2.0 -hostname $IP -community $COMMUNITY
|
||||
Name: serialNumber, Tags: map[type:node], Meta: map[], fields: map[value:18B0PCNXXXXX], Timestamp: 1702050709599311288
|
||||
```
|
@@ -1,167 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
lp "github.com/ClusterCockpit/cc-metric-collector/pkg/ccMetric"
|
||||
"github.com/gosnmp/gosnmp"
|
||||
)
|
||||
|
||||
func ReadCLI() map[string]string {
|
||||
args := map[string]string{
|
||||
"port": "161",
|
||||
"community": "public",
|
||||
"version": "2c",
|
||||
"hostname": "127.0.0.1",
|
||||
"timeout": "1s",
|
||||
}
|
||||
|
||||
host_cfg := flag.String("hostname", "127.0.0.1", "Hostname")
|
||||
port_cfg := flag.String("port", "161", "Port number")
|
||||
comm_cfg := flag.String("community", "public", "SNMP community")
|
||||
vers_cfg := flag.String("version", "2c", "SNMP version")
|
||||
time_cfg := flag.String("timeout", "1s", "Timeout for SNMP request")
|
||||
|
||||
name_cfg := flag.String("name", "", "Name of metric or OID")
|
||||
value_cfg := flag.String("value", "", "Value OID")
|
||||
unit_cfg := flag.String("unit", "", "Unit of metric or OID")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
args["port"] = *port_cfg
|
||||
args["community"] = *comm_cfg
|
||||
args["hostname"] = *host_cfg
|
||||
args["version"] = *vers_cfg
|
||||
args["timeout"] = *time_cfg
|
||||
|
||||
args["name"] = *name_cfg
|
||||
args["value"] = *value_cfg
|
||||
args["unit"] = *unit_cfg
|
||||
|
||||
if len(args["name"]) == 0 || len(args["value"]) == 0 {
|
||||
fmt.Printf("Required arguments: --name and --value\n")
|
||||
flag.Usage()
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func validOid(oid string) bool {
|
||||
// Regex from https://github.com/BornToBeRoot/NETworkManager/blob/6805740762bf19b95051c7eaa73cf2b4727733c3/Source/NETworkManager.Utilities/RegexHelper.cs#L88
|
||||
// Match on leading dot added by Thomas Gruber <thomas.gruber@fau.de>
|
||||
match, err := regexp.MatchString(`^[\.]?[012]\.(?:[0-9]|[1-3][0-9])(\.\d+)*$`, oid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
args := ReadCLI()
|
||||
|
||||
if len(args["name"]) == 0 || len(args["value"]) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
version := gosnmp.Version2c
|
||||
if len(args["version"]) > 0 {
|
||||
switch args["version"] {
|
||||
case "1":
|
||||
version = gosnmp.Version1
|
||||
case "2c":
|
||||
version = gosnmp.Version2c
|
||||
case "3":
|
||||
version = gosnmp.Version3
|
||||
default:
|
||||
fmt.Printf("Invalid SNMP version '%s'\n", args["version"])
|
||||
return
|
||||
}
|
||||
}
|
||||
v, err := strconv.ParseInt(args["port"], 10, 16)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse port number '%s'\n", args["port"])
|
||||
return
|
||||
}
|
||||
port := uint16(v)
|
||||
|
||||
t, err := time.ParseDuration(args["timeout"])
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse timeout '%s'\n", args["timeout"])
|
||||
return
|
||||
}
|
||||
timeout := t
|
||||
|
||||
params := &gosnmp.GoSNMP{
|
||||
Target: args["hostname"],
|
||||
Port: port,
|
||||
Community: args["community"],
|
||||
Version: version,
|
||||
Timeout: timeout,
|
||||
}
|
||||
err = params.Connect()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to connect to %s:%d : %v\n", params.Target, params.Port, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
oids := make([]string, 0)
|
||||
idx := 0
|
||||
name := gosnmp.SnmpPDU{
|
||||
Value: args["name"],
|
||||
Name: args["name"],
|
||||
}
|
||||
nameidx := -1
|
||||
value := gosnmp.SnmpPDU{
|
||||
Value: nil,
|
||||
Name: args["value"],
|
||||
}
|
||||
valueidx := -1
|
||||
unit := gosnmp.SnmpPDU{
|
||||
Value: args["unit"],
|
||||
Name: args["unit"],
|
||||
}
|
||||
unitidx := -1
|
||||
if validOid(args["name"]) {
|
||||
oids = append(oids, args["name"])
|
||||
nameidx = idx
|
||||
idx++
|
||||
}
|
||||
if validOid(args["value"]) {
|
||||
oids = append(oids, args["value"])
|
||||
valueidx = idx
|
||||
idx++
|
||||
}
|
||||
if len(args["unit"]) > 0 && validOid(args["unit"]) {
|
||||
oids = append(oids, args["unit"])
|
||||
unitidx = idx
|
||||
}
|
||||
result, err := params.Get(oids)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to get data for OIDs [%s] : %v\n", strings.Join(oids, ", "), err.Error())
|
||||
return
|
||||
}
|
||||
if nameidx >= 0 && len(result.Variables) > nameidx {
|
||||
name = result.Variables[nameidx]
|
||||
}
|
||||
if valueidx >= 0 && len(result.Variables) > valueidx {
|
||||
value = result.Variables[valueidx]
|
||||
}
|
||||
if unitidx >= 0 && len(result.Variables) > unitidx {
|
||||
unit = result.Variables[unitidx]
|
||||
}
|
||||
if value.Value != nil {
|
||||
y, err := lp.New(name.Value.(string), map[string]string{"type": "node"}, map[string]string{}, map[string]interface{}{"value": value.Value}, time.Now())
|
||||
if err == nil {
|
||||
if len(unit.Name) > 0 && unit.Value != nil {
|
||||
y.AddMeta("unit", unit.Value.(string))
|
||||
}
|
||||
fmt.Println(y)
|
||||
}
|
||||
}
|
||||
}
|
@@ -45,6 +45,9 @@ type HttpSinkConfig struct {
|
||||
|
||||
// Maximum number of retries to connect to the http server (default: 3)
|
||||
MaxRetries int `json:"max_retries,omitempty"`
|
||||
|
||||
// Timestamp precision
|
||||
Precision string `json:"precision,omitempty"`
|
||||
}
|
||||
|
||||
type key_value_pair struct {
|
||||
@@ -141,7 +144,7 @@ func (s *HttpSink) Write(m lp.CCMetric) error {
|
||||
|
||||
// Check that encoding worked
|
||||
if err != nil {
|
||||
return fmt.Errorf("Encoding failed: %v", err)
|
||||
return fmt.Errorf("encoding failed: %v", err)
|
||||
}
|
||||
|
||||
if s.config.flushDelay == 0 {
|
||||
@@ -268,6 +271,7 @@ func NewHttpSink(name string, config json.RawMessage) (Sink, error) {
|
||||
s.config.Timeout = "5s"
|
||||
s.config.FlushDelay = "5s"
|
||||
s.config.MaxRetries = 3
|
||||
s.config.Precision = "ns"
|
||||
cclog.ComponentDebug(s.name, "Init()")
|
||||
|
||||
// Read config
|
||||
@@ -315,6 +319,19 @@ func NewHttpSink(name string, config json.RawMessage) (Sink, error) {
|
||||
cclog.ComponentDebug(s.name, "Init(): flushDelay", t)
|
||||
}
|
||||
}
|
||||
precision := influx.Nanosecond
|
||||
if len(s.config.Precision) > 0 {
|
||||
switch s.config.Precision {
|
||||
case "s":
|
||||
precision = influx.Second
|
||||
case "ms":
|
||||
precision = influx.Millisecond
|
||||
case "us":
|
||||
precision = influx.Microsecond
|
||||
case "ns":
|
||||
precision = influx.Nanosecond
|
||||
}
|
||||
}
|
||||
|
||||
// Create http client
|
||||
s.client = &http.Client{
|
||||
@@ -326,7 +343,7 @@ func NewHttpSink(name string, config json.RawMessage) (Sink, error) {
|
||||
}
|
||||
|
||||
// Configure influx line protocol encoder
|
||||
s.encoder.SetPrecision(influx.Nanosecond)
|
||||
s.encoder.SetPrecision(precision)
|
||||
s.extended_tag_list = make([]key_value_pair, 0)
|
||||
|
||||
return s, nil
|
||||
|
@@ -18,7 +18,8 @@ The `http` sink uses POST requests to a HTTP server to submit the metrics in the
|
||||
"timeout": "5s",
|
||||
"idle_connection_timeout" : "5s",
|
||||
"flush_delay": "2s",
|
||||
"batch_size": 1000
|
||||
"batch_size": 1000,
|
||||
"precision": "s"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -34,3 +35,8 @@ The `http` sink uses POST requests to a HTTP server to submit the metrics in the
|
||||
- `idle_connection_timeout`: Timeout for idle connections (default '120s'). Should be larger than the measurement interval to keep the connection open
|
||||
- `flush_delay`: Batch all writes arriving in during this duration (default '1s', batching can be disabled by setting it to 0)
|
||||
- `batch_size`: Maximal batch size. If `batch_size` is reached before the end of `flush_delay`, the metrics are sent without further delay
|
||||
- `precision`: Precision of the timestamp. Valid values are 's', 'ms', 'us' and 'ns'. (default is 'ns')
|
||||
|
||||
### Using HttpSink for communication with cc-metric-store
|
||||
|
||||
The cc-metric-store only accepts metrics with a timestamp precision in seconds, so it is required to set `"precision": "s"`.
|
||||
|
@@ -25,3 +25,4 @@ The `nats` sink publishes all metrics into a NATS network. The publishing key is
|
||||
- `user`: Username for basic authentication
|
||||
- `password`: Password for basic authentication
|
||||
- `meta_as_tags`: print all meta information as tags in the output (optional)
|
||||
|
||||
|
Reference in New Issue
Block a user