Skip to content

Commit

Permalink
Merge 1b1d20d into 436f008
Browse files Browse the repository at this point in the history
  • Loading branch information
Behoston committed Jan 18, 2019
2 parents 436f008 + 1b1d20d commit 5f3c690
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.rst
Expand Up @@ -209,6 +209,7 @@ module.
})
l.info('{"from": "userC", "to": "userD"}')
l.info("This log entry will be logged with the additional key: 'message'.")
l.info("This log entry will be enriched with extra data.", extra={'user_id': 1})
You can also customize formatter via logging.config.dictConfig

Expand Down
32 changes: 32 additions & 0 deletions fluent/handler.py
Expand Up @@ -77,6 +77,7 @@ def __init__(self, fmt=None, datefmt=None, style='%', fill_missing_fmt_key=False
else:
if hasattr(fmt, "__call__"):
self._formatter = fmt
self._fmt_dict = None
self.usesTime = fmt.usesTime
else:
self._fmt_dict = fmt
Expand All @@ -101,9 +102,40 @@ def format(self, record):
# Apply format
data = self._formatter(record)

# Add extra data
extra = self._get_extra_fields(record)
if extra:
data['extra'] = extra

self._structuring(data, record)
return data

def _get_extra_fields(self, record):
"""
Method based on:
https://github.com/vklochan/python-logstash/blob/master/logstash/formatter.py#L23
"""
# The list contains all the attributes listed in
# http://docs.python.org/library/logging.html#logrecord-attributes
skip_list = (
'args', 'asctime', 'created', 'exc_info', 'exc_text', 'filename',
'funcName', 'id', 'levelname', 'levelno', 'lineno', 'module',
'msecs', 'msecs', 'message', 'msg', 'name', 'pathname', 'process',
'processName', 'relativeCreated', 'stack_info', 'thread', 'threadName',
'extra', 'auth_token', 'password', 'hostname', )

easy_types = (str, bool, dict, float, int, list, type(None))

fields = {}
fmt_dict = self._fmt_dict or {}
for key, value in record.__dict__.items():
if key not in skip_list and key not in fmt_dict:
if isinstance(value, easy_types):
fields[key] = value
else:
fields[key] = repr(value)
return fields

def usesTime(self):
"""This method is substituted on construction based on settings for performance reasons"""

Expand Down
16 changes: 16 additions & 0 deletions tests/test_handler.py
Expand Up @@ -371,3 +371,19 @@ def test_exception_message(self):
self.assertTrue('it failed' in message)
self.assertTrue('tests/test_handler.py", line' in message)
self.assertTrue('Exception: sample exception' in message)

def test_extra_data(self):
handler = fluent.handler.FluentHandler('app.follow', port=self._port)

with handler:
logging.basicConfig(level=logging.INFO)
log = logging.getLogger('fluent.test')
handler.setFormatter(fluent.handler.FluentRecordFormatter())
log.addHandler(handler)
log.info("Sample log massage", extra={'user_id': 1})
log.removeHandler(handler)

data = self.get_data()
eq = self.assertEqual
eq("Sample log massage", data[0][2]['message'])
eq({'user_id': 1}, data[0][2]['extra'])

0 comments on commit 5f3c690

Please sign in to comment.