Skip to content

Instantly share code, notes, and snippets.

@tomchuk
Last active February 25, 2017 00:37
Show Gist options
  • Select an option

  • Save tomchuk/c5d87aba8a710e953083 to your computer and use it in GitHub Desktop.

Select an option

Save tomchuk/c5d87aba8a710e953083 to your computer and use it in GitHub Desktop.
TrackJS Incoming Webhook for Slack
#!/usr/bin/env python
import argparse
import calendar
import datetime
import hashlib
import json
import logging
import requests
import sqlite3
class TrackJSAPI(object):
api_url = 'https://api.trackjs.com/{}/v1/errors/messages'
def __init__(self, customer_id, api_key, db_path):
self.customer_id = customer_id
self.api_key = api_key
self.now = calendar.timegm(datetime.datetime.utcnow().utctimetuple())
self.con = sqlite3.connect(db_path)
self.con.row_factory = sqlite3.Row
self.cur = self.con.cursor()
self._put_schema()
self._messages = []
self._new = []
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
if type:
logging.error(u'{}: {}'.format(type, value))
logging.error(traceback)
self.con.rollback()
else:
self.con.commit()
self.cur.close()
self.con.close()
def _put_schema(self):
schema = '''
CREATE TABLE IF NOT EXISTS
messages(
hash TEXT PRIMARY KEY,
key TEXT,
count INT,
url TEXT,
fetched_at INT
)
'''
self.cur.execute(schema)
def _fetch_messages(self):
page = 0
params = {'startDate': self.last_fetched, 'page': page}
has_more = True
while(has_more):
params.update({'page': params['page']+1})
response = requests.get(
self.api_url.format(self.customer_id),
headers={'Authorization': self.api_key},
params=params, verify=False)
if response.status_code != 200:
raise RuntimeError(response.text)
response = response.json()
self._messages += response['data']
has_more = response['metadata']['hasMore']
@property
def messages(self):
if not self._messages:
self._fetch_messages()
return self._messages
@property
def last_fetched(self):
if not getattr(self, '_last_fetched', None):
try:
self._last_fetched = self.cur.execute('SELECT DATETIME(fetched_at, "unixepoch", "utc") as last_fetched FROM messages ORDER BY last_fetched DESC LIMIT 1').fetchall()[0]['last_fetched']
except:
self._last_fetched = (datetime.date.today()-datetime.timedelta(days=1)).isoformat()
return self._last_fetched
@property
def new(self):
if not self._new:
fetched_keys = set([hashlib.sha1(m['key'].encode('utf8')).hexdigest() for m in self.messages])
query = u'SELECT hash FROM messages'
existing_keys = set([m['hash'] for m in self.cur.execute(query).fetchall()])
new_keys = fetched_keys - existing_keys
new_messages = {}
for m in self.messages:
msg_hash = hashlib.sha1(m['key'].encode('utf8')).hexdigest()
if msg_hash in new_keys:
new_messages[msg_hash] = m
new_messages = new_messages.values()
query = u'INSERT INTO messages VALUES (?,?,?,?,?)'
params = [(hashlib.sha1(m['key'].encode('utf8')).hexdigest(),
m['key'], m['count'], m['trackJsUrl'],
self.now) for m in new_messages]
self.con.executemany(query, params)
self._new = new_messages
return self._new
def main():
parser = argparse.ArgumentParser(description='Fetch new error messages from TrackJS')
parser.add_argument('-a', '--api_key', help='TrackJS API Key', required=True)
parser.add_argument('-c', '--customer_id', help='TrackJS Customer ID', required=True)
parser.add_argument('-d', '--db_path', help='Database Path', default='./messages.sqlite3')
parser.add_argument('-s', '--channel', help='Slack Channel', default='#devlog')
parser.add_argument('-n', '--name', help='Slack message username', default='TrackJS')
parser.add_argument('-u', '--url', help='Slack Incomming webhook url', required=True)
parser.add_argument('-p', '--prepopulate', help='Fill DB with known errors, don\'t send messages', action='store_true', default=False)
args = parser.parse_args()
with TrackJSAPI(api_key=args.api_key, customer_id=args.customer_id, db_path=args.db_path) as api:
if args.prepopulate:
api.new
else:
for message in api.new:
payload = {
'channel': args.channel,
'username': args.name,
'attachments': [{
'fallback': u'<{}|{}>'.format(message['trackJsUrl'], message['key'][0:50]),
'pretext': u'New Error: <{}|View on TrackJS>'.format(message['trackJsUrl']),
'color': 'danger',
'fields': [{
'title': 'Error Details',
'value': message['key'],
'short': False
}]
}]
}
requests.post(args.url, data=json.dumps(payload))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment