Commits

Carl Meyer  committed ed36871

initial code

  • Participants

Comments (0)

Files changed (17)

+dist/*
+django_errorstack.egg-info/*
+build/*
+*.pyc
+HGREV
+.project
+.pydevproject
+TAGS
+^dist/
+^django_errorstack.egg-info/
+^build/
+.pyc$
+^HGREV$
+^.project$
+^.pydevproject$
+^TAGS
+Carl Meyer <carl@dirtcircle.com>
+
+CHANGES
+=======
+
+tip (unreleased)
+----------------
+
+0.1 (2009.12.16)
+----------------
+
+- Initial release.
+Copyright (c) 2009, Carl Meyer
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of the author nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+include AUTHORS.txt
+include CHANGES.txt
+include LICENSE.txt
+include MANIFEST.in
+include README.txt
+include TODO.txt
+include HGREV
+===============
+django-errorstack
+===============
+
+A Django reusable application for logging errors to the `ErrorStack`_
+service.
+
+.. _ErrorStack: http://www.errorstack.com/
+
+Installation
+============
+
+Install from PyPI with ``easy_install`` or ``pip``::
+
+    pip install django-errorstack
+
+or get the `in-development version`_::
+
+    pip install django-errorstack==tip
+
+.. _in-development version: http://bitbucket.org/carljm/django-errorstack/get/tip.gz#egg=django_errorstack-tip
+
+Dependencies
+------------
+
+``django-errorstack`` requires `Django`_ 1.0 or later.
+
+.. _Django: http://www.djangoproject.com/
+
+Usage
+=====
+
+To use ``django-errorstack`` in your Django project:
+
+    1. Add ``'errorstack'`` to your ``INSTALLED_APPS`` setting.
+
+    2. Set the `ERRORSTACK_STACK_KEY`_ setting.
+
+    3. Add ``errorstack.middleware.ErrorStackMiddleware`` to the end
+       of your ``MIDDLEWARE_CLASSES`` setting.
+
+When ``DEBUG`` is False, all unhandled view exceptions will be logged
+to ErrorStack. Error handling will otherwise proceed as it would
+otherwise: ``django-errorstack`` does not disable or modify Django's
+usual error handling.
+
+Logging errors manually
+-----------------------
+
+You may want to log some errors to ErrorStack in your own code,
+without raising an unhandled exception or displaying a 500 page to
+your user.
+
+``django-errorstack`` uses a named logger from the Python standard
+library ``logging`` module. The name of the logger is defined by the
+`ERRORSTACK_LOGGER_NAME` setting (defaults to "errorstack"). Assuming
+you don't change the setting, you could log errors yourself like this::
+
+    import logging
+
+    logger = logging.getLogger("errorstack")
+
+    try:
+        #... some code that raises an exception
+    except:
+        logger.error("Something bad happpened.", exc_info=True)
+
+This logger only sends errors or critical errors (not warnings or info
+or debug messages) to ErrorStack.
+
+Attaching the ErrorStack handler to your own logger
+---------------------------------------------------
+
+Your application may already use the stdlib ``logging`` module with
+your own named loggers. If you want to attach the ErrorStack logger
+handler to your own loggers, you can do the following::
+
+    import logging
+
+    from errorstack.handlers import errorstack_handler
+
+    logger = logging.getLogger("my_logger")
+    logger.addHandler(errorstack_handler)
+
+Again, this handler only listens for errors or critical errors.
+
+Settings
+========
+
+ERRORSTACK_STACK_KEY
+--------------------
+
+The key of the error stack you want to send errors to. This option is
+required.
+
+ERRORSTACK_CATCH_404
+--------------------
+
+Log ``Http404`` exceptions to ErrorStack if this is
+``True``. ``False`` by default.
+
+ERRORSTACK_LOGGER_NAME
+----------------------
+
+The logger name to use. Defaults to "errorstack".
+TODO
+====
+

File errorstack/__init__.py

Empty file added.

File errorstack/handlers.py

+import logging
+import logging.handlers
+
+from errorstack import settings
+
+if settings.STACK_KEY is None:
+    raise ImproperlyConfigured('ErrorStackHandler requires the '
+                               'ERRORSTACK_STACK_KEY setting.')
+
+# This code modified from Python example at errorstack.com
+class ErrorStackHandler(logging.handlers.HTTPHandler):
+    def mapLogRecord(self, record):
+        """ Define the values submitted to ErrorStack.com. """
+        keys = ['name', 'msg', 'levelname', 'module', 'pathname', 'funcName',
+                'lineno', 'args', 'exc_text', 'threadName', 'thread', 'process',
+                'asctime']
+        info = {}
+        for key in keys:
+            info[key] = record.__dict__.get(key, '')
+        return info
+
+errorstack_handler = ErrorStackHandler(
+    "www.errorstack.com",
+    "/submit?_s=%s&_r=json" % settings.STACK_KEY,
+    "POST")
+errorstack_handler.setLevel(logging.ERROR)
+
+logger = logging.getLogger(settings.LOGGER_NAME)
+logger.addHandler(errorstack_handler)

File errorstack/middleware.py

+import logging
+
+from django.http import Http404
+from django.core.exceptions import MiddlewareNotUsed, ImproperlyConfigured
+from django.conf import settings as django_settings
+
+from errorstack import settings
+from errorstack.handlers import logger
+
+class ErrorStackMiddleware(object):
+
+    def __init__(self):
+        if settings.STACK_KEY is None:
+            raise ImproperlyConfigured('ErrorStackMiddleware requires the '
+                                       'ERRORSTACK_STACK_KEY setting.')
+        if django_settings.DEBUG:
+            raise MiddlewareNotUsed
+
+    def process_exception(self, request, exception):
+        if not settings.CATCH_404 and isinstance(exception, Http404):
+            return
+
+        logger.error('Unhandled exception', exc_info=True)

File errorstack/models.py

Empty file added.

File errorstack/settings.py

+from django.conf import settings
+
+STACK_KEY = getattr(settings, 'ERRORSTACK_STACK_KEY', None)
+CATCH_404 = getattr(settings, 'ERRORSTACK_CATCH_404', False)
+LOGGER_NAME = getattr(settings, 'ERRORSTACK_LOGGER_NAME', 'errorstack')

File errorstack/tests/__init__.py

+from errorstack.tests.tests import *

File errorstack/tests/runtests.py

+#!/usr/bin/env python
+
+from os.path import dirname, abspath
+import sys
+
+def runtests(*test_args):
+    if not test_args:
+        test_args = ['errorstack']
+    parent = dirname(dirname(dirname(abspath(__file__))))
+    sys.path.insert(0, parent)
+    from tests import django_settings
+    from django.test.utils import get_runner
+    test_runner = get_runner(django_settings)
+    failures = test_runner(test_args, verbosity=1, interactive=True)
+    sys.exit(failures)
+
+
+if __name__ == '__main__':
+    runtests(*sys.argv[1:])

File errorstack/tests/tests.py

+import datetime
+import os
+
+from django.conf import settings as django_settings
+
+if not django_settings.configured:
+    django_settings.configure(
+        DATABASE_ENGINE='sqlite3',
+        INSTALLED_APPS=(
+            'errorstack',
+        ),
+    )
+
+from django.test import TestCase
+
+__all__ = []
+
+# TODO!
+from setuptools import setup, find_packages
+import subprocess
+import os.path
+
+try:
+    # don't get confused if our sdist is unzipped in a subdir of some
+    # other hg repo
+    if os.path.isdir('.hg'):
+        p = subprocess.Popen(['hg', 'parents', r'--template={rev}\n'],
+                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        if not p.returncode:
+            fh = open('HGREV', 'w')
+            fh.write(p.communicate()[0].splitlines()[0])
+            fh.close()
+except (OSError, IndexError):
+    pass
+
+try:
+    hgrev = open('HGREV').read()
+except IOError:
+    hgrev = ''
+
+long_description = '\n'.join([open('README.txt').read(),
+                              open('CHANGES.txt').read(),
+                              open('TODO.txt').read()])
+setup(
+    name='django-errorstack',
+    version='0.1pre%s' % hgrev,
+    description=('Easy Django integration with the ErrorStack.com service'),
+    long_description=long_description,
+    author='Carl Meyer',
+    author_email='carl@dirtcircle.com',
+    url='http://bitbucket.org/carljm/django-errorstack/',
+    packages=find_packages(),
+    classifiers=[
+        'Development Status :: 3 - Alpha',
+        'Environment :: Web Environment',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: BSD License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Framework :: Django',
+    ],
+    zip_safe=False,
+    test_suite='errorstack.tests.runtests.runtests',
+)