Skip to content

Commit 7e269a4

Browse files
JSON Formatter added
1 parent 6b64ee7 commit 7e269a4

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed

redis_json_logger/__init__.py

Whitespace-only changes.

redis_json_logger/formatter.py

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import json
2+
import traceback as tb
3+
from logging import Formatter
4+
from .functions import get_current_time_iso
5+
6+
7+
class JSONFormatter(Formatter):
8+
required_fields = '__all__'
9+
exclude_fields = None
10+
default_datetime_format = '%Y-%m-%d %H:%M:%S'
11+
12+
def __init__(self, required_fields=None, exclude_fields=None, datefmt=None):
13+
if required_fields:
14+
self.required_fields = required_fields
15+
16+
if exclude_fields:
17+
self.exclude_fields = exclude_fields
18+
19+
if not datefmt:
20+
self.datefmt = self.default_datetime_format
21+
else:
22+
self.datefmt = datefmt
23+
24+
def validate_field(self):
25+
assert not (self.required_fields and self.exclude_fields), ("Cannot set both 'required_fields' and 'exclude_fields' options",)
26+
27+
def usesTime(self):
28+
"""
29+
Check if the format uses the creation time of the record.
30+
"""
31+
if self.required_fields == '__all__':
32+
return True
33+
else:
34+
return 'asctime' in self.required_fields
35+
36+
def formatMessage(self, record):
37+
return record.__dict__.copy()
38+
39+
def format(self, record):
40+
"""
41+
Format the specified record as text.
42+
43+
The record's attribute dictionary is used as the operand to a
44+
string formatting operation which yields the returned string.
45+
Before formatting the dictionary, a couple of preparatory steps
46+
are carried out. The message attribute of the record is computed
47+
using LogRecord.getMessage(). If the formatting string uses the
48+
time (as determined by a call to usesTime(), formatTime() is
49+
called to format the event time. If there is exception information,
50+
it is formatted using formatException() and appended to the message.
51+
"""
52+
record.message = record.getMessage()
53+
if self.usesTime():
54+
record.asctime = self.formatTime(record, self.datefmt)
55+
log_dict = self.formatMessage(record)
56+
if record.exc_info:
57+
# Cache the traceback text to avoid converting it multiple times
58+
# (it's constant anyway)
59+
if not record.exc_text:
60+
record.exc_text = self.formatException(record.exc_info)
61+
if record.exc_text:
62+
log_dict['exc_text'] = record.exc_text
63+
if record.stack_info:
64+
log_dict['stack_info'] = self.formatStack(record.stack_info)
65+
json_string = self.convert_to_json_string(log_dict)
66+
return json_string
67+
68+
def formatException(self, ei):
69+
return tb.format_exception(*ei)
70+
71+
def get_required_fields(self):
72+
return self.required_fields
73+
74+
def get_exclude_fields(self):
75+
return self.exclude_fields
76+
77+
def optimize_required_log_fields(self, log_dict, fields):
78+
return {field: log_dict.get(field, '') for field in fields}
79+
80+
def optimize_exclude_log_fields(self, log_dict, fields):
81+
for field in fields:
82+
log_dict.pop(field, None)
83+
return log_dict
84+
85+
def optimize_log_fields(self, python_log_dict):
86+
required_fields = self.get_required_fields()
87+
if required_fields:
88+
if required_fields == '__all__':
89+
return python_log_dict
90+
else:
91+
return self.optimize_required_log_fields(python_log_dict, required_fields)
92+
else:
93+
exclude_fields = self.get_exclude_fields()
94+
if exclude_fields is None:
95+
return python_log_dict
96+
else:
97+
return self.optimize_exclude_log_fields(python_log_dict, required_fields)
98+
99+
def convert_to_json_string(self, log_dict):
100+
optimized_log_dict = self.optimize_log_fields(log_dict)
101+
return json.dumps(optimized_log_dict)
102+
103+
104+
class LogStashJSONFormatter(JSONFormatter):
105+
default_datetime_format = '%Y-%m-%dT%H:%M:%S'
106+
107+
def usesTime(self):
108+
return True
109+
110+
def optimize_log_fields(self, python_log_dict):
111+
python_log_dict = super().optimize_log_fields(python_log_dict)
112+
timestamp = python_log_dict.pop('asctime') if 'asctime' in python_log_dict else get_current_time_iso(self.default_datetime_format)
113+
python_log_dict['@timestamp'] = timestamp
114+
return python_log_dict

redis_json_logger/functions.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from datetime import datetime
2+
3+
4+
def get_current_time_iso(fmt):
5+
return datetime.now().strftime(fmt)

0 commit comments

Comments
 (0)