Skip to content
This repository was archived by the owner on Dec 21, 2024. It is now read-only.

Commit af5778d

Browse files
authored
Merge branch 'master' into ensure_ascii
2 parents 29114dc + eebe45e commit af5778d

File tree

9 files changed

+132
-18
lines changed

9 files changed

+132
-18
lines changed

README.markdown

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Usage
2525

2626
## Integrating with Python's logging framework
2727

28-
Json outputs are provided by the JsonFormatter logging formatter. You can add the customer formatter like below:
28+
Json outputs are provided by the JsonFormatter logging formatter. You can add the custom formatter like below:
2929

3030
**Please note: version 0.1.0 has changed the import structure, please update to the following example for proper importing**
3131

@@ -63,7 +63,7 @@ You can also add extra fields to your json output by specifying a dict in place
6363

6464
Contents of these dictionaries will be added at the root level of the entry and may override basic fields.
6565

66-
You can also use the `add_fields` method to add to or generally normalize the set of default set of fields, it is be called for every log event. For example, to unify default fields with those provided by [structlog](http://www.structlog.org/) you could do something like this:
66+
You can also use the `add_fields` method to add to or generally normalize the set of default set of fields, it is called for every log event. For example, to unify default fields with those provided by [structlog](http://www.structlog.org/) you could do something like this:
6767

6868
```python
6969
class CustomJsonFormatter(jsonlogger.JsonFormatter):

debian/changelog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
python3-jsonlogger (0.1.8-1) stable; urgency=medium
2+
3+
* Initial release.
4+
5+
-- Maximilian Wilhelm <max@sdn.clinic> Wed, 07 Feb 2018 22:12:07 +0100

debian/compat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
9

debian/control

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Source: python3-jsonlogger
2+
Section: python
3+
Priority: optional
4+
Maintainer: Maximilian Wilhelm <max@sdn.clinic>
5+
Build-Depends: debhelper (>= 9), dh-python, dh-systemd,
6+
python3-all,
7+
python3-setuptools,
8+
python3-pbr
9+
Standards-Version: 3.9.5
10+
Homepage: https://github.com/madzak/python-json-logger
11+
X-Python3-Version: >= 3.2
12+
13+
Package: python3-jsonlogger
14+
Architecture: all
15+
Depends: ${python3:Depends}, ${misc:Depends}
16+
Description: JSON library for Python logging framework
17+
This library is provided to allow standard python logging to output log data
18+
as json objects. With JSON we can make our logs more readable by machines
19+
and we can stop writing custom parsers for syslog type records.

debian/copyright

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2+
Upstream-Name: python-json-logger
3+
Source: https://github.com/madzak/python-json-logger
4+
5+
Files: *
6+
Copyright: 2011-2018 Zakaria Zajac <madzak42@gmail.com>
7+
License: BSD-2-Clause
8+
9+
Files: debian/*
10+
Copyright: 2018 Maximilian Wilhelm <max@sdn.clinic>
11+
License: BSD-2-Clause
12+
13+
License: BSD-2-Clause
14+
Redistribution and use in source and binary forms, with or without
15+
modification, are permitted provided that the following conditions
16+
are met:
17+
1. Redistributions of source code must retain the above copyright
18+
notice, this list of conditions and the following disclaimer.
19+
2. Redistributions in binary form must reproduce the above copyright
20+
notice, this list of conditions and the following disclaimer in the
21+
documentation and/or other materials provided with the distribution.
22+
.
23+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24+
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HOLDERS OR
27+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

debian/rules

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/make -f
2+
# See debhelper(7) (uncomment to enable)
3+
# output every command that modifies files on the build system.
4+
#DH_VERBOSE = 1
5+
6+
# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/*
7+
DPKG_EXPORT_BUILDFLAGS = 1
8+
include /usr/share/dpkg/default.mk
9+
10+
export PBR_VERSION=0.5.5
11+
12+
# main packaging script based on dh7 syntax
13+
%:
14+
dh $@ --with python3 --buildsystem=pybuild
15+
16+
override_dh_auto_install:
17+
dh_auto_install -O--buildsystem=pybuild

debian/source/format

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.0 (quilt)

setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
'Programming Language :: Python :: 3.2',
3333
'Programming Language :: Python :: 3.3',
3434
'Programming Language :: Python :: 3.4',
35+
'Programming Language :: Python :: 3.5',
36+
'Programming Language :: Python :: 3.6',
3537
'Topic :: System :: Logging',
3638
]
3739
)

src/pythonjsonlogger/jsonlogger.py

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import logging
66
import json
77
import re
8-
import datetime
8+
from datetime import date, datetime, time
99
import traceback
1010

1111
from inspect import istraceback
@@ -24,10 +24,8 @@
2424
'msecs', 'message', 'msg', 'name', 'pathname', 'process',
2525
'processName', 'relativeCreated', 'stack_info', 'thread', 'threadName')
2626

27-
RESERVED_ATTR_HASH = dict(zip(RESERVED_ATTRS, RESERVED_ATTRS))
2827

29-
30-
def merge_record_extra(record, target, reserved=RESERVED_ATTR_HASH):
28+
def merge_record_extra(record, target, reserved):
3129
"""
3230
Merges extra attributes from LogRecord object into target dictionary
3331
@@ -44,6 +42,36 @@ def merge_record_extra(record, target, reserved=RESERVED_ATTR_HASH):
4442
return target
4543

4644

45+
class JsonEncoder(json.JSONEncoder):
46+
"""
47+
A custom encoder extending the default JSONEncoder
48+
"""
49+
def default(self, obj):
50+
if isinstance(obj, (date, datetime, time)):
51+
return self.format_datetime_obj(obj)
52+
53+
elif istraceback(obj):
54+
return ''.join(traceback.format_tb(obj)).strip()
55+
56+
elif type(obj) == Exception \
57+
or isinstance(obj, Exception) \
58+
or type(obj) == type:
59+
return str(obj)
60+
61+
try:
62+
return super(JsonEncoder, self).default(obj)
63+
64+
except TypeError:
65+
try:
66+
return str(obj)
67+
68+
except Exception:
69+
return None
70+
71+
def format_datetime_obj(self, obj):
72+
return obj.isoformat()
73+
74+
4775
class JsonFormatter(logging.Formatter):
4876
"""
4977
A custom formatter to format logging records as json strings.
@@ -58,35 +86,39 @@ def __init__(self, *args, **kwargs):
5886
:param json_encoder: optional custom encoder
5987
:param json_serializer: a :meth:`json.dumps`-compatible callable
6088
that will be used to serialize the log record.
89+
:param json_indent: an optional :meth:`json.dumps`-compatible numeric value
90+
that will be used to customize the indent of the output json.
6191
:param prefix: an optional string prefix added at the beginning of
6292
the formatted string
6393
:param json_indent: indent parameter for json.dumps
6494
:param json_ensure_ascii: ensure_ascii parameter for json.dumps
95+
:param reserved_attrs: an optional list of fields that will be skipped when
96+
outputting json log record. Defaults to all log record attributes:
97+
http://docs.python.org/library/logging.html#logrecord-attributes
98+
:param timestamp: an optional string/boolean field to add a timestamp when
99+
outputting the json log record. If string is passed, timestamp will be added
100+
to log record using string as key. If True boolean is passed, timestamp key
101+
will be "timestamp". Defaults to False/off.
65102
"""
66103
self.json_default = kwargs.pop("json_default", None)
67104
self.json_encoder = kwargs.pop("json_encoder", None)
68105
self.json_serializer = kwargs.pop("json_serializer", json.dumps)
69106
self.json_indent = kwargs.pop("json_indent", None)
70107
self.json_ensure_ascii = kwargs.pop("json_ensure_ascii", True)
71108
self.prefix = kwargs.pop("prefix", "")
109+
reserved_attrs = kwargs.pop("reserved_attrs", RESERVED_ATTRS)
110+
self.reserved_attrs = dict(zip(reserved_attrs, reserved_attrs))
111+
self.timestamp = kwargs.pop("timestamp", False)
112+
72113
#super(JsonFormatter, self).__init__(*args, **kwargs)
73114
logging.Formatter.__init__(self, *args, **kwargs)
74115
if not self.json_encoder and not self.json_default:
75-
def _default_json_handler(obj):
76-
'''Prints dates in ISO format'''
77-
if isinstance(obj, (datetime.date, datetime.time)):
78-
return obj.isoformat()
79-
elif istraceback(obj):
80-
tb = ''.join(traceback.format_tb(obj))
81-
return tb.strip()
82-
elif isinstance(obj, Exception):
83-
return "Exception: %s" % str(obj)
84-
return str(obj)
85-
self.json_default = _default_json_handler
116+
self.json_encoder = JsonEncoder
117+
86118
self._required_fields = self.parse()
87119
self._skip_fields = dict(zip(self._required_fields,
88120
self._required_fields))
89-
self._skip_fields.update(RESERVED_ATTR_HASH)
121+
self._skip_fields.update(self.reserved_attrs)
90122

91123
def parse(self):
92124
"""
@@ -107,6 +139,10 @@ def add_fields(self, log_record, record, message_dict):
107139
log_record.update(message_dict)
108140
merge_record_extra(record, log_record, reserved=self._skip_fields)
109141

142+
if self.timestamp:
143+
key = self.timestamp if type(self.timestamp) == str else 'timestamp'
144+
log_record[key] = datetime.utcnow()
145+
110146
def process_log_record(self, log_record):
111147
"""
112148
Override this method to implement custom logic

0 commit comments

Comments
 (0)