6. Monitoring Variables

This section describes configuration of the monitoring variables. Note that we ship with the default variables already configured. If the set of variables we offer as the default suits your needs, you do not have to make any changes and can skip this section. However you can add your own variables or change some default settings in the variables we offer by adding configuration sections and statements described in this document.

Configuration of the monitoring variables consists of two major parts: Python hook scripts that generate variables and configuration file section that describes the way their values are presented in the UI.

6.1. How Monitoring Variables are Stored

Variables are kept in memory and when the UI requests data to build a graph, the server looks in memory buffer first. If the graph requires data beyond what it has in memory, it makes query to tsdb to pull old data. But first, it needs to find the variable and that is done by comparing the “triplet” from the query with what it has in memory buffers (no tsdb queries are made at this time). The “triplet” consists of three components separated by a dot:

variableName . DeviceId . ComponentId

For example:

cpuUtil.5.32

Here the variable name is “cpuUtil”, device id is 5 and component id is 32. In case of variables related to interfaces, the index (the last component in the triplet) is equal to ifIndex of the interface. In other cases the index is taken from the SNMP OID used to collect data about the component. Index is always unique for the given component of the device, that is, there are never two components of the same device with equal index values, however components of different devices can have the same index. Combination of device id and component index uniquely identifies the component.

There are two configuration parameters at play:

monitor.memoryPoolDurationHrs
monitor.retentionHrs

memoryPoolDurationHrs determines how long we keep data in memory as it keeps coming. As new data points come from the monitor, they are added to the head of the buffer and oldest data points are pulled from the back of the buffer and thrown away. The memory buffer always has no more than memoryPoolDurationHrs hours of data (or less, if we have just started)

Parameter retentionHrs determines the behavior in case data points stop coming in. The buffer is still there, but no new data points are added to it and old ones are not popped from the back. The server periodically checks the time stamp of the most fresh data point in all variables and if its time stamp is older than ( now - retentionHrs ), then it “expires” corresponding variable by throwing it away from memory completely. When this happens, it makes record that looks like this in the log:

Expiring stale variable totalPacketDrops.168.233, last modified Sat Mar 14 15:34:01 PDT 2015

Just grep for “Expiring stale variable”, there should be some in your logs.

The purpose of this is to drop variables that track things that don’t exist anymore, such as interfaces that went down and stay down for a long time or devices that dropped offline.

Looking at this the opposite way, the purpose of retention is to keep data in memory for a while even when interfaces or whole devices go down and stop responding. This way, you can still get graphs for them, even though corresponding line in the graph will stop at some point in time. However this can only work for a limited time which is no longer than smaller of the values of parameters memoryPoolDurationHrs and retentionHrs.

By default both memory pool duration and retention are set to 1 hour. You may need to tune both parameters. For example memoryPoolDurationHrs of 1 hr is probably too short, 24hr may be more operationally meaningful interval. Note that changing this will make the server use more RAM. Watch variables jvmMemTotal and jvmMemFree in the Graphing Workbench (both can be found in category Monitor) to check current server RAM footprint. You may need to add parameter -Xmx to the configuration parameter ui.args to force maximum amount of RAM the server is allowed to take and set it higher.

6.2. Python hook scripts that create Monitoring Variables

You can find copies of these scripts in the directory python/variable_builders in the distribution tar archive. Note that these scripts are copies of those NetSpyGlass uses to generate default variables. We provide these copies for reference and as an example you can study when you decide to add your own.

The main “runner” script is variable_builder_runner.py. It defines class VariableBuilder that has method execute(). To find and load this class, NetSpyGlass looks for the configuration parameter network.monitor.variableBuilder defined in the default configuration as follows:

network {
    monitor {
        variableBuilder = "variable_builders.variable_builder_runner.VariableBuilder"

NetSpyGlass finds the script, loads it and creates an object of the class VariableBuilder. Then, it calls method execute() with an object of the class PyDevice as a parameter. This is done in a loop for all monitored devices.

See section How to override the defaults below for the explanation how to set up your own variable builder script.

Method execute() returns a dictionary that describes monitoring variables for the device. This dictionary has the following structure:

{
    'sysUpTime': {
        'snmp_oid': 'SNMPv2-MIB:sysUpTime.0'
        'index': 2,
        'name': 'SNMP Agent',
        'data_format': MonitoringDataType.TimeTick,
    },

    'snmpInTotalReqVars': {
        'snmp_oid': 'SNMPv2-MIB:snmpInTotalReqVars.0',
        'index': 2,
        'name': 'SNMP Agent',
        'data_format': MonitoringDataType.Counter,
    },

In this example we create monitoring variables with names “sysUpTime” and “snmpInTotalReqVars”.

Built-in variable builder script variable_builders.variable_builder_runner.py relies on few specialized Python classes that generate variables for various aspects of the device, its hardware components and interfaces. Source code of these classes is also provided for reference in the same directory. For example, class DeviceVariableBuilder is responsible for building monitoring variables to monitor some metrics related to the device as a whole, whereas class InterfaceVariableBuilder makes variables to monitor parameters of network interfaces of the device.

Script variable_builders.variable_builder_runner.py uses methods of the class PyDevice to get lists of hardware components and network interfaces.

6.2.1. Selection of components to monitor

Python scripts used to generate monitoring variables also decide which h/w components or interfaces should be monitored. Functions have access to attributes name, address, tags and others both for the device and its components and interfaces.

For example, function InterfaceVariableBuilder.make_variables() analyzes tags of interfaces to decide which should be monitored. Class InterfaceVariableBuilder defines few functions that do this. Here is an example of a function that checks if the interface is in admin state ‘Up’ and is not a loopback or some kind of internal:

def is_interesting_interface(self, intf):
    """
    This function implements some basic checks to decide if we want to monitor this interface

    :type intf: PyNetworkInterface
    :param intf: PyNetworkInterface wrapper object
    :return:  True if we want to monitor this interface
    """
    return ('ifAdminStatus.Up' in intf.tags and
            not 'ifRole.LoopbackInterface' in intf.tags and
            not 'ifRole.OutOfBandManagement' in intf.tags and
            not 'ifRole.SimulatedInterface' in intf.tags and
            not 'ifRole.Internal' in intf.tags)

Tags are added to the interface object by the discovery process and tag selection Python hook script (see document tags.md)

6.2.2. The structure of the variable definition dictionary

In the end, function variable_builder_runner.VariableBuilder.execute() should return a dictionary where the key is variable name and value is a dictionary that describes the variable.

Most of the items in this dictionary are optional except for snmp_oid. Also, either component or index must be present.

The dictionary can have the following keys:

component

The value of this dictionary item is a reference to the hardware component or interface for which this variable is created. Both h/w component and interface objects have the name and index, so if the key component is provided, name and index become optional. However if you provide name or index in addition to component, they will override values read from the corresponding h/w component or interface.

name

The name of the component. If you provide item with the key component, the name will be taken from the corresponding object. However if you provide both, the value of the item with the key name overrides.

index

The index of the component or ifIndex of an interface. For example variable that monitors CPU load of the device has index equal to the index of the CPU we discover on the device (some devices may have multiple processors or cores). Variables that monitor values related to network interfaces have index equal to the ifIndex of the interface (defined in RFC1213 MIB).

Normally you don’t have to specify index explicitly but instead, you just provide reference to the component using key component. However you need to set index explicitly for variables that do not correspond to any h/w component or interface we discover, for example “snmp timeouts” for the device or “the size of the routing table”. The requirement for the index is that it must be unique for the given variable and device. Different variables can have coinciding indexes, for example variables ‘ifHCInOctets’ and ‘ifHCOutOctets’ refer to the same interface by its ifIndex and therefore have the same value of the index attribute. However different instances of the same variable ifHCInOctets must have different index values. If you create monitoring variables for something that does not obtain its index from the discovery process, you’ll have to generate your own. Here is how this looks like (this fragment is taken from the script python/variable_builders/device.py, function DeviceVariableBuilder.make_variables() with minor modifications):

class DeviceVariableBuilder(BaseVariableBuilder):

   def make_variables(self, device):
        """
        Given device object, build set of monitoring variables
        for it

        :type device: PyDevice
        :param device:   network device object
        :return: a dictionary where the key is variable name and value is another dictionary
        """
        assert isinstance(device, PyDevice)

        return {
            'snmpTimeoutsPercentage': {
                'snmp_oid': Constants.snmpTimeoutsOid,
                'index': 1,
                'name': 'SNMP Agent',
                'data_format': MonitoringDataType.Gauge,
            },

            'snmpInTotalReqVars': {
                'snmp_oid': 'SNMPv2-MIB:snmpInTotalReqVars.0',
                'index': 2,
                'name': 'SNMP Agent',
                'data_format': MonitoringDataType.Counter,
            },

            'sysUpTime': {
                'snmp_oid': 'SNMPv2-MIB:sysUpTime.0',
                'index': 2,
                'name': 'SNMP Agent',
                'data_format': MonitoringDataType.TimeTick,
            },

        }

This function creates three monitoring variables: snmpTimeoutsPercentage, snmpInTotalReqVars and sysUpTime that do not correspond to any particular h/w component or network interface we can discover, so it needs to assign index explicitly. The actual value of the index does not matter as long as it satisfies the requirement listed above.

snmp_oid

This item defines SNMP OID that will be used to poll the device. You can either use explicit dot-separated numeric value or use “MIB-NAME:OID-NAME.subindex” format illustrated in the example above. Note that since the function has access to the device and h/w component or interface object, you can use index or other parameters discovered by NetSpyGlass. For example, the following function uses ifIndex of the interface (see script python/variable_builders/interface.py, function InterfaceVariableBuilder.make_basic_vars()):

class InterfaceVariableBuilder(BaseVariableBuilder):
    def make_basic_vars(self, intf):
        """
        Generate configuration for the basic set of monitoring variables
        for the interface: interface utilization, errors, discards

        :type intf: PyNetworkInterface
        :param intf: PyNetworkInterface wrapper object
        :return: a dictionary where the key is variable name and value is another dictionary
        """
        if_index = intf.if_index
        in_octets_oid = 'IF-MIB:ifInOctets.{0}'.format(if_index)
        out_octets_oid = 'IF-MIB:ifOutOctets.{0}'.format(if_index)

        if intf.if_high_speed > 0:
            in_octets_oid = 'IF-MIB:ifHCInOctets.{0}'.format(if_index)
            out_octets_oid = 'IF-MIB:ifHCOutOctets.{0}'.format(if_index)

        return {
            # ---------------------------------------------------------------
            'ifHCInOctets': {
                'component': intf,
                'snmp_oid': in_octets_oid
            },

            'ifHCOutOctets': {
                'component': intf,
                'snmp_oid': out_octets_oid
            },

This function takes ifIndex of the interface from the attribute if_index of PyNetworkInterface object passed as an argument and checks if interface supports 64 bit counters by looking at the attribute if_high_speed. If the value of if_high_speed is greater than zero, it assumes 64-bit part of the IF-MIB is supported. Here you can also see how snmp_oid can be constructed using the MIB and OID names and the value of if_index.

tags

This item allows you to inject tags into generated monitoring variable at this stage. Note that the system will automatically add tags assigned to the device and component to the variable, however this item allows you to add tags that do not already belong to either device or component. Here is how this item can be used to add forwarding class name as a tag in facet CoS to the CoS metrics variable:

def make_cos_vars(self, device, intf):
    """
    Generate configuration for the set of COS monitoring variables
    for the interface: tail and red drops.

    :type device: PyDevice
    :param device:   network device object
    :type intf: PyNetworkInterface
    :param intf: PyNetworkInterface wrapper object
    :return: a dictionary where the key is variable name and value is another dictionary
    """
    if_index = intf.if_index
    cos_vars = {}
    if 'Vendor.Juniper' in device.tags:
        configured_queues = intf.cos_queues

        for queue in configured_queues:
            fc_number = device.getFcNumber(queue)
            fc_name_tag = 'CoS.{0}'.format(device.getFcName(fc_number))
            cos_vars['jnxCosTailDropPktsQueue{0}'.format(queue)] = {
                'component': intf,
                'snmp_oid': 'JUNIPER-COS-MIB:jnxCosQstatTailDropPkts.{0}.{1}'.format(if_index, queue),
                'tags': fc_name_tag
            }

    return cos_vars

a call to function getFcName() of the PyDevice gets forwarding class name for given queue number.

Note that the value of this item can be either a list of strings or just a single string.

data_format

This item is used to define data format if it can not be deduced from the SNMP OID definition in the MIB. NetSpyGlass needs to know data format to properly compute rates and convert some of the values, such as OIDs that return time in “time ticks” (1/100 of a second). Data format is set to the value of Java enum MonitoringDataType as follows:

from net.happygears.nw2.py import MonitoringDataType

class DeviceVariableBuilder(BaseVariableBuilder):

    def make_variables(self, device):
        return {
            'sysUpTime': {
                'snmp_oid': 'SNMPv2-MIB:sysUpTime.0',
                'index': 2,
                'name': 'SNMP Agent',
                'data_format': MonitoringDataType.TimeTick,
            },

6.3. How to override the defaults

6.3.1. Example 1: making NetSpyGlass monitor specific interfaces that are not monitored by default

Suppose you want to change just one or two attributes of particular monitoring variable, while leaving the rest the defaults. For example, suppose we just want to make NetSpyGlass monitor Juniper “ms” interfaces in addition to the standard set of variables. The problem with “ms” interfaces is that our network discovery does not think they are connected anywhere but the default monitoring variable builder only monitors interfaces that are connected. So we need to override the logic that selects interfaces for monitoring but don’t need to change anything about the variables it produces.

First, create a “runner” script where you define a class based on our default class VariableBuilder and save this script under the name var_builder.py in NetSpyGlass home directory:

# File var_builder.py

from net.happygears.nw2.py.py_wrappers import PyDevice
from net.happygears.nw2.py.py_wrappers import PyNetworkInterface
from variable_builders import *
from variable_builders.variable_builder_runner import VariableBuilder


class ModifiedInterfaceVarBuilder(InterfaceVariableBuilder):
    """
    This class overrides checks implemented in InterfaceVariableBuilder to make
    NetSpyGlass try to monitor interfaces "ms" in addition to the ones picked
    by the base class InterfaceVariableBuilder.

    You can find copy of the source code of InterfaceVariableBuilder in
    python/variable_builders/interface.py
    """

    def basic_interface_match(self, intf):
        """
        This function overrides the "core" check in the base class. It is used
        to decide if we want to monitor this interface

        :type intf: PyNetworkInterface
        :param intf: PyNetworkInterface wrapper object
        :return: True if we want to monitor this interface
        """
        return 'ms-' in intf.name or super(ModifiedInterfaceVarBuilder, self).basic_interface_match(intf)

class ModifiedVariableBuilder(VariableBuilder):
    """
    This class is based on the standard VariableBuilder class but substitutes
    class used to build interface-related variables.

    :param log: Java logger object. You can call it using self.log.info("log message")
    """

    def __init__(self, log):
        super(ModifiedVariableBuilder, self).__init__(log)
        # Override these builder objects with our new classes
        self.interface = ModifiedInterfaceVarBuilder(log)

Note

Python hook scripts, such as var_builder.py, should be readable by the user account NetSpyGlass server is running under. When you install NetSpyGlass using distributed rpm or deb package, this is user nw2.

This script defines modified interface variable builder class ModifiedInterfaceVarBuilder that mostly defers to the base class except it overrides function basic_interface_match() that also checks if interface name matches simple pattern “ms-”.

This is it, now add the following parameter to the configuration file nw2.conf to activate new script:

# File nw2.conf

network {
    monitor.variableBuilder = "var_builder.ModifiedVariableBuilder"

Note

you don’t have to restart NetSpyGlass when you modify the script, however you need to restart it when you switch from the default variable builder script to the one you provide.

6.3.2. Example 2: making NetSpyGlass poll packet rate counter OIDs for network interfaces

By default, NetSpyGlass polls the following OIDs for each network interface:

  • ifAlias this is a string variable, its value is equal to the interface description
  • ifspeed interface speed
  • ifHCInOctets The total number of octets received on the interface, including framing characters. NetSpyGlass uses this information to compute inbound traffic rate through the interface (variable ifInRate)
  • ifHCOutOctets The total number of octets transmitted out of the interface, including framing characters. This information is used to compute outbound traffic rate through the interface (variable ifOutRate)
  • ifInErrors The number of inbound packets that contained errors preventing them from being deliverable to a higher-layer protocol. Variable ifInErrorRate is computed as rate(ifInErrors)
  • ifOutErrors The number of outbound packets that could not be transmitted because of errors. Variable ifOutErrorRate is computed as rate(ifOutErrors)
  • ifInDiscards The number of inbound packets which were chosen to be discarded even though no errors had been detected to prevent their being deliverable to a higher-layer protocol. Variable ifInDiscardRate is computed as rate(ifInDiscards)
  • ifOutDiscards The number of outbound packets which were chosen to be discarded even though no errors had been detected to prevent their being transmitted. Variable ifOutDiscardRate is computed as rate(ifOutDiscards)
  • ifOperStatus The current operational state of the interface.

Some users want to track various packet rates in addition to these. Standard IF-MIB supported by most devices offers a number of OIDs that monitor the following packet rates:

  • ifHCInUcastPkts The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were not addressed to a multicast or broadcast address at this sub-layer.
  • ifHCInMulticastPkts The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were addressed to a multicast address at this sub-layer. For a MAC layer protocol, this includes both Group and Functional addresses.
  • ifHCInBroadcastPkts The number of packets, delivered by this sub-layer to a higher (sub-)layer, which were addressed to a broadcast address at this sub-layer.

(there are also corresponding outbound packet counters).

NetSpyGlass does not poll packet counter OIDs by default, but it is easy to turn this on by just setting one boolean variable in the Interface variable builder class. As in the previous example, save the following script in the file var_builder.py in NetSpyGlass home directory:

# File var_builder.py

from variable_builders import *
from variable_builders.variable_builder_runner import VariableBuilder


class ModifiedVariableBuilder(VariableBuilder):
    """
    This class is based on the standard VariableBuilder class. It just sets
    the flag `make_interface_packet_counter_vars` in the interface variable
    builder class instance to `True`.

    :param log: Java logger object. You can call it using self.log.info("log message")
    """

    def __init__(self, log):
        super(ModifiedVariableBuilder, self).__init__(log)
        self.interface.make_interface_packet_counter_vars = True

Then add parameter network.monitor.variableBuilder to your nw2.conf configuration file:

# File nw2.conf

network {
    monitor.variableBuilder = "var_builder.ModifiedVariableBuilder"

6.4. Report

NetSpyGlass “watches” the file defined by the parameter network.monitor.variableBuilder and reloads variables whenever the file is updated. At the end of the reconfiguration, the Monitor writes report to the file

reports/$network_name/monitor/0/$device_name

(where $network_name is the name of the network defined in the configuration and $device_name is the name of each device). Report directories are rotated before the new report is written; the system keeps 10 generations of reports.

The report lists monitoring variables and corresponding OIDs that will be polled on the device, as well as some summary information. It looks like this:

Monitoring variables collected from device router1.rd

Report generated 2015-08-29T13:10:39.887-07:00

Total number of OIDs for this device: 2385
Number of queries for this device: (max 30 OIDs per query, max PDU payload size 480 bytes): 86

-------------------------------------------------------------------

bgpPeerAdminStatus (category 'Protocol'): total 8 instances
-----------------------------------------------------------------
bgpPeerAdminStatus.76.174285569          | AS36323 10.99.99.1   |  INTEGER | 1.3.6.1.2.1.15.3.1.3.10.99.99.1
bgpPeerAdminStatus.76.174285570          | AS36323 10.99.99.2   |  INTEGER | 1.3.6.1.2.1.15.3.1.3.10.99.99.2
bgpPeerAdminStatus.76.174285571          | AS36323 10.99.99.3   |  INTEGER | 1.3.6.1.2.1.15.3.1.3.10.99.99.3
bgpPeerAdminStatus.76.174285572          | AS36323 10.99.99.4   |  INTEGER | 1.3.6.1.2.1.15.3.1.3.10.99.99.4

At the bottom of the report you can find actual batch queries that will be sent to the device. Sometimes the order and number of OIDs in a batch query is important and this part of the report can be used to troubleshoot certain class of problems with SNMP polling of the device. Lists of OIDs in the example below have been truncated to make them fit on the page:

Batch queries:
Batch    0: [1.3.6.1.2.1.1.3.0, 1.3.6.1.2.1.2.2.1.5.33, 1.3.6.1.2.1.2.2.1.5.34, 1.3.6.1.2.1.2.2.1.5.35, ( and more ... )
Batch    1: [1.3.6.1.2.1.2.2.1.5.241, 1.3.6.1.2.1.2.2.1.5.244, 1.3.6.1.2.1.2.2.1.5.245, 1.3.6.1.2.1.2.2.1.5.246,

6.5. Data Display

The second part of the configuration related to the monitoring data is the set of rules that define display of the data in the UI. These rules are defined in the config, you can inspect default configuration in the copy of the built-in default configuration provided in the file doc/default_config/data_display.conf. Here is how it looks like:

variables {

    ifInRate: {
        category: Interface,
        group: Utilization,
        column: In,
        description: "Inbound traffic through interface",
        unit: "bit/sec",
        significantFigures: 3,
        range: [0, auto],
        scale: auto,
        prefix: auto
    },

    ifOutRate: {
        category: Interface,
        group: Utilization,
        column: Out,
        description: "Outbound traffic through interface",
        unit: "bit/sec",
        significantFigures: 3,
        range: [0, auto],
        scale: auto,
        prefix: auto
    },

First, all variable definitions are located inside of the configuration section variables. Data display parameters for each variable are grouped in a dictionary that can have the following set of keys:

category, group and column

Monitoring variables are organized in a three-level hierarchy, built using parameters category, group and column. Device Details panel uses these three levels as follows:

  • categories are used for tabs “Interface”, “CPU”, “Temperature” etc
  • groups are used for the top level column headers
  • columns are used for the second level column headers.

For example, interface utilization variables ifInRate and ifOutRate have category “Interface”, group “Utilization” and column “In” and “Out”. This means they appear in the tab “Interface” in columns with headers “In” and “Out” and the top level header that spans both columns and says “Utilization”.

Graphing workbench uses only “Category” attribute to group variables by category.

description

This parameter allows you to provide description of the variable. Description appears in the Graphing Workbench when you select a variable.

unit

Measurement unit for the variable.

Note the difference between unit “byte” and “B”. If the unit is “B” and scale is set to “auto”, NetSpyGlass computes scaling factor assuming the value of the variable assuming one “kilobyte” is equal to 1024 bytes. This only works if the unit is exactly equal to “B” and is typically only used for variables that monitor amount of system memory or swap. In all other cases automatic scaling algorithm assumes “kilo-” means “1000”.

significantFigures

Values can be rounded to the fixed number of significant figures specified by this parameter. Note that this is different from rounding to the fixed number of decimal places.

accuracy

Values can be rounder to fixed number of digits to the right of the decimal point. If accuracy > 0, it is used. Otherwise significantFigures is used.

range

the range of values for this variable. Range is used to configure Y axis in graphs. This parameter is defined as a list of two items, each can be either a number or word ‘auto’. If either side of the range is ‘auto’, NetSpyGlass will compute minimum or maximum (or both) of values of the variable within graph’s time interval and use this for the Y axis.

Interface-related variables can also use word ‘speed’ for the maximum side of the range, in which case Y axis will be scaled to interface speed.

Example of setting Y axis range to ‘auto’ for the inbound interface utilization:

ifInRate: {
    category: Interface,
    group: Utilization,
    column: In,
    unit: "bit/sec",
    range: [0, auto],
},

Setting Y axis range to interface speed for the inbound interface utilization:

ifInRate: {
    category: Interface,
    group: Utilization,
    column: In,
    unit: "bit/sec",
    range: [0, speed],
},

Here is how we can make the range fixed for the variable where it makes sense:

cpuUtil: {
    category: CPU,
    column: "CPU utilization",
    group: CPU,
    description: "CPU utilization",
    unit: %,
    range: [0, 100.0],
},

scale

A number or word ‘auto’. This parameter tells NetSpyGlass if it should try to scale the value of the variable before the display to make it more human-friendly. If the parameter is set to ‘auto’, the program will try to pick most appropriate scaling factor to make scaled value compact. For example, 1000000 bits/sec will be converted to 1 Mbit/sec by choosing scaling factor 10E-6.

If scale is set to 1.0 or any other number, automatic scaling is not done but values are just multiplied by this number before the display.

prefix

This parameter can be either a string or word ‘auto’. It works in combination with scale when both scale and prefix are set to ‘auto’. When NetSpyGlass chooses scaling factor, it also assigns corresponding prefix to the parameter ‘prefix’. In the example above value 1000000 bit/sec can be converted to 1 Mbit/sec by choosing scaling factor 10E-6. When this happens, prefix is assigned value of ‘M’. Prefix is used in combination with unit, making the result ‘Mbit/sec’ when unit is ‘bit/sec’.

zeroThreshold

If > 0.0, then it is interpreted as fraction of the maximum range of values of the variable and all values below this threshold are rounded down to zero. For interface traffic-related variable the maximum value of the range is interface speed, therefore zeroThreshold defines fraction of the speed. Absolute value of the threshold is then equal to speed * zeroThreshold. If zeroThreshold is equal to “1E-5” and interface is a Gigabit Ethernet (speed = 1E9 bits/sec), then the value of the threshold is equal to 1E9 * 1E-5 = 1E4 or 10 kbit/sec. Any values lower than this will be rounded down to zero. User with caution because this distorts actual measured values when they are displayed and makes it impossible to compare very small levels of traffic across interfaces. Default value of zeroThreshold is “0.0”, therefore it is not used.

The main use case for the parameter zeroThreshold is to display very low levels of traffic going through high-bandwidth network interface as zero. Use with caution because with this parameter activated, two variables may appear to have the same value of zero, while in reality they may have different very small values. By default this parameter is turned off. This parameter does not affect values shown in graphs.

Here is an example:

# Change some defaults
variables {

    ifInRate.range = [0, auto]
    ifInRate.accuracy = 2
    ifInRate.zeroThreshold = 1E-4

    ifOutRate.range = [0, auto]
    ifOutRate.accuracy = 2
    ifOutRate.zeroThreshold = 1E-4
}

6.5.1. How to change or add data display rules

To change default data display rules or add your own just add corresponding section to your nw2.conf file and override corresponding parameters. Here is an example:

# Change some defaults

variables {

    ifInRate.range = [0, auto]
    ifInRate.accuracy = 2

    ifOutRate.range = [0, auto]
    ifOutRate.accuracy = 2

    bgpPeerInUpdatesRate.unit = "prefixes/sec"
    bgpPeerInUpdatesRate.accuracy = 2
    bgpPeerInUpdatesRate.scale = 1.0
    bgpPeerInUpdatesRate.prefix = ""
}

This can be added anywhere in the nw2.conf as long as it is at the top level of the hierarchy (that is, it won’t work if you put this inside of the “network” section). If you just want to override one or two parameters, you can use this syntax:

variables.ifInRate.range = [0, speed]
variables.ifOutRate.range = [0, speed]

6.6. String Monitoring Variables

NetSpyGlass supports monitoring variables that have string values. One example of a variable like that is ifAlias which tracks interface descriptions. The value of the variable like that can be accessed in Python scripts by calling function net.happygears.nw2.time_series_buffer.TimeSeriesBuffer.getLastValueAsString().

Note

String monitoring variables can be stored in TSDB running on top of hbase or InfluxDb but not if it uses RRDB or Graphite