-
-
Save sickel/de8997122203ab3946f4ae43b45e021d to your computer and use it in GitHub Desktop.
Parse the Nagios status.dat and print out lines to be read by postgresql file_fdw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
""" | |
This script reads the nagios status.dat file and exports it as a csv-file | |
the output can be read directly by postgresql file_fdw foreign data wrapper. | |
To set this up, make sure fdw_file is ready to use and define the following table: | |
create foreign table nagiosstatus( | |
statustype text, | |
hostname text, | |
service text, | |
time integer, | |
comment text, | |
author text, | |
state integer, | |
statuschange integer, | |
statusinfo text, | |
acknowledged integer, | |
jsondata jsonb) | |
server nagiosstatus options(program '/home/nagios/vaktside/vakt/status2json.py'); | |
I have selected those fields I need for our day to day work to be stored as field, all the | |
information is in the jsondata field and can be queried using the json query syntax. If | |
other fields are needed, the definition of the table can be changed, but then the lines for | |
printing out the data must also be changed. | |
the nagiosstatus server must be defined, cf documentation for fdw_file. | |
the program option must point to wherever this status2json.py script is installed- | |
The table can be queried directly, but if it is queried often, e.g. from | |
various grafana dashboards, it can be cached in a materialized view: | |
create materialized view nagiosstatus_cached as | |
select statustype, hostname, service, time, comment, author , state, statuschange, | |
statusinfo, acknowledged, jsondata | |
from nagiosstatus; | |
A materialized view will be stored as a table and needs to be updated through | |
refresh materialized view nagiosstatus_cached ; | |
It can be set up in crontab like this, given that the user can log on postgresql as the owner | |
of the materialized view without giving a password (e.g. using .pgpass) | |
*/2 * * * * /usr/bin/psql nagios -c 'refresh materialized view nagiosstatus_cached' > /dev/null | |
Forked from @alexwright | |
""" | |
import re | |
import json | |
import sys | |
STATUS_FILE_PATH = "/var/lib/nagios4/status.dat" | |
STATUS_FILE_PATH = "/usr/local/nagios/var/status.dat" | |
def read_status(): | |
hosts = {} | |
hostcomments = [] | |
servicecomments = [] | |
translation = str.maketrans({'"': r'\"',chr(9):' '}) | |
try: | |
fh = open(STATUS_FILE_PATH) | |
status_raw = fh.read() | |
except FileNotFoundError: | |
print(f'Cannot open {STATUS_FILE_PATH} - exiting') | |
sys.exit(2) | |
pattern = re.compile('([\w]+)\s+\{([\S\s]*?)\}',re.DOTALL) | |
matches = pattern.findall(status_raw) | |
for def_type, data in matches: | |
lines = [line.strip() for line in data.split("\n")] | |
# With the final json, there cannot be unescaped " in the string | |
lines = [line.translate(translation) for line in lines] | |
pairs = [line.split("=", 1) for line in lines if line != ''] | |
data = dict(pairs) | |
if def_type == "servicestatus": | |
if 'host_name' in data: | |
hosts[data['host_name']]['services'][data['service_description']]=data | |
if def_type == "hoststatus": | |
data['services'] = {} | |
data['comments'] = [] | |
hosts[data['host_name']] = data | |
if def_type == "hostcomment": | |
hostcomments.append(data) | |
if 'host_name' in data: | |
hosts[data['host_name']]['comments'].append(data) | |
if def_type == "servicecomment": | |
servicecomments.append(data) | |
if 'host_name' in data: | |
hosts[data['host_name']]['comments'].append(data) | |
return { | |
'hosts': hosts, | |
'servicecomments': servicecomments, | |
'hostcomments': hostcomments, | |
} | |
if __name__ == "__main__": | |
data = read_status() | |
""" | |
Output to be read by fdw_file. | |
Fields: | |
statustype, | |
host, | |
service, may be null | |
time, (entrytime or checktime) | |
comment, (for comment) | |
author, (for comment) | |
state, | |
problem start, | |
status information, | |
last change | |
plugin output | |
acked | |
jsondata | |
""" | |
comment = '' | |
author = '' | |
datatype = 'host' | |
for hostname in data['hosts']: | |
info = data['hosts'][hostname] | |
if 'services' in info: | |
datatype = 'service' | |
for servicename in info['services']: | |
service = info['services'][servicename] | |
jsondata = json.dumps(service) | |
print(f"{datatype}\t{hostname}\t{servicename}\t{service['last_check']}\t{comment}\t{author}\t\ | |
{service['current_state']}\t{service['last_time_ok']}\t{service['plugin_output']}\t\ | |
{service['problem_has_been_acknowledged']}\t{jsondata}") | |
# Do not want to keep the service info here. | |
del info['services'] | |
servicename = '' | |
if 'comments' in info: | |
datatype = 'comment' | |
for comment in info['comments']: | |
hostname = comment['host_name'] | |
if 'service_description' in comment: | |
servicename = comment['service_description'] | |
else: | |
servicename = '' | |
author = comment['author'] | |
commenttext = comment['comment_data'] | |
jsondata = json.dumps(comment) | |
time = comment['entry_time'].strip() | |
state = '' | |
print(f"{datatype}\t{hostname}\t{servicename}\t{time}\t{commenttext}\t{author}\t-1\t-1\t\t-1\t{jsondata}") | |
del info['comments'] | |
comment = '' | |
datatype = 'host' | |
jsondata = json.dumps(info) | |
print(f"{datatype}\t{hostname}\t{servicename}\t{info['last_check']}\t{comment}\t{author}\t\ | |
{info['current_state']}\t{info['last_time_up']}\t{info['plugin_output']}\t\ | |
{info['problem_has_been_acknowledged']}\t{jsondata}") | |
#sys.exit() | |
""" | |
for servicename in data['services']: | |
info = data['services'][servicename] | |
info['check_command'] = info['check_command'].replace('"',"'") | |
jsondata = json.dumps(info) | |
print(f"{datatype}\t{data['host_name']}\t{servicename}\t{info['last_check']}\t{comment}\t{author}\t\ | |
{info['current_state']}\t{info['last_state_change']}\t{info['plugin_output']}\t\ | |
{info['problem_has_been_acknowledged']}\t{jsondata}") | |
""" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
At the moment this is working. It makes no sense to build up the data structure that is needed for the json just to print out lines, so each status object could be printed out directly. I may rewrite it one day, or I may keep it as is since it is easy to change it back for json output.