255 строки
7.9 KiB
Python
255 строки
7.9 KiB
Python
import dictconfig
|
|
import logging
|
|
import sys
|
|
import json
|
|
|
|
from django.conf import settings
|
|
|
|
from mock import Mock, patch
|
|
from nose.tools import eq_
|
|
from metlog.config import client_from_dict_config
|
|
|
|
import amo.tests
|
|
import commonware.log
|
|
from lib.log_settings_base import error_fmt
|
|
from lib.metlog_shim import MetlogTastypieHandler
|
|
from lib.misc.admin_log import ErrorTypeHandler
|
|
from test_utils import RequestFactory
|
|
|
|
|
|
cfg = {
|
|
'version': 1,
|
|
'formatters': {
|
|
'error': {
|
|
'()': commonware.log.Formatter,
|
|
'datefmt': '%H:%M:%S',
|
|
'format': ('%s: [%%(USERNAME)s][%%(REMOTE_ADDR)s] %s'
|
|
% (settings.SYSLOG_TAG, error_fmt)),
|
|
},
|
|
},
|
|
'handlers': {
|
|
'test_syslog': {
|
|
'class': 'lib.misc.admin_log.ErrorSyslogHandler',
|
|
'formatter': 'error',
|
|
},
|
|
},
|
|
'loggers': {
|
|
'test.lib.misc.logging': {
|
|
'handlers': ['test_syslog'],
|
|
'level': 'ERROR',
|
|
'propagate': False,
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
class TestErrorLog(amo.tests.TestCase):
|
|
|
|
def setUp(self):
|
|
dictconfig.dictConfig(cfg)
|
|
self.log = logging.getLogger('test.lib.misc.logging')
|
|
self.request = RequestFactory().get('http://foo.com/blargh')
|
|
|
|
def division_error(self):
|
|
try:
|
|
1 / 0
|
|
except:
|
|
return sys.exc_info()
|
|
|
|
def io_error(self):
|
|
class IOError(Exception):
|
|
pass
|
|
try:
|
|
raise IOError('request data read error')
|
|
except:
|
|
return sys.exc_info()
|
|
|
|
def fake_record(self, exc_info):
|
|
record = Mock()
|
|
record.exc_info = exc_info
|
|
record.should_email = None
|
|
return record
|
|
|
|
def test_should_email(self):
|
|
et = ErrorTypeHandler()
|
|
assert et.should_email(self.fake_record(self.division_error()))
|
|
|
|
def test_should_not_email(self):
|
|
et = ErrorTypeHandler()
|
|
assert not et.should_email(self.fake_record(self.io_error()))
|
|
|
|
@patch('lib.misc.admin_log.ErrorTypeHandler.emitted')
|
|
def test_called_email(self, emitted):
|
|
self.log.error('blargh!',
|
|
exc_info=self.division_error(),
|
|
extra={'request': self.request})
|
|
eq_(set([n[0][0] for n in emitted.call_args_list]),
|
|
set(['errorsysloghandler']))
|
|
|
|
@patch('lib.misc.admin_log.ErrorTypeHandler.emitted')
|
|
def test_called_no_email(self, emitted):
|
|
self.log.error('blargh!',
|
|
exc_info=self.io_error(),
|
|
extra={'request': self.request})
|
|
eq_(set([n[0][0] for n in emitted.call_args_list]),
|
|
set(['errorsysloghandler']))
|
|
|
|
@patch('lib.misc.admin_log.ErrorTypeHandler.emitted')
|
|
def test_no_exc_info_request(self, emitted):
|
|
self.log.error('blargh!')
|
|
eq_(set([n[0][0] for n in emitted.call_args_list]),
|
|
set(['errorsysloghandler']))
|
|
|
|
@patch('lib.misc.admin_log.ErrorTypeHandler.emitted')
|
|
def test_no_request(self, emitted):
|
|
self.log.error('blargh!',
|
|
exc_info=self.io_error())
|
|
eq_(set([n[0][0] for n in emitted.call_args_list]),
|
|
set(['errorsysloghandler']))
|
|
|
|
|
|
class TestMetlogStdLibLogging(amo.tests.TestCase):
|
|
|
|
def setUp(self):
|
|
METLOG_CONF = {
|
|
'sender': {
|
|
'class': 'metlog.senders.logging.StdLibLoggingSender',
|
|
'logger_name': 'z.metlog',
|
|
}
|
|
}
|
|
self.metlog = client_from_dict_config(METLOG_CONF)
|
|
self.logger = logging.getLogger('z.metlog')
|
|
|
|
"""
|
|
When logging.config.dictConfig is used to configure logging
|
|
with a 'one-shot' config dictionary, any previously
|
|
instantiated singleton loggers (ie: all old loggers not in
|
|
the new config) will be explicitly disabled.
|
|
"""
|
|
self.logger.disabled = False
|
|
|
|
self._orig_handlers = self.logger.handlers
|
|
self.handler = logging.handlers.BufferingHandler(65536)
|
|
self.logger.handlers = [self.handler]
|
|
|
|
def tearDown(self):
|
|
self.logger.handlers = self._orig_handlers
|
|
|
|
def test_oldstyle_sends_msg(self):
|
|
msg = 'error'
|
|
self.metlog.error(msg)
|
|
logrecord = self.handler.buffer[-1]
|
|
self.assertEqual(logrecord.msg, msg)
|
|
self.assertEqual(logrecord.levelname, 'ERROR')
|
|
|
|
msg = 'info'
|
|
self.metlog.info(msg)
|
|
logrecord = self.handler.buffer[-1]
|
|
self.assertEqual(logrecord.msg, msg)
|
|
self.assertEqual(logrecord.levelname, 'INFO')
|
|
|
|
msg = 'warn'
|
|
self.metlog.warn(msg)
|
|
logrecord = self.handler.buffer[-1]
|
|
self.assertEqual(logrecord.msg, msg)
|
|
self.assertEqual(logrecord.levelname, 'WARNING')
|
|
|
|
# debug shouldn't log
|
|
msg = 'debug'
|
|
self.metlog.debug(msg)
|
|
logrecord = self.handler.buffer[-1]
|
|
self.assertNotEqual(logrecord.msg, msg)
|
|
self.assertNotEqual(logrecord.levelname, 'DEBUG')
|
|
|
|
def test_other_sends_json(self):
|
|
timer = 'footimer'
|
|
elapsed = 4
|
|
self.metlog.timer_send(timer, elapsed)
|
|
logrecord = self.handler.buffer[-1]
|
|
self.assertEqual(logrecord.levelname, 'INFO')
|
|
msg = json.loads(logrecord.msg)
|
|
self.assertEqual(msg['type'], 'timer')
|
|
self.assertEqual(msg['payload'], str(elapsed))
|
|
self.assertEqual(msg['fields']['name'], timer)
|
|
|
|
|
|
class TestRaven(amo.tests.TestCase):
|
|
def setUp(self):
|
|
"""
|
|
We need to set the settings.METLOG instance to use a
|
|
DebugCaptureSender so that we can inspect the sent messages.
|
|
|
|
We also need to force list of handlers for
|
|
'django.request.tastypie' to use only the MetlogTastypieHandler,
|
|
then revert the list of handlers back to whatever they were
|
|
prior to invoking the test case.
|
|
"""
|
|
|
|
metlog = settings.METLOG
|
|
METLOG_CONF = {
|
|
'logger': 'zamboni',
|
|
'sender': {'class': 'metlog.senders.DebugCaptureSender'},
|
|
}
|
|
from metlog.config import client_from_dict_config
|
|
self.metlog = client_from_dict_config(METLOG_CONF, metlog)
|
|
|
|
def test_send_raven(self):
|
|
try:
|
|
1 / 0
|
|
except:
|
|
self.metlog.raven('blah')
|
|
|
|
eq_(len(self.metlog.sender.msgs), 1)
|
|
msg = json.loads(self.metlog.sender.msgs[0])
|
|
eq_(msg['type'], 'sentry')
|
|
|
|
|
|
class TestTastypieHandler(amo.tests.TestCase):
|
|
def setUp(self):
|
|
"""
|
|
We need to set the settings.METLOG instance to use a
|
|
DebugCaptureSender so that we can inspect the sent messages.
|
|
|
|
We also need to force list of handlers for
|
|
'django.request.tastypie' to use only the MetlogTastypieHandler,
|
|
then revert the list of handlers back to whatever they were
|
|
prior to invoking the test case.
|
|
"""
|
|
|
|
metlog = settings.METLOG
|
|
METLOG_CONF = {
|
|
'logger': 'zamboni',
|
|
'sender': {'class': 'metlog.senders.DebugCaptureSender'},
|
|
}
|
|
from metlog.config import client_from_dict_config
|
|
self.metlog = client_from_dict_config(METLOG_CONF, metlog)
|
|
self.metlog.sender.msgs.clear()
|
|
|
|
self.logger = logging.getLogger('django.request.tastypie')
|
|
|
|
"""
|
|
When logging.config.dictConfig is used to configure logging
|
|
with a 'one-shot' config dictionary, any previously
|
|
instantiated singleton loggers (ie: all old loggers not in
|
|
the new config) will be explicitly disabled.
|
|
"""
|
|
self.logger.disabled = False
|
|
|
|
self._orig_handlers = self.logger.handlers
|
|
self.logger.handlers = [MetlogTastypieHandler(settings.METLOG)]
|
|
|
|
def tearDown(self):
|
|
self.logger.handlers = self._orig_handlers
|
|
|
|
def test_tastypie_handler(self):
|
|
err_msg = "tastypie error triggered"
|
|
try:
|
|
1 / 0
|
|
except:
|
|
self.logger.error(err_msg)
|
|
|
|
msg = json.loads(self.metlog.sender.msgs[0])
|
|
|
|
eq_(msg['type'], 'sentry')
|
|
eq_(msg['fields']['msg'], err_msg)
|