mirror of
https://github.com/sprockets/sprockets.logging.git
synced 2024-12-27 20:24:41 +00:00
commit
16a57b6484
4 changed files with 81 additions and 7 deletions
|
@ -1,6 +1,10 @@
|
|||
Version History
|
||||
===============
|
||||
|
||||
`1.3.0`_ Aug 28, 2015
|
||||
---------------------
|
||||
- Add the traceback and environment if set
|
||||
|
||||
`1.2.1`_ Jun 24, 2015
|
||||
---------------------
|
||||
- Fix a potential ``KeyError`` when a HTTP request object is not present.
|
||||
|
|
|
@ -13,14 +13,16 @@ from __future__ import absolute_import
|
|||
from logging import config
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
try:
|
||||
from tornado import log
|
||||
except ImportError:
|
||||
log = None
|
||||
|
||||
version_info = (1, 2, 1)
|
||||
version_info = (1, 3, 0)
|
||||
__version__ = '.'.join(str(v) for v in version_info)
|
||||
|
||||
# Shortcut methods and constants to avoid needing to import logging directly
|
||||
|
@ -65,6 +67,28 @@ class JSONRequestFormatter(logging.Formatter):
|
|||
the log data as JSON.
|
||||
|
||||
"""
|
||||
|
||||
def extract_exc_record(self, typ, val, tb):
|
||||
"""Create a JSON representation of the traceback given the records
|
||||
exc_info
|
||||
|
||||
:param `Exception` typ: Exception type of the exception being handled
|
||||
:param `Exception` instance val: instance of the Exception class
|
||||
:param `traceback` tb: traceback object with the call stack
|
||||
|
||||
:rtype: dict
|
||||
|
||||
"""
|
||||
exc_record = {'type': typ.__name__,
|
||||
'message': str(val),
|
||||
'stack': []}
|
||||
for file_name, line_no, func_name, txt in traceback.extract_tb(tb):
|
||||
exc_record['stack'].append({'file': file_name,
|
||||
'line': str(line_no),
|
||||
'func': func_name,
|
||||
'text': txt})
|
||||
return exc_record
|
||||
|
||||
def format(self, record):
|
||||
"""Return the log data as JSON
|
||||
|
||||
|
@ -72,6 +96,12 @@ class JSONRequestFormatter(logging.Formatter):
|
|||
:rtype: str
|
||||
|
||||
"""
|
||||
if hasattr(record, 'exc_info'):
|
||||
try:
|
||||
traceback = self.extract_exc_record(*record.exc_info)
|
||||
except:
|
||||
traceback = None
|
||||
|
||||
output = {'name': record.name,
|
||||
'module': record.module,
|
||||
'message': record.msg % record.args,
|
||||
|
@ -81,7 +111,8 @@ class JSONRequestFormatter(logging.Formatter):
|
|||
'timestamp': self.formatTime(record),
|
||||
'thread': record.threadName,
|
||||
'file': record.filename,
|
||||
'request': record.args}
|
||||
'request': record.args,
|
||||
'traceback': traceback}
|
||||
for key, value in list(output.items()):
|
||||
if not value:
|
||||
del output[key]
|
||||
|
@ -119,7 +150,8 @@ def tornado_log_function(handler):
|
|||
'protocol': handler.request.protocol,
|
||||
'query_args': handler.request.query_arguments,
|
||||
'remote_ip': handler.request.remote_ip,
|
||||
'status_code': status_code})
|
||||
'status_code': status_code,
|
||||
'environment': os.environ.get('ENVIRONMENT')})
|
||||
|
||||
|
||||
def currentframe():
|
||||
|
|
41
tests.py
41
tests.py
|
@ -1,5 +1,6 @@
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import unittest
|
||||
import uuid
|
||||
|
@ -7,9 +8,10 @@ import uuid
|
|||
import mock
|
||||
|
||||
import sprockets.logging
|
||||
from tornado import web, testing
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
os.environ['ENVIRONMENT'] = 'testing'
|
||||
|
||||
class Prototype(object):
|
||||
pass
|
||||
|
@ -91,9 +93,11 @@ class TornadoLogFunctionTestCase(unittest.TestCase):
|
|||
'protocol': handler.request.protocol,
|
||||
'query_args': handler.request.query_arguments,
|
||||
'remote_ip': handler.request.remote_ip,
|
||||
'status_code': handler.status_code})
|
||||
'status_code': handler.status_code,
|
||||
'environment': os.environ['ENVIRONMENT']})
|
||||
sprockets.logging.tornado_log_function(handler)
|
||||
access_log.assertCalledOnceWith(expectation)
|
||||
access_log.info.assert_called_once_with(*expectation)
|
||||
|
||||
|
||||
|
||||
class JSONRequestHandlerTestCase(unittest.TestCase):
|
||||
|
@ -135,3 +139,34 @@ class JSONRequestHandlerTestCase(unittest.TestCase):
|
|||
value = json.loads(result)
|
||||
for key in keys:
|
||||
self.assertIn(key, value)
|
||||
|
||||
|
||||
class JSONRequestFormatterTestCase(testing.AsyncHTTPTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(JSONRequestFormatterTestCase, self).setUp()
|
||||
self.recorder = RecordingHandler()
|
||||
self.formatter = sprockets.logging.JSONRequestFormatter()
|
||||
self.recorder.setFormatter(self.formatter)
|
||||
web.app_log.addHandler(self.recorder)
|
||||
|
||||
def tearDown(self):
|
||||
super(JSONRequestFormatterTestCase, self).tearDown()
|
||||
web.app_log.removeHandler(self.recorder)
|
||||
|
||||
def get_app(self):
|
||||
class JustFail(web.RequestHandler):
|
||||
def get(self):
|
||||
raise RuntimeError('something busted')
|
||||
|
||||
return web.Application([web.url('/', JustFail)])
|
||||
|
||||
def test_that_things_happen(self):
|
||||
self.fetch('/')
|
||||
self.assertEqual(len(self.recorder.log_lines), 1)
|
||||
|
||||
failure_info = json.loads(self.recorder.log_lines[0])
|
||||
self.assertEqual(failure_info['traceback']['type'], 'RuntimeError')
|
||||
self.assertEqual(failure_info['traceback']['message'],
|
||||
'something busted')
|
||||
self.assertEqual(len(failure_info['traceback']['stack']), 2)
|
||||
|
|
5
tox.ini
5
tox.ini
|
@ -7,4 +7,7 @@ skip_missing_interpreters = true
|
|||
|
||||
[testenv]
|
||||
commands = nosetests []
|
||||
deps = nose
|
||||
deps =
|
||||
nose
|
||||
mock
|
||||
tornado
|
||||
|
|
Loading…
Reference in a new issue