Sensu monitoring module (#612)
This module connects to the API of a Sensu monitoring service and displays current status based on Sensu events. There is a formatter to display most recent event message too.
This commit is contained in:
parent
f451d922c2
commit
07c40bc715
120
i3pystatus/sensu.py
Normal file
120
i3pystatus/sensu.py
Normal file
@ -0,0 +1,120 @@
|
||||
from i3pystatus import IntervalModule, formatp
|
||||
|
||||
from enum import IntEnum
|
||||
import requests
|
||||
from urllib.parse import urljoin
|
||||
|
||||
|
||||
class SensuCheck(IntervalModule):
|
||||
""" Pool sensu api events
|
||||
|
||||
.. rubric:: Available formatters
|
||||
|
||||
* {status} OK if not events else numbers of events
|
||||
* {last_event} Display the output of the most recent event (with priority on error event)
|
||||
"""
|
||||
interval = 5
|
||||
|
||||
required = ("api_url",)
|
||||
|
||||
settings = (
|
||||
|
||||
("api_url", "URL of Sensu API. e.g: http://localhost/sensu/"),
|
||||
"api_username",
|
||||
"api_password",
|
||||
"format",
|
||||
"color_error",
|
||||
"color_warn",
|
||||
"color_ok",
|
||||
("last_event_label", "Label to put before the last event output (default 'Last:')"),
|
||||
("max_event_field", "Defines max length of the last_event message field "
|
||||
"(default: 50)"),
|
||||
)
|
||||
|
||||
api_url = None
|
||||
api_username = None
|
||||
api_password = None
|
||||
|
||||
format = "{status}"
|
||||
color_error = "#ff0000"
|
||||
color_warn = "#f9ba46"
|
||||
color_ok = "#00ff00"
|
||||
last_event_label = "Last:"
|
||||
max_event_field = 50
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
auth = ()
|
||||
if self.api_username:
|
||||
auth = (self.api_username, self.api_password or "")
|
||||
|
||||
response = requests.get(urljoin(self.api_url, "events"), auth=auth)
|
||||
if response.status_code != requests.codes.OK:
|
||||
self.error("could not query sensu api: {}".format(response.status_code))
|
||||
else:
|
||||
try:
|
||||
events = response.json()
|
||||
except ValueError:
|
||||
self.error("could not decode json")
|
||||
else:
|
||||
try:
|
||||
self.set_output(events)
|
||||
except KeyError as exc:
|
||||
self.error("could not find field {!s} in event".format(exc))
|
||||
except Exception as exc:
|
||||
self.output = {
|
||||
"full_text": "FAILED: {!s}".format(str(exc)),
|
||||
"color": self.color_error,
|
||||
}
|
||||
|
||||
def set_output(self, events):
|
||||
events = sorted(
|
||||
[e for e in events if e["action"] != "resolve" and not e["silenced"]],
|
||||
key=lambda x: x["last_ok"],
|
||||
reverse=True
|
||||
)
|
||||
|
||||
last_event_output = ""
|
||||
if not events:
|
||||
status = "OK"
|
||||
color = self.color_ok
|
||||
else:
|
||||
error = None
|
||||
try:
|
||||
error = next(e for e in events if e["check"]["status"] == SensuStatus.critical)
|
||||
except StopIteration:
|
||||
last_event = events[0]
|
||||
else:
|
||||
last_event = error
|
||||
|
||||
status = "{} event(s)".format(len(events))
|
||||
color = self.color_error if error else self.color_warn
|
||||
last_event_output = self.get_event_output(last_event)
|
||||
|
||||
self.output = {
|
||||
"full_text": formatp(self.format, status=status, last_event=last_event_output),
|
||||
"color": color,
|
||||
}
|
||||
|
||||
def get_event_output(self, event):
|
||||
output = (event["check"]["output"] or "").replace("\n", " ")
|
||||
if self.last_event_label:
|
||||
output = "{} {}".format(self.last_event_label, output)
|
||||
|
||||
if self.max_event_field and len(output) > self.max_event_field:
|
||||
output = output[:self.max_event_field]
|
||||
|
||||
return output
|
||||
|
||||
def error(self, error_msg):
|
||||
self.output = {
|
||||
"full_text": error_msg,
|
||||
"color": self.color_error,
|
||||
}
|
||||
|
||||
|
||||
class SensuStatus(IntEnum):
|
||||
ok = 0
|
||||
warn = 1
|
||||
critical = 2
|
||||
unknown = 3
|
Loading…
Reference in New Issue
Block a user