The user_identity format flexibility
This patch-set add a new config string option for user_identity format. Default of "logging_context_format_string" format is followings, '%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' '%(name)s [%(request_id)s %(user_identity)s] ' '%(instance)s%(message)s', which is defined in oslo_log/_option.py, or config file. And default of "%(user_identity)s" field format is followings, user_idt_format = '{user} {tenant} {domain} {user_domain} {p_domain}' which is defined in oslo_context/context.py So, adding new config string option for user_identity format, we are able to control the user_identity format. For example, add following line to config file. logging_user_identity_format = U:%(user)s T:%(tenant)s Change-Id: I249ef7a8d144a4d5a34c3f80113f96fa4730ce28 Implements: blueprint user-identity-format-flexibility
This commit is contained in:
parent
8ab7644d57
commit
674dab4012
|
@ -132,6 +132,11 @@ log_opts = [
|
||||||
default='[instance: %(uuid)s] ',
|
default='[instance: %(uuid)s] ',
|
||||||
help='The format for an instance UUID that is passed with the '
|
help='The format for an instance UUID that is passed with the '
|
||||||
'log message.'),
|
'log message.'),
|
||||||
|
cfg.StrOpt('logging_user_identity_format',
|
||||||
|
default='%(user)s %(tenant)s '
|
||||||
|
'%(domain)s %(user_domain)s %(project_domain)s',
|
||||||
|
help='Format string for user_identity field of '
|
||||||
|
'the logging_context_format_string'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,11 @@ def _update_record_with_context(record):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class _ReplaceFalseValue(dict):
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return dict.get(self, key, None) or '-'
|
||||||
|
|
||||||
|
|
||||||
class JSONFormatter(logging.Formatter):
|
class JSONFormatter(logging.Formatter):
|
||||||
def __init__(self, fmt=None, datefmt=None):
|
def __init__(self, fmt=None, datefmt=None):
|
||||||
# NOTE(jkoelker) we ignore the fmt argument, but its still there
|
# NOTE(jkoelker) we ignore the fmt argument, but its still there
|
||||||
|
@ -216,6 +221,15 @@ class ContextFormatter(logging.Formatter):
|
||||||
if key not in record.__dict__:
|
if key not in record.__dict__:
|
||||||
record.__dict__[key] = ''
|
record.__dict__[key] = ''
|
||||||
|
|
||||||
|
# Set the "user_identity" value of "logging_context_format_string"
|
||||||
|
# by using "logging_user_identity_format" and
|
||||||
|
# "to_dict()" of oslo.context.
|
||||||
|
if context:
|
||||||
|
record.user_identity = (
|
||||||
|
self.conf.logging_user_identity_format %
|
||||||
|
_ReplaceFalseValue(context.__dict__)
|
||||||
|
)
|
||||||
|
|
||||||
if record.__dict__.get('request_id'):
|
if record.__dict__.get('request_id'):
|
||||||
fmt = self.conf.logging_context_format_string
|
fmt = self.conf.logging_context_format_string
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -41,7 +41,14 @@ from oslo_log import log
|
||||||
|
|
||||||
|
|
||||||
def _fake_context():
|
def _fake_context():
|
||||||
return context.RequestContext(1, 1, overwrite=True)
|
ctxt = context.RequestContext(1, 1, overwrite=True)
|
||||||
|
ctxt.user = 'myuser'
|
||||||
|
ctxt.tenant = 'mytenant'
|
||||||
|
ctxt.domain = 'mydomain'
|
||||||
|
ctxt.project_domain = 'myprojectdomain'
|
||||||
|
ctxt.user_domain = 'myuserdomain'
|
||||||
|
|
||||||
|
return ctxt
|
||||||
|
|
||||||
|
|
||||||
class CommonLoggerTestsMixIn(object):
|
class CommonLoggerTestsMixIn(object):
|
||||||
|
@ -422,6 +429,37 @@ class ContextFormatterTestCase(LogTestBase):
|
||||||
message)
|
message)
|
||||||
self.assertEqual(expected, self.stream.getvalue())
|
self.assertEqual(expected, self.stream.getvalue())
|
||||||
|
|
||||||
|
def test_user_identity_logging(self):
|
||||||
|
self.config(logging_context_format_string="HAS CONTEXT "
|
||||||
|
"[%(request_id)s "
|
||||||
|
"%(user_identity)s]: "
|
||||||
|
"%(message)s")
|
||||||
|
ctxt = _fake_context()
|
||||||
|
ctxt.request_id = u'99'
|
||||||
|
message = 'test'
|
||||||
|
self.log.info(message, context=ctxt)
|
||||||
|
expected = ("HAS CONTEXT [%s %s %s %s %s %s]: %s\n" %
|
||||||
|
(ctxt.request_id, ctxt.user, ctxt.tenant, ctxt.domain,
|
||||||
|
ctxt.user_domain, ctxt.project_domain,
|
||||||
|
six.text_type(message)))
|
||||||
|
self.assertEqual(expected, self.stream.getvalue())
|
||||||
|
|
||||||
|
def test_user_identity_logging_set_format(self):
|
||||||
|
self.config(logging_context_format_string="HAS CONTEXT "
|
||||||
|
"[%(request_id)s "
|
||||||
|
"%(user_identity)s]: "
|
||||||
|
"%(message)s",
|
||||||
|
logging_user_identity_format="%(user)s "
|
||||||
|
"%(tenant)s")
|
||||||
|
ctxt = _fake_context()
|
||||||
|
ctxt.request_id = u'99'
|
||||||
|
message = 'test'
|
||||||
|
self.log.info(message, context=ctxt)
|
||||||
|
expected = ("HAS CONTEXT [%s %s %s]: %s\n" %
|
||||||
|
(ctxt.request_id, ctxt.user, ctxt.tenant,
|
||||||
|
six.text_type(message)))
|
||||||
|
self.assertEqual(expected, self.stream.getvalue())
|
||||||
|
|
||||||
|
|
||||||
class ExceptionLoggingTestCase(LogTestBase):
|
class ExceptionLoggingTestCase(LogTestBase):
|
||||||
"""Test that Exceptions are logged."""
|
"""Test that Exceptions are logged."""
|
||||||
|
@ -592,9 +630,6 @@ class DomainTestCase(LogTestBase):
|
||||||
|
|
||||||
def test_domain_in_log_msg(self):
|
def test_domain_in_log_msg(self):
|
||||||
ctxt = _fake_context()
|
ctxt = _fake_context()
|
||||||
ctxt.domain = 'mydomain'
|
|
||||||
ctxt.project_domain = 'myprojectdomain'
|
|
||||||
ctxt.user_domain = 'myuserdomain'
|
|
||||||
user_identity = ctxt.to_dict()['user_identity']
|
user_identity = ctxt.to_dict()['user_identity']
|
||||||
self.assertTrue(ctxt.domain in user_identity)
|
self.assertTrue(ctxt.domain in user_identity)
|
||||||
self.assertTrue(ctxt.project_domain in user_identity)
|
self.assertTrue(ctxt.project_domain in user_identity)
|
||||||
|
|
Loading…
Reference in New Issue