Response

ResponseLevel

class naghelp.ResponseLevel(name, exit_code)

Object to use when exiting a naghelp plugin

Instead of using numeric code that may be hard to memorize, predefined objects has be created :

Response level object exit code
OK 0
WARNING 1
CRITICAL 2
UNKNOWN 3

To exit a plugin with the correct exit code number, one have just to call the exit() method of the wanted ResonseLevel object

exit()

This is the official way to exit a naghelp plugin

Example

>>> level = CRITICAL
>>> level.exit()  
    SystemExit: 2
info()

Get name and exit code for a Response Level

Examples

>>> level = CRITICAL
>>> level.info()
'CRITICAL (exit_code=2)'
>>> level.name
'CRITICAL'
>>> level.exit_code
2

PluginResponse

class naghelp.PluginResponse(default_level=OK)

Response to return to Nagios for a naghelp plugin

Parameters:default_level (ResponseLevel) – The level to return when no level messages has been added to the response (for exemple when no error has be found). usually it is set to OK or UNKNOWN

A naghelp response has got many sections :

  • A synopsis (The first line that is directl visible onto Nagios interface)
  • A body (informations after the first line, only visible in detailed views)
  • Some performance Data

The body itself has got some sub-sections :

  • Begin messages (Usually for a title, an introduction …)

  • Levels messages, that are automatically splitted into Nagios levels in this order:

    • Critical messages
    • Warning messages
    • Unkown messages
    • OK messages
  • More messages (Usually to give more information about the monitored host)

  • End messages (Custom conclusion messages. naghelp Plugin use this section

    to add automatically some informations about the plugin.

Each section can be updated by adding a message through dedicated methods.

PluginResponse object takes care to calculate the right ResponseLevel to return to Nagios : it will depend on the Levels messages you will add to the plugin response. For example, if you add one OK message and one WARNING message, the response level will be WARNING. if you add again one CRITICAL message then an OK message , the response level will be CRITICAL.

About the synopsis section : if not manualy set, the PluginResponse class will build one for you : It will be the unique level message if you add only one in the response or a summary giving the number of messages in each level.

Examples

>>> r = PluginResponse(OK)
>>> print r
OK
add(level, msg, *args, **kwargs)

Add a message in levels messages section and sets the response level at the same time

Use this method each time your plugin detects a WARNING or a CRITICAL error. You can also use this method to add a message saying there is an UNKNOWN or OK state somewhere. You can use this method several times and at any time until the send() is used. This method updates the calculated ResponseLevel. When the response is rendered, the added messages are splitted into sub-section

Parameters:
  • level (ResponseLevel) – the message level (Will affect the final response level)
  • msg (str) – the message to add in levels messages section.
  • args (list) – if additional arguments are given, msg will be formatted with % (old-style python string formatting)
  • kwargs (dict) – if named arguments are given, msg will be formatted with str.format()

Examples

>>> r = PluginResponse(OK)
>>> print r.get_current_level()
OK
>>> r.add(CRITICAL,'The system crashed')
>>> r.add(WARNING,'Found some almost full file system')
>>> r.add(UNKNOWN,'Cannot find FAN %s status',0)
>>> r.add(OK,'Power {power_id} is ON',power_id=1)
>>> print r.get_current_level()
CRITICAL
>>> print r     
STATUS : CRITICAL:1, WARNING:1, UNKNOWN:1, OK:1
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
The system crashed

----( WARNING )-----------------------------------------------------------------
Found some almost full file system

----( UNKNOWN )-----------------------------------------------------------------
Cannot find FAN 0 status

----( OK )----------------------------------------------------------------------
Power 1 is ON

add_begin(msg, *args, **kwargs)

Add a message in begin section

You can use this method several times and at any time until the send() is used. The messages will be displayed in begin section in the same order as they have been added. This method does not change the calculated ResponseLevel.

Parameters:
  • msg (str) – the message to add in begin section.
  • args (list) – if additionnal arguments are given, msg will be formatted with % (old-style python string formatting)
  • kwargs (dict) – if named arguments are given, msg will be formatted with str.format()

Examples

>>> r = PluginResponse(OK)
>>> r.add_begin('='*40)
>>> r.add_begin('{hostname:^40}', hostname='MyHost')
>>> r.add_begin('='*40)
>>> r.add_begin('Date : %s, Time : %s','2105-12-18','14:55:11')
>>> r.add_begin('\n')
>>> r.add(CRITICAL,'This is critical !')
>>> print r     
This is critical !
========================================
                 MyHost
========================================
Date : 2105-12-18, Time : 14:55:11

==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
This is critical !

add_comment(level, msg, *args, **kwargs)

Add a comment in levels messages section and sets the response level at the same time

it works like add() except that the message is not counted into the synopsis

Parameters:
  • level (ResponseLevel) – the message level (Will affect the final response level)
  • msg (str) – the message to add in levels messages section.
  • args (list) – if additionnal arguments are given, msg will be formatted with % (old-style python string formatting)
  • kwargs (dict) – if named arguments are given, msg will be formatted with str.format()

Examples

>>> r = PluginResponse(OK)
>>> print r.get_current_level()
OK
>>> r.add_comment(CRITICAL,'Here are some errors')
>>> r.add(CRITICAL,'error 1')
>>> r.add(CRITICAL,'error 2')
>>> print r     
STATUS : CRITICAL:2
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
Here are some errors
error 1
error 2

add_elif(*add_ifs, **kwargs)

Multi-conditionnal message add

This works like add_if() except that it accepts multiple tests. Like python elif, the method stops on first True test and send corresponding message. If you want to build the equivalent of a default message, just use True as the last test.

Parameters:
  • add_ifs (list) – list of tuple (test,level,message).
  • kwargs (dict) – if named arguments are given, messages will be formatted with str.format()

Examples

>>> r = PluginResponse(OK)
>>> print r.get_current_level()
OK
>>> logs = '''
... Power 0 is critical
... Power 1 is OK
... Power 2 is degraded
... Power 3 is failed
... Power 4 is OK
... Power 5 is degraded
... Power 6 is smoking
... '''
>>> from textops import *
>>> for log in logs | rmblank():
...     r.add_elif( (log|haspattern('critical|failed'), CRITICAL, log),
...                 (log|haspattern('degraded|warning'), WARNING, log),
...                 (log|haspattern('OK'), OK, log),
...                 (True, UNKNOWN, log) )
>>> print r.get_current_level()
CRITICAL
>>> print r     
STATUS : CRITICAL:2, WARNING:2, UNKNOWN:1, OK:2
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
Power 0 is critical
Power 3 is failed

----( WARNING )-----------------------------------------------------------------
Power 2 is degraded
Power 5 is degraded

----( UNKNOWN )-----------------------------------------------------------------
Power 6 is smoking

----( OK )----------------------------------------------------------------------
Power 1 is OK
Power 4 is OK

add_end(msg, *args, **kwargs)

Add a message in end section

You can use this method several times and at any time until the send() is used. The messages will be displayed in end section in the same order as they have been added. This method does not change the calculated ResponseLevel.

Parameters:
  • msg (str) – the message to add in end section.
  • args (list) – if additional arguments are given, msg will be formatted with % (old-style python string formatting)
  • kwargs (dict) – if named arguments are give, msg will be formatted with str.format()

Examples

>>> r = PluginResponse(OK)
>>> r.add_end('='*40)
>>> r.add_end('{hostname:^40}', hostname='MyHost')
>>> r.add_end('='*40)
>>> r.add_end('Date : %s, Time : %s','2105-12-18','14:55:11')
>>> r.add_end('\n')
>>> r.add(CRITICAL,'This is critical !')
>>> print r     
This is critical !

==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
This is critical !


========================================
                 MyHost
========================================
Date : 2105-12-18, Time : 14:55:11
add_if(test, level, msg=None, header=None, footer=None, *args, **kwargs)

Test than add a message in levels messages section and sets the response level at the same time

This works like add() except that it is conditionnal : test must be True. If no message is given, the value of test is used.

Parameters:
  • test (any) – the message is added to the response only if bool(test) is True.
  • level (ResponseLevel) – the message level (Will affect the final response level)
  • msg (str) – the message to add in levels messages section. If no message is given, the value of test is used.
  • header (str) – Displayed before the message as a level comment if not None (Default : None)
  • footer (str) – Displayed after the message as a level comment if not None (Default : None)
  • args (list) – if additional arguments are given, msg will be formatted with % (old-style python string formatting)
  • kwargs (dict) – if named arguments are given, msg will be formatted with str.format()

Examples

>>> r = PluginResponse(OK)
>>> print r.get_current_level()
OK
>>> logs = '''
... Power 0 is critical
... Power 1 is OK
... Power 2 is degraded
... Power 3 is failed
... Power 4 is OK
... Power 5 is degraded
... '''
>>> from textops import *
>>> nb_criticals = logs | grepc('critical|failed')
>>> print nb_criticals
2
>>> warnings = logs | grep('degraded|warning').tostr()
>>> print warnings
Power 2 is degraded
Power 5 is degraded
>>> unknowns = logs | grep('unknown').tostr()
>>> print unknowns

>>> r.add_if(nb_criticals,CRITICAL,'{n} power(s) are critical',n=nb_criticals)
>>> r.add_if(warnings,WARNING)
>>> r.add_if(unknowns,UNKNOWN)
>>> print r.get_current_level()
CRITICAL
>>> print r     
STATUS : CRITICAL:1, WARNING:1
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
2 power(s) are critical

----( WARNING )-----------------------------------------------------------------
Power 2 is degraded
Power 5 is degraded

add_list(level, msg_list, header=None, footer=None, *args, **kwargs)

Add several level messages having a same level

Sometimes, you may have to specify a list of faulty parts in the response : this can be done by this method in a single line. If a message is empty in the list, it is not added.

Parameters:
  • level (ResponseLevel) – the message level (Will affect the final response level)
  • msg_list (list) – the messages list to add in levels messages section.
  • header (str) – Displayed before the message as a level comment if not None (Default : None) one can use {_len} in the comment to get list count.
  • footer (str) – Displayed after the message as a level comment if not None (Default : None) one can use {_len} in the comment to get list count.
  • args (list) – if additional arguments are given, messages in msg_list will be formatted with % (old-style python string formatting)
  • kwargs (dict) – if named arguments are given, messages in msg_list will be formatted with str.format()

Examples

>>> r = PluginResponse(OK)
>>> print r.get_current_level()
OK
>>> logs = '''
... Power 0 is critical
... Power 1 is OK
... Power 2 is degraded
... Power 3 is failed
... Power 4 is OK
... Power 5 is degraded
... '''
>>> from textops import grep
>>> criticals = logs >> grep('critical|failed')
>>> warnings = logs >> grep('degraded|warning')
>>> print criticals
['Power 0 is critical', 'Power 3 is failed']
>>> print warnings
['Power 2 is degraded', 'Power 5 is degraded']
>>> r.add_list(CRITICAL,criticals)
>>> r.add_list(WARNING,warnings)
>>> print r.get_current_level()
CRITICAL
>>> print r     
STATUS : CRITICAL:2, WARNING:2
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
Power 0 is critical
Power 3 is failed

----( WARNING )-----------------------------------------------------------------
Power 2 is degraded
Power 5 is degraded

>>> r = PluginResponse()
>>> r.add_list(WARNING,['Power warning1','Power warning2'],'{_len} Power warnings:','Power warnings : {_len}')
>>> r.add_list(WARNING,['CPU warning1','CPU warning2'],'{_len} CPU warnings:','CPU warnings : {_len}')
>>> print r
STATUS : WARNING:4
==================================[  STATUS  ]==================================

----( WARNING )-----------------------------------------------------------------
2 Power warnings:
Power warning1
Power warning2
Power warnings : 2
2 CPU warnings:
CPU warning1
CPU warning2
CPU warnings : 2

add_many(lst, *args, **kwargs)

Add several level messages NOT having a same level

This works like add_list() except that instead of giving a list of messages one have to specify a list of tuples (level,message). By this way, one can give a level to each message into the list. If a message is empty in the list, it is not added.

Parameters:
  • lst (list) – A list of (level,message) tuples to add in levels messages section.
  • args (list) – if additional arguments are given, messages in lst will be formatted with % (old-style python string formatting)
  • kwargs (dict) – if named arguments are given, messages in lst will be formatted with str.format()

Examples

>>> r = PluginResponse(OK)
>>> print r.get_current_level()
OK
>>> logs = '''
... Power 0 is critical
... Power 1 is OK
... Power 2 is degraded
... Power 3 is failed
... Power 4 is OK
... Power 5 is degraded
... '''
>>> from textops import *
>>> errors = [ (CRITICAL if error|haspatterni('critical|failed') else WARNING,error)
...            for error in logs | grepv('OK') ]
>>> print errors  
[(WARNING, ''), (CRITICAL, 'Power 0 is critical'), (WARNING, 'Power 2 is degraded'),
(CRITICAL, 'Power 3 is failed'), (WARNING, 'Power 5 is degraded')]
>>> r.add_many(errors)
>>> print r.get_current_level()
CRITICAL
>>> print r     
STATUS : CRITICAL:2, WARNING:2
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
Power 0 is critical
Power 3 is failed

----( WARNING )-----------------------------------------------------------------
Power 2 is degraded
Power 5 is degraded

add_mlist(levels, lists, headers=[], footers=[], *args, **kwargs)

Add a list of lists of messages

This is useful with textops.sgrep utility that returns lists of lists of messages. first level will be affected to first list, second level to the second list and so on.

Parameters:
  • levels (ResponseLevel) – a list of message levels. use a None level to skip a list.
  • lists (list) – list of message lists.
  • header (str) – Displayed before the message as a level comment if not None (Default : None) one can use {_len} in the comment to get list count.
  • footer (str) – Displayed after the message as a level comment if not None (Default : None) one can use {_len} in the comment to get list count.
  • args (list) – if additional arguments are given, messages in msg_list will be formatted with % (old-style python string formatting)
  • kwargs (dict) – if named arguments are given, messages in msg_list will be formatted with str.format()

Examples

>>> from textops import StrExt
>>> r = PluginResponse(OK)
>>> logs = StrExt('''
... Power 0 is critical
... Power 1 is OK
... Power 2 is degraded
... Power 3 is failed
... Power 4 is OK
... Power 5 is degraded
... ''')
>>>
>>> print logs.sgrep(('critical|failed','degraded|warning'))  
[['Power 0 is critical', 'Power 3 is failed'],
['Power 2 is degraded', 'Power 5 is degraded'],
['', 'Power 1 is OK', 'Power 4 is OK']]
>>> r.add_mlist((CRITICAL,WARNING,OK),logs.sgrep(('critical|failed','degraded|warning')))
>>> print r                                                   
STATUS : CRITICAL:2, WARNING:2, OK:2
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
Power 0 is critical
Power 3 is failed

----( WARNING )-----------------------------------------------------------------
Power 2 is degraded
Power 5 is degraded

----( OK )----------------------------------------------------------------------
Power 1 is OK
Power 4 is OK

>>> r = PluginResponse(OK)
>>> r.add_mlist((CRITICAL,WARNING,None),logs.sgrep(('critical|failed','degraded|warning')))
>>> print r
STATUS : CRITICAL:2, WARNING:2
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
Power 0 is critical
Power 3 is failed

----( WARNING )-----------------------------------------------------------------
Power 2 is degraded
Power 5 is degraded

add_more(msg, *args, **kwargs)

Add a message in “more messages” section (aka “Additionnal informations”)

You can use this method several times and at any time until the send() is used. The messages will be displayed in the section in the same order as they have been added. This method does not change the calculated ResponseLevel.

Parameters:
  • msg (str) – the message to add in end section.
  • args (list) – if additional arguments are given, msg will be formatted with % (old-style python string formatting)
  • kwargs (dict) – if named arguments are give, msg will be formatted with str.format()

Note

The “Additionnal informations” section title will be added automatically if the section is not empty.

Examples

>>> r = PluginResponse(OK)
>>> r.add(CRITICAL,'This is critical !')
>>> r.add_more('Date : %s, Time : %s','2105-12-18','14:55:11')
>>> print r     
This is critical !
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
This is critical !

==========================[ Additionnal informations ]==========================
Date : 2105-12-18, Time : 14:55:11
add_perf_data(data)

Add performance object into the response

Parameters:data (str or PerfData) – the perf data string or PerfData object to add to the response. Have a look to Performance data string syntax.

Examples

>>> r = PluginResponse(OK)
>>> r.add_begin('Begin\n')
>>> r.add_end('End')
>>> r.add_perf_data(PerfData('filesystem_/','55','%','95','98','0','100'))
>>> r.add_perf_data(PerfData('filesystem_/usr','34','%','95','98','0','100'))
>>> r.add_perf_data('cpu_wait=88%;40;60;0;100')
>>> r.add_perf_data('cpu_user=12%;80;95;0;100')
>>> print r
OK|filesystem_/=55%;95;98;0;100
Begin
End| filesystem_/usr=34%;95;98;0;100 cpu_wait=88%;40;60;0;100 cpu_user=12%;80;95;0;100
escape_msg(msg)

Escapes forbidden chars in messages

Nagios does not accept the pipe symbol in messages because it is a separator for performance data. This method escapes or replace such forbidden chars. Default behaviour is to replace the pipe | by an exclamation mark !.

Parameters:msg (str) – The message to escape

Returns

str : The escaped message
get_current_level()

get current level

If no level has not been set yet, it will return the default_level. Use this method if you want to know what ResponseLevel will be sent.

Returns:the response level to be sent
Return type:ResponseLevel

Examples

>>> r = PluginResponse(OK)
>>> print r.get_current_level()
OK
>>> r.set_level(WARNING)
>>> print r.get_current_level()
WARNING
get_default_synopsis()

Returns the default synopsis

This method is called if no synopsis has been set manually, the response synopsis (first line of the text returned by the plugin) will be :

  • The error message if there is only one level message
  • Otherwise, some statistics like : STATUS : CRITICAL:2, WARNING:2, UNKNOWN:1, OK:2

If you want to have a different default synopsis, you can subclass the PluginResponse class and redefine this method.

Examples

>>> r = PluginResponse(OK)
>>> r.add(CRITICAL,'This is critical !')
>>> print r.get_default_synopsis()
This is critical !
>>> r.add(WARNING,'This is just a warning.')
>>> print r.get_default_synopsis()
STATUS : CRITICAL:1, WARNING:1
get_output(body_max_length=None)

Renders the whole response following the Nagios syntax

This method is automatically called when the response is sent by send(). If you want to have a different output, you can subclass the PluginResponse class and redefine this method.

Returns:The response text output following the Nagios syntax
Return type:str

Note

As __str__ directly calls get_output(), printing a PluginResponse object is equivalent to call get_output().

Example

>>> r = PluginResponse(OK)
>>> r.add(CRITICAL,'This is critical !')
>>> r.add(WARNING,'This is just a warning.')
>>> print r.get_output()
STATUS : CRITICAL:1, WARNING:1
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
This is critical !

----( WARNING )-----------------------------------------------------------------
This is just a warning.

>>> print r
STATUS : CRITICAL:1, WARNING:1
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
This is critical !

----( WARNING )-----------------------------------------------------------------
This is just a warning.

get_sublevel()

get sublevel

Returns:sublevel (0,1,2 or 3)
Return type:int

Exemples:

>>> r = PluginResponse(OK)
>>> print r.get_sublevel()
0
>>> r.set_sublevel(2)
>>> print r.get_sublevel()
2
level_msgs_render()

Renders level messages

This method is automatically called when the response is rendered by get_outpout(). If you want to have a different output, you can subclass the PluginResponse class and redefine this method.

Returns:The foramtted level messages
Return type:str

Example

>>> r = PluginResponse(OK)
>>> r.add(CRITICAL,'This is critical !')
>>> r.add(WARNING,'This is just a warning.')
>>> print r.level_msgs_render()
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
This is critical !

----( WARNING )-----------------------------------------------------------------
This is just a warning.

section_format(title)

Returns the section title string

This method is automatically called when the response is rendered by get_outpout(). If you want to have a different output, you can subclass the PluginResponse class and redefine this method.

Parameters:title (str) – the section name to be formatted
Returns:The foramtted section title
Return type:str

Example

>>> r = PluginResponse(OK)
>>> print r.section_format('My section')
=================================[ My section ]=================================
send(level=None, synopsis='', msg='', sublevel=None, nagios_host=None, nagios_svc=None, nagios_cmd=None)

Send the response to Nagios

This method is automatically called by naghelp.ActivePlugin.run() method and follow these steps :

  • if defined, force a level, a sublevel, a synopsis or add a last message
  • render the response string following the Nagios syntax
  • display the string on stdout
  • exit the plugin with the exit code corresponding to the response level.
Parameters:
  • level (ResponseLevel) – force a level (optional),
  • synopsis (str) – force a synopsis (optional),
  • msg (str) – add a last level message (optional),
  • sublevel (int) – force a sublevel [0-3] (optional),
  • nagios_host (str) – nagios hostname (only for passive response)
  • nagios_svc (str) – nagios service (only for passive response)
  • nagios_cmd (str or pynag obj) – if None, the response goes to stdout : this is for active plugin. if string the response is sent to the corresponding file for debug. if it is a pynag cmd object, the response is sent to the nagios pipe for host nagios_host and for service nagios_svc : this is for a passive plugin.
set_level(level)

Manually set the response level

Parameters:level (ResponseLevel) – OK, WARNING, CRITICAL or UNKNOWN

Examples

>>> r = PluginResponse(OK)
>>> print r.level
None
>>> r.set_level(WARNING)
>>> print r.level
WARNING
set_sublevel(sublevel)

sets sublevel attribute

Parameters:sublevel (int) – 0,1,2 or 3 (Default : 0)

From time to time, the CRITICAL status meaning is not detailed enough : It may be useful to color it by a sub-level. The sublevel value is not used directly by PluginResponse, but by ActivePlugin class which adds a __sublevel__=<sublevel> string in the plugin informations section. This string can be used for external filtering.

Actually, the sublevel meanings are :

Sub-level Description
0 The plugin is 100% sure there is a critical error
1 The plugin was able to contact remote host (ping) but got no answer from agent (timeout,credentials)
2 The plugin was unable to contact the remote host, it may be a network issue (firewall, …)
3 The plugin raised an unexpected exception : it should be a bug.
set_synopsis(msg, *args, **kwargs)

Sets the response synopsis.

By default, if no synopsis has been set manually, the response synopsis (first line of the text returned by the plugin) will be :

  • The error message if there is only one level message
  • Otherwise, some statistics like : STATUS : CRITICAL:2, WARNING:2, UNKNOWN:1, OK:2

If something else is wanted, one can define a custom synopsis with this method.

Parameters:
  • msg (str) – the synopsis.
  • args (list) – if additional arguments are given, msg will be formatted with % (old-style python string formatting)
  • kwargs (dict) – if named arguments are give, msg will be formatted with str.format()

Examples

>>> r = PluginResponse(OK)
>>> r.add(CRITICAL,'This is critical !')
>>> print r     
This is critical !
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
This is critical !

>>> r.set_synopsis('Mayday, Mayday, Mayday')
>>> print r     
Mayday, Mayday, Mayday
==================================[  STATUS  ]==================================

----( CRITICAL )----------------------------------------------------------------
This is critical !
subsection_format(title)

Returns the subsection title string

This method is automatically called when the response is rendered by get_outpout(). If you want to have a different output, you can subclass the PluginResponse class and redefine this method.

Parameters:title (str) – the subsection name to be formatted
Returns:The foramtted subsection title
Return type:str

Example

>>> r = PluginResponse(OK)
>>> print r.subsection_format('My subsection')
----( My subsection )-----------------------------------------------------------