Replace RFCSysLogHandler by a syslog() based one
Rather than using the Python provided logging module that reimplents the
whole syslog protocol and pointing it to /dev/log (which is not
portable), we use the system calls from the syslog module, which are
portable and default to the behaviour we actually want.
Closes-Bug: 1385295
Closes-Bug: 1391428
Partial-Bug: 1459046
(cherry picked from commit 33f5c6f94d
)
Conflicts:
oslo_log/log.py
requirements.txt
Change-Id: I2e47c896841cbd43d1f5504f2b8b897fc432cd0b
This commit is contained in:
parent
9a9a2cbb1c
commit
9a6c22663b
|
@ -15,6 +15,9 @@ import logging
|
|||
import logging.config
|
||||
import logging.handlers
|
||||
import os
|
||||
import syslog
|
||||
|
||||
from debtcollector import removals
|
||||
|
||||
|
||||
try:
|
||||
|
@ -36,6 +39,17 @@ def _get_binary_name():
|
|||
|
||||
|
||||
class RFCSysLogHandler(logging.handlers.SysLogHandler):
|
||||
"""SysLogHandler following the RFC
|
||||
|
||||
.. deprecated:: 1.2.0
|
||||
Use :class:`OSSysLogHandler` instead
|
||||
"""
|
||||
|
||||
@removals.remove(
|
||||
message='use oslo_log.handlers.OSSysLogHandler()',
|
||||
version='1.2.0',
|
||||
removal_version='?',
|
||||
)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.binary_name = _get_binary_name()
|
||||
# Do not use super() unless type(logging.handlers.SysLogHandler)
|
||||
|
@ -54,6 +68,33 @@ class RFCSysLogHandler(logging.handlers.SysLogHandler):
|
|||
_AUDIT = logging.INFO + 1
|
||||
|
||||
|
||||
class OSSysLogHandler(logging.Handler):
|
||||
severity_map = {
|
||||
"CRITICAL": syslog.LOG_CRIT,
|
||||
"DEBUG": syslog.LOG_DEBUG,
|
||||
"ERROR": syslog.LOG_ERR,
|
||||
"INFO": syslog.LOG_INFO,
|
||||
"WARNING": syslog.LOG_WARNING,
|
||||
"WARN": syslog.LOG_WARNING,
|
||||
}
|
||||
|
||||
def __init__(self, facility=syslog.LOG_USER,
|
||||
use_syslog_rfc_format=True):
|
||||
# Do not use super() unless type(logging.Handler) is 'type'
|
||||
# (i.e. >= Python 2.7).
|
||||
logging.Handler.__init__(self)
|
||||
if use_syslog_rfc_format:
|
||||
binary_name = _get_binary_name()
|
||||
else:
|
||||
binary_name = ""
|
||||
syslog.openlog(binary_name, 0, facility)
|
||||
|
||||
def emit(self, record):
|
||||
syslog.syslog(self.severity_map.get(record.levelname,
|
||||
syslog.LOG_DEBUG),
|
||||
record.getMessage())
|
||||
|
||||
|
||||
class ColorHandler(logging.StreamHandler):
|
||||
LEVEL_COLORS = {
|
||||
logging.DEBUG: '\033[00;32m', # GREEN
|
||||
|
@ -66,4 +107,4 @@ class ColorHandler(logging.StreamHandler):
|
|||
|
||||
def format(self, record):
|
||||
record.color = self.LEVEL_COLORS[record.levelno]
|
||||
return logging.StreamHandler.format(self, record)
|
||||
return logging.StreamHandler.format(self, record)
|
||||
|
|
|
@ -31,8 +31,8 @@ import logging
|
|||
import logging.config
|
||||
import logging.handlers
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import syslog
|
||||
import traceback
|
||||
|
||||
from oslo_config import cfg
|
||||
|
@ -229,28 +229,30 @@ def set_defaults(logging_context_format_string=None,
|
|||
logging_context_format_string=logging_context_format_string)
|
||||
|
||||
|
||||
def _find_facility_from_conf(conf):
|
||||
facility_names = logging.handlers.SysLogHandler.facility_names
|
||||
facility = getattr(logging.handlers.SysLogHandler,
|
||||
conf.syslog_log_facility,
|
||||
None)
|
||||
def _find_facility(facility):
|
||||
# NOTE(jd): Check the validity of facilities at run time as they differ
|
||||
# depending on the OS and Python version being used.
|
||||
valid_facilities = [f for f in
|
||||
["LOG_KERN", "LOG_USER", "LOG_MAIL",
|
||||
"LOG_DAEMON", "LOG_AUTH", "LOG_SYSLOG",
|
||||
"LOG_LPR", "LOG_NEWS", "LOG_UUCP",
|
||||
"LOG_CRON", "LOG_AUTHPRIV", "LOG_FTP",
|
||||
"LOG_LOCAL0", "LOG_LOCAL1", "LOG_LOCAL2",
|
||||
"LOG_LOCAL3", "LOG_LOCAL4", "LOG_LOCAL5",
|
||||
"LOG_LOCAL6", "LOG_LOCAL7"]
|
||||
if getattr(syslog, f, None)]
|
||||
|
||||
if facility is None and conf.syslog_log_facility in facility_names:
|
||||
facility = facility_names.get(conf.syslog_log_facility)
|
||||
facility = facility.upper()
|
||||
|
||||
if facility is None:
|
||||
valid_facilities = facility_names.keys()
|
||||
consts = ['LOG_AUTH', 'LOG_AUTHPRIV', 'LOG_CRON', 'LOG_DAEMON',
|
||||
'LOG_FTP', 'LOG_KERN', 'LOG_LPR', 'LOG_MAIL', 'LOG_NEWS',
|
||||
'LOG_AUTH', 'LOG_SYSLOG', 'LOG_USER', 'LOG_UUCP',
|
||||
'LOG_LOCAL0', 'LOG_LOCAL1', 'LOG_LOCAL2', 'LOG_LOCAL3',
|
||||
'LOG_LOCAL4', 'LOG_LOCAL5', 'LOG_LOCAL6', 'LOG_LOCAL7']
|
||||
valid_facilities.extend(consts)
|
||||
if not facility.startswith("LOG_"):
|
||||
facility = "LOG_" + facility
|
||||
|
||||
if facility not in valid_facilities:
|
||||
raise TypeError(_('syslog facility must be one of: %s') %
|
||||
', '.join("'%s'" % fac
|
||||
for fac in valid_facilities))
|
||||
|
||||
return facility
|
||||
return getattr(syslog, facility)
|
||||
|
||||
|
||||
def _setup_logging_from_conf(conf, project, version):
|
||||
|
@ -280,20 +282,13 @@ def _setup_logging_from_conf(conf, project, version):
|
|||
log_root.addHandler(handler)
|
||||
|
||||
if conf.use_syslog:
|
||||
try:
|
||||
facility = _find_facility_from_conf(conf)
|
||||
# TODO(bogdando) use the format provided by RFCSysLogHandler
|
||||
# after existing syslog format deprecation in J
|
||||
if conf.use_syslog_rfc_format:
|
||||
syslog = handlers.RFCSysLogHandler(address='/dev/log',
|
||||
facility=facility)
|
||||
else:
|
||||
syslog = logging.handlers.SysLogHandler(address='/dev/log',
|
||||
facility=facility)
|
||||
log_root.addHandler(syslog)
|
||||
except socket.error:
|
||||
log_root.error('Unable to add syslog handler. Verify that syslog '
|
||||
'is running.')
|
||||
facility = _find_facility(conf.syslog_log_facility)
|
||||
# TODO(bogdando) use the format provided by RFCSysLogHandler after
|
||||
# existing syslog format deprecation in J
|
||||
syslog = handlers.OSSysLogHandler(
|
||||
facility=facility,
|
||||
use_syslog_rfc_format=conf.use_syslog_rfc_format)
|
||||
log_root.addHandler(syslog)
|
||||
|
||||
datefmt = conf.log_date_format
|
||||
for handler in log_root.handlers:
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
import syslog
|
||||
import tempfile
|
||||
|
||||
import mock
|
||||
|
@ -210,6 +211,26 @@ class SysLogHandlersTestCase(BaseTestCase):
|
|||
expected.getMessage())
|
||||
|
||||
|
||||
class OSSysLogHandlerTestCase(BaseTestCase):
|
||||
def tests_handler(self):
|
||||
handler = handlers.OSSysLogHandler()
|
||||
syslog.syslog = mock.Mock()
|
||||
handler.emit(
|
||||
logging.LogRecord("foo", logging.INFO,
|
||||
"path", 123, "hey!",
|
||||
None, None))
|
||||
self.assertTrue(syslog.syslog.called)
|
||||
|
||||
def test_find_facility(self):
|
||||
self.assertEqual(syslog.LOG_USER, log._find_facility("user"))
|
||||
self.assertEqual(syslog.LOG_LPR, log._find_facility("LPR"))
|
||||
self.assertEqual(syslog.LOG_LOCAL3, log._find_facility("log_local3"))
|
||||
self.assertEqual(syslog.LOG_UUCP, log._find_facility("LOG_UUCP"))
|
||||
self.assertRaises(TypeError,
|
||||
log._find_facility,
|
||||
"fougere")
|
||||
|
||||
|
||||
class LogLevelTestCase(BaseTestCase):
|
||||
def setUp(self):
|
||||
super(LogLevelTestCase, self).setUp()
|
||||
|
|
|
@ -11,3 +11,4 @@ oslo.context>=0.2.0,<0.3.0 # Apache-2.0
|
|||
oslo.i18n>=1.5.0,<1.6.0 # Apache-2.0
|
||||
oslo.utils>=1.4.0,<1.5.0 # Apache-2.0
|
||||
oslo.serialization>=1.4.0,<1.5.0 # Apache-2.0
|
||||
debtcollector>=0.3.0,<0.4.0 # Apache-2.0
|
||||
|
|
Loading…
Reference in New Issue