Last active
February 25, 2017 00:37
-
-
Save tomchuk/c5d87aba8a710e953083 to your computer and use it in GitHub Desktop.
TrackJS Incoming Webhook for Slack
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/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