Skip to content

Commit b7fdc1f

Browse files
committed
Add a simplified way to have counter-part messages
From the YAML profiles, which can be easily extended and loaded into the user environment, we should be able to signalise groups or pairs of notifications, referring to the same entity (i.e., interface, neighbour, alarm, etc.). This would have a direct applicability into the Prometheus metrics, as it'd add a new `_state` metric by default, but also would be useful in the other publishers which will be adding the new ``state`` field when provided. The new ``state`` field is a numeric value, with a specific meaning, mapping out to a value that provides a meaningful information for the end user (e.g., interface up = 1, interface down = 0; alarm set = 1, alarm cleared = 0, and so on.) - but not limited to binary values only, there can be as many states as desired.
1 parent 573beee commit b7fdc1f

File tree

9 files changed

+139
-0
lines changed

9 files changed

+139
-0
lines changed

docs/developers/device_profiles.rst

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,41 @@ should be placed. There are two options, ``variables`` and ``static``.
213213
``variables`` should be used when the value being set is taken from the message,
214214
and ``static`` should be used when the value is manually set.
215215

216+
``state``
217+
---------
218+
219+
``state`` is an optional config bit which may be useful when defining messages
220+
that have a counter-part. For example: ``MAJOR_ALARM_SET``
221+
/ ``MAJOR_ALARM_CLEARED``. The idea behind this is to have pairs or groups of
222+
notifications that have a specific significance mapping out to a desired value
223+
(e.g., the state value for ``MAJOR_ALARM_SET`` can be 1, while the state value
224+
for ``MAJOR_ALARM_CLEARED`` can be 0). The value can be any number, not only
225+
binary, when the group is larger than two notifications.
226+
227+
It is equally important to not that when using the :ref:`publisher-prometheus`
228+
Publisher, when using this field, an additional metric is being exposed,
229+
providing the state value, besides the usual counter.
230+
231+
The metric name is derived from the base name of the notification, by stripping
232+
the last part (after underscore) and replacing it with ``_state``. For
233+
instance, continuing the example above, ``MAJOR_ALARM_SET`` and
234+
``MAJOR_ALARM_CLEARED`` would both set the same Gauge metric
235+
``napalm_logs_major_alarm_state``. If the notification groups don't have
236+
a common base name for whatever reason, you can define individual state tags
237+
using the ``state_tag`` option (see below).
238+
239+
``state_tag``
240+
-------------
241+
242+
This option provides a custom name for the state metric on groups of
243+
notifications. By default, this is not necessary, as it's assumed a group has
244+
the same base name, but it may not always be the case.
245+
246+
Based on the example above, ``MAJOR_ALARM_SET`` and ``MAJOR_ALARM_CLEARED``
247+
would, by default, set the ``napalm_logs_major_alarm_state`` Gauge metric,
248+
however, by providing the value ``state_tag: system_alarm_state`` (for both), the
249+
metric becomes: ``napalm_logs_system_alarm_state``.
250+
216251
Pure Python profiles
217252
++++++++++++++++++++
218253

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
messages:
2+
3+
- error: MAINTENANCE_MODE_STARTED
4+
tag: MMODE-5-MAINT_UNIT_STATE_CHANGE
5+
state: 1
6+
values: {}
7+
line: ': Maintenance unit state changed for unit MAINT-UNIT. Old State maintenanceModeEnter, New State underMaintenance'
8+
model: ietf-notification-messages
9+
mapping:
10+
variables: {}
11+
static:
12+
notification-messages//notification-message//message-text: "maintenance started"
13+
14+
- error: MAINTENANCE_MODE_ENDED
15+
tag: MMODE-5-MAINT_UNIT_STATE_CHANGE
16+
state: 0
17+
values: {}
18+
line: ': Maintenance unit state changed for unit MAINT-UNIT. Old State maintenanceModeExit, New State active'
19+
model: ietf-notification-messages
20+
mapping:
21+
variables: {}
22+
static:
23+
notification-messages//notification-message//message-text: "maintenance ended"

napalm_logs/device.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ def _compile_messages(self):
136136
'replace': replace,
137137
'model': model,
138138
'mapping': mapping,
139+
'state': message_dict.get('state'),
140+
'state_tag': message_dict.get('state_tag'),
139141
}
140142
)
141143
log.debug('Compiled messages:')
@@ -175,6 +177,8 @@ def _parse(self, msg_dict):
175177
'mapping': message['mapping'],
176178
'replace': message['replace'],
177179
'error': message['error'],
180+
'_state': message['state'],
181+
'_state_tag': message['state_tag'],
178182
}
179183
for key in values.keys():
180184
# Check if the value needs to be replaced
@@ -355,6 +359,10 @@ def start(self):
355359
'facility': facility,
356360
'severity': severity,
357361
}
362+
if kwargs.get('_state') is not None:
363+
to_publish['state'] = kwargs['_state']
364+
if kwargs.get('_state_tag'):
365+
to_publish['state_tag'] = kwargs['_state_tag']
358366
log.debug('Queueing to be published:')
359367
log.debug(to_publish)
360368
# self.pub_pipe.send(to_publish)

napalm_logs/server.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ def _compile_prefixes(self):
144144
'prefix_positions': sorted_position,
145145
'raw_prefix': escaped.format(**values),
146146
'values': values,
147+
'state': prefix.get('state'),
148+
'state_tag': prefix.get('state_tag'),
147149
}
148150
)
149151
# log.debug('Compiled prefixes')

napalm_logs/transport/prometheus.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ def __parse_without_details(self, msg):
4040
)
4141
self.metrics[error].labels(host=msg['host']).inc()
4242

43+
if msg.get('state') is not None:
44+
base = error.split('_')[:-1]
45+
metric = msg.get('state_tag', '_'.join(base + ['state']).lower())
46+
if metric not in self.metrics:
47+
self.metrics[metric] = Gauge(
48+
'napalm_logs_{}'.format(metric),
49+
'State for {} type notifications'.format('_'.join(base)),
50+
['host'],
51+
)
52+
self.metrics[metric].labels(host=msg['host']).set(msg['state'])
53+
4354
def __parse_user_action(self, msg):
4455
'''
4556
Helper to generate Counter metrics that provide the host label, together
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<100>Feb 28 17:54:21 some-switch MaintenanceMode: %MMODE-5-MAINT_UNIT_STATE_CHANGE: Maintenance unit state changed for unit MAINT-UNIT. Old State maintenanceModeExit, New State active
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"error": "MAINTENANCE_MODE_ENDED",
3+
"host": "some-switch",
4+
"ip": "127.0.0.1",
5+
"timestamp": 1646070861,
6+
"yang_message": {
7+
"notification-messages": {
8+
"notification-message": {
9+
"message-text": "maintenance ended"
10+
}
11+
}
12+
},
13+
"message_details": {
14+
"date": "Feb 28",
15+
"time": "17:54:21",
16+
"host": "some-switch",
17+
"processName": "MaintenanceMode",
18+
"tag": "MMODE-5-MAINT_UNIT_STATE_CHANGE",
19+
"pri": "100",
20+
"message": ": Maintenance unit state changed for unit MAINT-UNIT. Old State maintenanceModeExit, New State active",
21+
"facility": 12,
22+
"severity": 4
23+
},
24+
"yang_model": "ietf-notification-messages",
25+
"os": "eos",
26+
"facility": 12,
27+
"severity": 4,
28+
"state": 0
29+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<100>Feb 28 17:54:21 some-switch MaintenanceMode: %MMODE-5-MAINT_UNIT_STATE_CHANGE: Maintenance unit state changed for unit MAINT-UNIT. Old State maintenanceModeEnter, New State underMaintenance
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"error": "MAINTENANCE_MODE_STARTED",
3+
"host": "some-switch",
4+
"ip": "127.0.0.1",
5+
"timestamp": 1646070861,
6+
"yang_message": {
7+
"notification-messages": {
8+
"notification-message": {
9+
"message-text": "maintenance started"
10+
}
11+
}
12+
},
13+
"message_details": {
14+
"date": "Feb 28",
15+
"time": "17:54:21",
16+
"host": "some-switch",
17+
"processName": "MaintenanceMode",
18+
"tag": "MMODE-5-MAINT_UNIT_STATE_CHANGE",
19+
"pri": "100",
20+
"message": ": Maintenance unit state changed for unit MAINT-UNIT. Old State maintenanceModeEnter, New State underMaintenance",
21+
"facility": 12,
22+
"severity": 4
23+
},
24+
"yang_model": "ietf-notification-messages",
25+
"os": "eos",
26+
"facility": 12,
27+
"severity": 4,
28+
"state": 1
29+
}

0 commit comments

Comments
 (0)