Skip to content

Commit

Permalink
Add AlertManager API
Browse files Browse the repository at this point in the history
  • Loading branch information
goughes committed Feb 26, 2021
1 parent e049d6c commit bda6976
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/python/Utils/Timers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from builtins import object
import time
from datetime import tzinfo, timedelta


def timeFunction(func):
Expand Down Expand Up @@ -52,3 +53,47 @@ def __exit__(self, exc_type, exc_val, exc_tb):
runtime = end - self.start
msg = '{label} took {time} seconds to complete'
print(msg.format(label=self.label, time=runtime))


class LocalTimezone(tzinfo):

"""
A required python 2 class to determine current timezone for formatting rfc3339 timestamps
https://docs.python.org/2/library/datetime.html#tzinfo-objects
Required for sending alerts to the MONIT AlertManager
Can be removed once WMCore starts using python3
"""

def __init__(self):
super(LocalTimezone, self).__init__()
self.ZERO = timedelta(0)
self.STDOFFSET = timedelta(seconds=-time.timezone)
if time.daylight:
self.DSTOFFSET = timedelta(seconds=-time.altzone)
else:
self.DSTOFFSET = self.STDOFFSET

self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET

def utcoffset(self, dt):
if self._isdst(dt):
return self.DSTOFFSET
else:
return self.STDOFFSET

def dst(self, dt):
if self._isdst(dt):
return self.DSTDIFF
else:
return self.ZERO

def tzname(self, dt):
return time.tzname[self._isdst(dt)]

def _isdst(self, dt):
tt = (dt.year, dt.month, dt.day,
dt.hour, dt.minute, dt.second,
dt.weekday(), 0, 0)
stamp = time.mktime(tt)
tt = time.localtime(stamp)
return tt.tm_isdst > 0
86 changes: 86 additions & 0 deletions src/python/WMCore/Services/AlertManager/AlertManagerAPI.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""
AlertManagerAPI - send alerts to MONIT AlertManager via API calls
"""

from __future__ import division
from datetime import timedelta, datetime
import socket
import json

from WMCore.Services.pycurl_manager import RequestHandler
from Utils.Timers import LocalTimezone


class AlertManagerAPI(object):
"""
A class used to send alerts via the MONIT AlertManager API
"""

def __init__(self, alertManagerUrl):
self.alertManagerUrl = alertManagerUrl
# sender's hostname is added as an annotation
self.hostname = socket.gethostname()
self.mgr = RequestHandler()
self.ltz = LocalTimezone()

def send(self, alertName, severity, labels, end, generatorURL, annotations):
"""
configDict: the WMCore service configuration
alertName: a unique name for the alert
severity: low, medium, high
labels: a customizable dict of key:value pairs used for routing the alert, ex. "tag": "microservices"
must be configured in AlertManager by MONIT team
end: how many minutes until the alarm is silenced
generatorURL: this URL will be sent to AlertManager and configured as a clickable "Source" link in the web interface
annotations: a customizable dict of key:value pairs to be appended to the alert, typically:
"hostname": "the hostname where the alert generated" (appended automatically)
"summary": "a short description of the alert"
"description": "a longer informational message with details about the alert"
AlertManager JSON format reference: https://www.prometheus.io/docs/alerting/latest/clients/
[
{
"labels": {
"alertname": "<requiredAlertName>",
"<labelname>": "<labelvalue>",
...
},
"annotations": {
"<labelname>": "<labelvalue>",
...
},
"startsAt": "<rfc3339>", # optional, will be current time if not present
"endsAt": "<rfc3339>",
"generatorURL": "<generator_url>" # optional
},
]
"""

headers = {"Content-Type": "application/json"}
request = []
alert = {}

# add labels
labels["alertname"] = alertName
labels["severity"] = severity
alert["labels"] = labels

# add annotations
annotations["hostname"] = self.hostname
alert["annotations"] = annotations

# In python3 we won't need the LocalTimezone class
# Will change to d = datetime.now().astimezone() + timedelta(minutes = self.end)
d = datetime.now(self.ltz) + timedelta(minutes = end)
alert["endsAt"] = d.isoformat("T")
alert["generatorURL"] = generatorURL

request.append(alert)
# need to do this because pycurl_manager only accepts dict and encoded strings type
params = json.dumps(request)

res = self.mgr.getdata(self.alertManagerUrl, params=params, headers=headers, verb='POST')

return res

0 comments on commit bda6976

Please sign in to comment.