ASCII Graph
gnmic
supports displaying collected metrics as an ASCII graph on the terminal. The graph is generated using the asciigraph package.
Configuration sample#
outputs:
output1:
# required
type: asciigraph
# string, the graph caption
caption:
# integer, the graph height. If unset, defaults to the terminal height
height:
# integer, the graph width. If unset, defaults to the terminal width
width:
# float, the graph minimum value for the vertical axis.
lower-bound:
# float, the graph minimum value for the vertical axis.
upper-bound:
# integer, the graph left offset.
offset:
# integer, the decimal point precision of the label values.
precision:
# string, the caption color. one of ANSI colors.
caption-color:
# string, the axis color. one of ANSI colors.
axis-color:
# string, the label color. one of ANSI colors.
label-color:
# duration, the graph refresh timer.
refresh-timer: 1s
# string, one of `overwrite`, `if-not-present`, ``
# This field allows populating/changing the value of Prefix.Target in the received message.
# if set to ``, nothing changes
# if set to `overwrite`, the target value is overwritten using the template configured under `target-template`
# if set to `if-not-present`, the target value is populated only if it is empty, still using the `target-template`
add-target:
# string, a GoTemplate that allows for the customization of the target field in Prefix.Target.
# it applies only if the previous field `add-target` is not empty.
# if left empty, it defaults to:
# {{- if index . "subscription-target" -}}
# {{ index . "subscription-target" }}
# {{- else -}}
# {{ index . "source" | host }}
# {{- end -}}`
# which will set the target to the value configured under `subscription.$subscription-name.target` if any,
# otherwise it will set it to the target name stripped of the port number (if present)
target-template:
# list of processors to apply on the message before writing
event-processors:
# bool enable debug
debug: false
Example#
This example shows how to use the asciigraph
output.
gNMIc config
cat gnmic_asciiout.yaml
targets:
clab-nfd33-spine1-1:
username: admin
password: NokiaSrl1!
skip-verify: true
subscriptions:
sub1:
paths:
- /interface[name=ethernet-1/3]/statistics/out-octets
- /interface[name=ethernet-1/3]/statistics/in-octets
stream-mode: sample
sample-interval: 1s
encoding: ascii
outputs:
out1:
type: asciigraph
caption: in/out octets per second
event-processors:
- rate
processors:
rate:
event-starlark:
script: rate.star
Starlark processor
cat rate.star
cache = {}
values_names = [
'/interface/statistics/out-octets',
'/interface/statistics/in-octets'
]
N=2
def apply(*events):
for e in events:
for value_name in values_names:
v = e.values.get(value_name)
# check if v is not None and is a digit to proceed
if not v:
continue
if not v.isdigit():
continue
# update cache with the latest value
val_key = "_".join([e.tags["source"], e.tags["interface_name"], value_name])
if not cache.get(val_key):
# initialize the cache entry if empty
cache.update({val_key: []})
if len(cache[val_key]) > N:
# remove the oldest entry if the number of entries reached N
cache[val_key] = cache[val_key][1:]
# update cache entry
cache[val_key].append((int(v), e.timestamp))
# get the list of values
val_list = cache[val_key]
# calculate rate
e.values[value_name+"_rate"] = rate(val_list)
e.values.pop(value_name)
return events
def rate(vals):
previous_value, previous_timestamp = None, None
for value, timestamp in vals:
if previous_value != None and previous_timestamp != None:
time_diff = (timestamp - previous_timestamp) / 1000000000 # 1 000 000 000
if time_diff > 0:
value_diff = value - previous_value
rate = value_diff / time_diff
return rate
previous_value = value
previous_timestamp = timestamp
return 0