Created
February 24, 2012 18:08
-
-
Save bkjones/1902478 to your computer and use it in GitHub Desktop.
A script I wrote to allow nagios to send an alert with an attached graphite graph via email.
This file contains 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/env python | |
""" | |
This takes a recipient email address and a graphite URL and sends a | |
POST to <graphite host>/dashboard/email with a body that looks like | |
this: | |
sender=user%40example.com&recipients=user2%40example.com&subject=foo&message=bar&graph_params=%7B%22target%22%3A%22target%3DdrawAsInfinite(metric.path.in.graphite)%22%2C%22from%22%3A%22-2hours%22%2C%22until%22%3A%22now%22%2C%22width%22%3A600%2C%22height%22%3A250%7D | |
...which will cause the graphite installation to send an email. | |
This script will also ping graphite so that you can | |
actually graph when these notifications were sent out as events, and | |
layer those graphs on top of the graphs that correspond to the notification | |
event, so we can visually verify that the alerts are going out (or attempted), | |
and that it's happening at the right time, etc. | |
Note that the pingback functionality sends the events to a metric in graphite | |
named 'nagios.<metricname>'. | |
""" | |
import requests | |
import logging | |
from socket import socket | |
import time | |
import sys | |
from email.mime.image import MIMEImage | |
from email.mime.text import MIMEText | |
from email.mime.multipart import MIMEMultipart | |
import smtplib | |
from optparse import OptionParser | |
CARBON_SERVER = 'host.name.fqdn' | |
CARBON_PORT = 2003 | |
logging.basicConfig(filename='/var/log/sendgraph.log', level=logging.DEBUG) | |
def send_graph_email(graph, subject, sender, receivers, body=None): | |
""" | |
Builds an email with the attached graph. | |
:param body: Text portion of the alert notification email. | |
:param graph: Assumed to be a PNG, currently. | |
:param subject: Email subject line | |
:param sender: an email address | |
:param receivers: list of email addresses to send to. | |
:return: | |
""" | |
logging.debug("body: %s subject: %s sender: %s receivers: %s" % (body, subject, sender, receivers)) | |
if body is None: | |
body = '\n' | |
msg = MIMEMultipart() | |
msg.attach(MIMEText(body)) | |
imgpart = MIMEImage(graph, _subtype='png') | |
imgpart.add_header('Content-Disposition', 'attachment', filename='graph.png') | |
msg.attach(imgpart) | |
msg['to'] = ', '.join(receivers) | |
msg['from'] = sender | |
msg['subject'] = subject | |
s = smtplib.SMTP() | |
try: | |
s.connect() | |
s.sendmail(sender, receivers, msg.as_string()) | |
s.close() | |
except Exception as out: | |
logging.error("Sending mail failed: %s" % out) | |
def ping_graphite(metric_name): | |
sock = socket() | |
try: | |
sock.connect( (CARBON_SERVER,CARBON_PORT) ) | |
except: | |
print "Couldn't connect to %(server)s on port %(port)d, is carbon-agent.py running?" % { 'server':CARBON_SERVER, 'port':CARBON_PORT } | |
sys.exit(1) | |
now = time.time() | |
message = '%s %s %s\n' % (metric_name, '1.0', now) | |
try: | |
sock.sendall(message) | |
except Exception as out: | |
logging.error("Updating graphite failed: %s", out) | |
sys.exit(1) | |
logging.info("Updated graphite: %s", message) | |
def do_options(): | |
parser = OptionParser() | |
parser.add_option('-u', '--url', | |
action='store', | |
dest='graph_url', | |
help="URL to the graphite graph that spawned the nagios alert") | |
parser.add_option('-t', '--to', | |
action='store', | |
dest = 'recip', | |
help='Email address of the alert recipient.') | |
parser.add_option('-n', '--name', | |
action='store', | |
dest='alertname', | |
help='The $SERVICENAME$ or $HOSTNAME$ from nagios.') | |
parser.add_option('-s', '--state', | |
action='store', | |
dest='state', | |
help='The $SERVICESTATE$ or $HOSTSTATE$ from nagios.') | |
options, args = parser.parse_args() | |
return options | |
def main(): | |
options = do_options() | |
graph_url = options.graph_url | |
logging.debug('graph url is %s' % graph_url) | |
alertname = options.alertname | |
state = options.state | |
metric_name = '%s.%s.%s' % ('nagios', alertname.replace(' ', '_'), state) | |
subject = '%s: %s' % (state, alertname) | |
sender = '[email protected]' | |
receivers = options.recip.split(' ') | |
graph = requests.get(graph_url) | |
logging.debug("Response headers for graph request: %s", graph.headers) | |
body = "According to graphite, %s is in a %s state. Here's a graph. Check it out." % (alertname, state) | |
send_graph_email(graph.content, subject, sender, receivers, body) | |
logging.debug("Mail sent - pinging graphite now...") | |
ping_graphite(metric_name) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi Brian,
This script doesn't have a license attached, and I certainly wouldn't want to make an incorrect assumption about its licensing terms. I'm in a corporate environment, so the consequences of getting licensing wrong can be pretty dramatic.
Would you be willing to attach a clear open source license to the script?
Thanks,
John