├── .gitignore ├── .python-version ├── LICENSE ├── MANIFEST.in ├── README.md ├── requirements.txt ├── sample.py ├── setup.py └── slack_log_handler └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.egg-info/ 3 | build/ 4 | *.pyc 5 | *~ 6 | dist/ 7 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 2.7.9 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 Claude Tech 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.md 2 | include LICENSE 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Slack log handler 2 | 3 | Simple Python log handler for Slack using Slack webhooks. 4 | 5 | # Installation 6 | 7 | ```sh 8 | $ pip install slack_log_handler 9 | ``` 10 | 11 | ## Usage 12 | 13 | The only required argument for `SlackLogHandler` is the webhook URL. 14 | You can pass the `channel`, `username`, or a dictionary of `emojis` for each 15 | log level as named arguments. 16 | 17 | Sample usage: 18 | 19 | ```python 20 | import os 21 | import logging 22 | from slack_log_handler import SlackLogHandler 23 | 24 | WEBHOOK_URL = os.getenv('SLACK_URL') 25 | 26 | slack_handler = SlackLogHandler(WEBHOOK_URL) 27 | slack_handler.setLevel(logging.WARNING) 28 | 29 | logger = logging.getLogger(__name__) 30 | logger.addHandler(slack_handler) 31 | 32 | logger.error('Oh my god, an error occurred!') 33 | ``` 34 | 35 | ## Troubleshooting 36 | 37 | On Linux, if you get an error of this kind, 38 | 39 | ``` 40 | SSL: CERTIFICATE_VERIFY_FAILED 41 | ``` 42 | 43 | make sure the `ca-certificates` package (or whatever package your distribution uses instead) is installed. 44 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -e . 2 | 3 | ipython 4 | -------------------------------------------------------------------------------- /sample.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | from slack_log_handler import SlackLogHandler 4 | 5 | WEBHOOK_URL = os.getenv('SLACK_URL') 6 | 7 | slack_handler = SlackLogHandler(WEBHOOK_URL) 8 | slack_handler.setLevel(logging.WARNING) 9 | 10 | logger = logging.getLogger(__name__) 11 | logger.addHandler(slack_handler) 12 | 13 | logger.error('Oh my god, an error occurred!') 14 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='slack_log_handler', 5 | version='0.3.0', 6 | author='Daniel Perez', 7 | author_email='daniel@claudetech.com', 8 | packages=['slack_log_handler'], 9 | url='https://github.com/claudetech/python-slack-log', 10 | license='LICENSE', 11 | description='Python Slack log handler using webhook', 12 | long_description=open('README.md').read(), 13 | classifiers=[ 14 | 'Development Status :: 4 - Beta', 15 | 'Intended Audience :: Developers', 16 | 'License :: OSI Approved :: MIT License', 17 | 'Operating System :: OS Independent', 18 | 'Programming Language :: Python', 19 | 'Topic :: Software Development :: Libraries' 20 | ], 21 | ) 22 | -------------------------------------------------------------------------------- /slack_log_handler/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json 3 | 4 | try: 5 | from urllib.request import urlopen, Request 6 | except ImportError: 7 | from urllib2 import urlopen, Request 8 | 9 | 10 | class SlackLogHandler(logging.Handler): 11 | EMOJIS = { 12 | logging.NOTSET: ':loudspeaker:', 13 | logging.DEBUG: ':speaker:', 14 | logging.INFO: ':information_source:', 15 | logging.WARNING: ':warning:', 16 | logging.ERROR: ':exclamation:', 17 | logging.CRITICAL: ':boom:' 18 | } 19 | 20 | def __init__(self, webhook_url, channel=None, username=None, emojis=None, 21 | format='[%(levelname)s] [%(asctime)s] [%(name)s] - %(message)s'): 22 | logging.Handler.__init__(self) 23 | self.webhook_url = webhook_url 24 | self.channel = channel 25 | self.username = username 26 | self.emojis = emojis if emojis is not None else SlackLogHandler.EMOJIS 27 | self.formatter = logging.Formatter(format) 28 | 29 | def _make_content(self, record): 30 | icon_emoji = getattr(record, 'slack_icon', self.emojis[record.levelno]) 31 | content = { 32 | 'text': self.format(record), 33 | 'icon_emoji': icon_emoji 34 | } 35 | if hasattr(record, 'slack_username'): 36 | content['username'] = getattr(record, 'slack_username') 37 | elif self.username: 38 | content['username'] = self.username 39 | else: 40 | content['username'] = "{0} - {1}".format(record.module, record.name) 41 | if self.channel: 42 | content['channel'] = self.channel 43 | return content 44 | 45 | def emit(self, record): 46 | try: 47 | req = Request(self.webhook_url) 48 | req.add_header('Content-Type', 'application/json') 49 | 50 | content = self._make_content(record) 51 | urlopen(req, json.dumps(content).encode("utf-8")) 52 | except: 53 | self.handleError(record) 54 | --------------------------------------------------------------------------------