Skip to content

Commit

Permalink
GROUNDWORK-3736 extend SNMP NonMibMetrics
Browse files Browse the repository at this point in the history
  • Loading branch information
Pavlo Sumkin committed Nov 28, 2024
1 parent 2b3e108 commit e013ccd
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 79 deletions.
158 changes: 80 additions & 78 deletions connectors/snmp/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type InterfaceMetric struct {
Key string
Mib string
Value int64
ts int64
}

func (state *MonitoringState) Init() {
Expand Down Expand Up @@ -79,56 +80,77 @@ func (device *DeviceExt) retrieveMonitoredServices(metricDefinitions map[string]
}

timestamp := transit.NewTimestamp()
ts := timestamp.Unix()
for _, iFace := range device.Interfaces {
var bytesInPrev, bytesOutPrev, bytesInX64Prev, bytesOutX64Prev int64 = -1, -1, -1, -1
if val, ok := previousValueCache.Get(fmt.Sprintf("%s:%s:%s", device.Name, iFace.Name, clients.IfInOctets)); ok {
bytesInPrev = val.(int64)
}
if val, ok := previousValueCache.Get(fmt.Sprintf("%s:%s:%s", device.Name, iFace.Name, clients.IfOutOctets)); ok {
bytesOutPrev = val.(int64)
}
if val, ok := previousValueCache.Get(fmt.Sprintf("%s:%s:%s", device.Name, iFace.Name, clients.IfHCInOctets)); ok {
bytesInX64Prev = val.(int64)
}
if val, ok := previousValueCache.Get(fmt.Sprintf("%s:%s:%s", device.Name, iFace.Name, clients.IfHCOutOctets)); ok {
bytesOutX64Prev = val.(int64)
}

var metricsBuilder []connectors.MetricBuilder
for mib, metric := range iFace.Metrics {
if metricDefinition, has := metricDefinitions[metric.Mib]; has {
unitType := transit.UnitCounter

metricBuilder := connectors.MetricBuilder{
Name: metric.Key,
CustomName: metricDefinition.CustomName,
ComputeType: metricDefinition.ComputeType,
Expression: metricDefinition.Expression,
UnitType: unitType,
Warning: metricDefinition.WarningThreshold,
Critical: metricDefinition.CriticalThreshold,
StartTimestamp: timestamp,
EndTimestamp: timestamp,
Graphed: metricDefinition.Graphed,

Value: nil,
}

ck := fmt.Sprintf("%s:%s:%s", device.Name, iFace.Name, mib)
isDelta, isPreviousPresent, valueToSet := calculateValue(metricDefinition.MetricType, unitType,
ck, metric.Value)
for key := range clients.NonMibMetrics {
if metricDefinition, has := metricDefinitions[key]; has {
metricBuilder := makeMetricBuilder(metricDefinition, key, timestamp)

switch mib {
case clients.IfInOctets, clients.IfOutOctets, clients.IfHCInOctets, clients.IfHCOutOctets:
valueToSet = valueToSet * 8
switch key {
case clients.BytesPerSecondIn:
if prev, ok := previousValueCache.Get(makeCK(device.Name, iFace.Name, clients.IfInOctets)); ok {
prev := prev.(InterfaceMetric)
v := (iFace.Metrics[clients.IfInOctets].Value - prev.Value) / (ts - prev.ts)
metricBuilder.Value = v
metricsBuilder = append(metricsBuilder, metricBuilder)
metricBuilder.Name = "bitsPerSecondIn"
metricBuilder.Value = v * 8
metricsBuilder = append(metricsBuilder, metricBuilder)
}
if prev, ok := previousValueCache.Get(makeCK(device.Name, iFace.Name, clients.IfHCInOctets)); ok {
prev := prev.(InterfaceMetric)
v := (iFace.Metrics[clients.IfHCInOctets].Value - prev.Value) / (ts - prev.ts)
metricBuilder.Name = "bytesPerSecondHCIn"
metricBuilder.Value = v
metricsBuilder = append(metricsBuilder, metricBuilder)
metricBuilder.Name = "bitsPerSecondHCIn"
metricBuilder.Value = v * 8
metricsBuilder = append(metricsBuilder, metricBuilder)
}

case clients.BytesPerSecondOut:
if prev, ok := previousValueCache.Get(makeCK(device.Name, iFace.Name, clients.IfOutOctets)); ok {
prev := prev.(InterfaceMetric)
v := (iFace.Metrics[clients.IfOutOctets].Value - prev.Value) / (ts - prev.ts)
metricBuilder.Value = v
metricsBuilder = append(metricsBuilder, metricBuilder)
metricBuilder.Name = "bitsPerSecondOut"
metricBuilder.Value = v * 8
metricsBuilder = append(metricsBuilder, metricBuilder)
}
if prev, ok := previousValueCache.Get(makeCK(device.Name, iFace.Name, clients.IfHCOutOctets)); ok {
prev := prev.(InterfaceMetric)
v := (iFace.Metrics[clients.IfHCOutOctets].Value - prev.Value) / (ts - prev.ts)
metricBuilder.Name = "bytesPerSecondHCOut"
metricBuilder.Value = v
metricsBuilder = append(metricsBuilder, metricBuilder)
metricBuilder.Name = "bitsPerSecondHCOut"
metricBuilder.Value = v * 8
metricsBuilder = append(metricsBuilder, metricBuilder)
}
}
}
}

if !isDelta || (isDelta && isPreviousPresent) {
metricBuilder.Value = valueToSet
for mib, metric := range iFace.Metrics {
if metricDefinition, has := metricDefinitions[metric.Mib]; has {
metricBuilder := makeMetricBuilder(metricDefinition, metric.Key, timestamp)

ck := makeCK(device.Name, iFace.Name, mib)
if isDelta(metricDefinition.MetricType) {
if prev, ok := previousValueCache.Get(ck); ok {
metricBuilder.Value = metric.Value - prev.(InterfaceMetric).Value
metricsBuilder = append(metricsBuilder, metricBuilder)
}
} else {
metricBuilder.Value = metric.Value
metricsBuilder = append(metricsBuilder, metricBuilder)
}

previousValueCache.SetDefault(ck, metric.Value)
metric.ts = ts
previousValueCache.SetDefault(ck, metric)

// log.Debug().
// Interface("_ck", ck).
Expand All @@ -140,21 +162,6 @@ func (device *DeviceExt) retrieveMonitoredServices(metricDefinitions map[string]
}
}

for key := range clients.NonMibMetrics {
if metricDefinition, has := metricDefinitions[key]; has {
switch key {
case clients.BytesPerSecondIn:
metricBuilder := calculateBytesPerSecond(key, metricDefinition,
iFace.Metrics[clients.IfInOctets].Value*8, iFace.Metrics[clients.IfHCInOctets].Value*8, bytesInPrev, bytesInX64Prev, timestamp)
metricsBuilder = append(metricsBuilder, metricBuilder)
case clients.BytesPerSecondOut:
metricBuilder := calculateBytesPerSecond(key, metricDefinition,
iFace.Metrics[clients.IfOutOctets].Value*8, iFace.Metrics[clients.IfHCOutOctets].Value*8, bytesOutPrev, bytesOutX64Prev, timestamp)
metricsBuilder = append(metricsBuilder, metricBuilder)
}
}
}

mService, err := connectors.BuildServiceForMetrics(iFace.Name, device.Name, metricsBuilder)
if err != nil {
log.Err(err).Msgf("could not create monitored service '%s:%s'", device.Name, iFace.Name)
Expand Down Expand Up @@ -191,29 +198,15 @@ func calculateHostStatus(lastOk float64) transit.MonitorStatus {
return transit.HostUnreachable
}

func calculateValue(metricKind transit.MetricKind, unitType transit.UnitType,
ck string, currentValue int64) (bool, bool, int64) {
if strings.EqualFold(string(metricKind), string(transit.Delta)) {
if previousValue, present := previousValueCache.Get(ck); present {
switch unitType {
case transit.UnitCounter:
currentValue = currentValue - previousValue.(int64)
}
return true, true, currentValue
}
return true, false, currentValue
}
return false, false, currentValue
func isDelta(k transit.MetricKind) bool {
return strings.EqualFold(string(k), string(transit.Delta))
}

func calculateBytesPerSecond(metricName string, metricDefinition transit.MetricDefinition, current, currentX64, previous,
previousX64 int64, timestamp *transit.Timestamp) connectors.MetricBuilder {
seconds := int(connectors.CheckInterval.Seconds())
result := (current - previous) / int64(seconds)
if currentX64 > 0 && previousX64 > 0 {
result = (currentX64 - previousX64) / int64(seconds)
}
func makeCK(deviceName, iFaceName, mib string) string {
return fmt.Sprintf("%s:%s:%s", deviceName, iFaceName, mib)
}

func makeMetricBuilder(metricDefinition transit.MetricDefinition, metricName string, timestamp *transit.Timestamp) connectors.MetricBuilder {
return connectors.MetricBuilder{
Name: metricName,
CustomName: metricDefinition.CustomName,
Expand All @@ -225,7 +218,16 @@ func calculateBytesPerSecond(metricName string, metricDefinition transit.MetricD
StartTimestamp: timestamp,
EndTimestamp: timestamp,
Graphed: metricDefinition.Graphed,

Value: result,
}
}

/**
## [Consider SNMP Counters: Frequently Asked Questions](https://www.cisco.com/c/en/us/support/docs/ip/simple-network-management-protocol-snmp/26007-faq-snmpcounter.html)
Q. When do 64-bit counters be used?
A. [RFC 2233](https://www.ietf.org/rfc/rfc2233.txt) adopted expanded 64-bit counters for high capacity interfaces in which 32-bit counters do not provide enough capacity and wrap too fast.
> [!Note]
> Cisco IOS Software does not support 64-bit counters for interface speeds of less than 20 Mbps.
> This means that 64-bit counters are not supported on 10 Mb Ethernet ports. Only 100 Mb Fast-Ethernet and other high speed ports support 64-bit counters.
*/
4 changes: 3 additions & 1 deletion connectors/snmp/snmp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ func TestRetrieveMonitoredResources(t *testing.T) {
_ = state.retrieveMonitoredResources(metricDefinitions)

for k, v := range previousValueCache.Items() {
previousValueCache.SetDefault(k, v.Object.(int64)-10)
prev := v.Object.(InterfaceMetric)
prev.Value = prev.Value - 10
previousValueCache.SetDefault(k, prev)
}

// 2nd call for deltas
Expand Down

0 comments on commit e013ccd

Please sign in to comment.