Summary: - Replace logger module by the standard module 'logging'. - When a log message from the sandbox includes newlines (e.g. for tracebacks), keep those lines together in the Node log message. Previously each line was a different message, making it difficult to view tracebacks, particularly in prod where each line becomes a separate message object. - Fix assorted lint errors. Test Plan: Added a test for the log-line splitting and escaping logic. Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D3956pull/587/head
parent
7fd48364df
commit
534615dd50
@ -1,74 +0,0 @@
|
||||
"""
|
||||
Logging for code running in the sandbox. The output simply goes to stderr (which gets to the
|
||||
console of the Node process), but the levels allow some configuration.
|
||||
|
||||
We don't use the `logging` module because it assumes more about the `time` module than we have.
|
||||
|
||||
Usage:
|
||||
import logger
|
||||
log = logger.Logger(__name__, logger.DEBUG) # Or logger.WARN; default is logger.INFO.
|
||||
log.info("Hello world")
|
||||
-> produces "[I] [foo.bar] Hello world"
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
# Level definitions
|
||||
DEBUG = 10
|
||||
INFO = 20
|
||||
WARN = 30
|
||||
ERROR = 40
|
||||
CRITICAL = 50
|
||||
|
||||
# Level strings
|
||||
level_strings = {
|
||||
DEBUG: 'DEBUG',
|
||||
INFO: 'INFO',
|
||||
WARN: 'WARN',
|
||||
ERROR: 'ERROR',
|
||||
CRITICAL: 'CRITICAL',
|
||||
}
|
||||
|
||||
def log_stderr(level, name, msg):
|
||||
sys.stderr.write("[%s] [%s] %s\n" % (level_strings.get(level, '?'), name, msg))
|
||||
sys.stderr.flush()
|
||||
|
||||
_log_handler = log_stderr
|
||||
|
||||
def set_handler(log_handler):
|
||||
"""
|
||||
Allows overriding the handler for all log messages. The handler should be a function, called as
|
||||
log_handler(level, name, message).
|
||||
Returns the handler which was set previously.
|
||||
"""
|
||||
|
||||
global _log_handler # pylint: disable=global-statement
|
||||
prev = _log_handler
|
||||
_log_handler = log_handler
|
||||
return prev
|
||||
|
||||
|
||||
class Logger(object):
|
||||
"""
|
||||
The object that actually provides the logging interface, specifically the methods debug, info,
|
||||
warn, error, and critical. The constructor takes an argument for a name that gets included in
|
||||
each message, and a minimum level, below which messages get ignored.
|
||||
"""
|
||||
def __init__(self, name, min_level=INFO):
|
||||
self._name = name
|
||||
self._min_level = min_level
|
||||
|
||||
def _log(self, level, msg):
|
||||
if level >= self._min_level:
|
||||
_log_handler(level, self._name, msg)
|
||||
|
||||
def debug(self, msg):
|
||||
self._log(DEBUG, msg)
|
||||
def info(self, msg):
|
||||
self._log(INFO, msg)
|
||||
def warn(self, msg):
|
||||
self._log(WARN, msg)
|
||||
def error(self, msg):
|
||||
self._log(ERROR, msg)
|
||||
def critical(self, msg):
|
||||
self._log(CRITICAL, msg)
|
@ -1,38 +0,0 @@
|
||||
import unittest
|
||||
import logger
|
||||
|
||||
|
||||
class TestLogger(unittest.TestCase):
|
||||
def _log_handler(self, level, name, msg):
|
||||
self.messages.append((level, name, msg))
|
||||
|
||||
def setUp(self):
|
||||
self.messages = []
|
||||
self.orig_handler = logger.set_handler(self._log_handler)
|
||||
|
||||
def tearDown(self):
|
||||
logger.set_handler(self.orig_handler)
|
||||
|
||||
def test_logger(self):
|
||||
log = logger.Logger("foo", logger.INFO)
|
||||
log.info("Hello Info")
|
||||
log.debug("Hello Debug")
|
||||
log.warn("Hello Warn")
|
||||
|
||||
self.assertEqual(self.messages, [
|
||||
(logger.INFO, 'foo', 'Hello Info'),
|
||||
(logger.WARN, 'foo', 'Hello Warn'),
|
||||
])
|
||||
del self.messages[:]
|
||||
|
||||
log = logger.Logger("baz", logger.DEBUG)
|
||||
log.debug("Hello Debug")
|
||||
log.info("Hello Info")
|
||||
self.assertEqual(self.messages, [
|
||||
(logger.DEBUG, 'baz', 'Hello Debug'),
|
||||
(logger.INFO, 'baz', 'Hello Info'),
|
||||
])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
Loading…
Reference in new issue