python-json-logger 2.0.7__tar.gz → 3.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/LICENSE +1 -1
- {python-json-logger-2.0.7/src/python_json_logger.egg-info → python-json-logger-3.0.0}/PKG-INFO +61 -37
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/README.md +43 -26
- python-json-logger-3.0.0/pyproject.toml +75 -0
- {python-json-logger-2.0.7 → python-json-logger-3.0.0/src/python_json_logger.egg-info}/PKG-INFO +61 -37
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/src/python_json_logger.egg-info/SOURCES.txt +2 -1
- python-json-logger-3.0.0/src/python_json_logger.egg-info/requires.txt +9 -0
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/src/pythonjsonlogger/jsonlogger.py +132 -74
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/tests/test_jsonlogger.py +76 -84
- python-json-logger-2.0.7/setup.py +0 -41
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/MANIFEST.in +0 -0
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/setup.cfg +0 -0
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/src/python_json_logger.egg-info/dependency_links.txt +0 -0
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/src/python_json_logger.egg-info/top_level.txt +0 -0
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/src/pythonjsonlogger/__init__.py +0 -0
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/src/pythonjsonlogger/py.typed +0 -0
- {python-json-logger-2.0.7 → python-json-logger-3.0.0}/tests/__init__.py +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c) 2011, Zakaria Zajac
|
|
1
|
+
Copyright (c) 2011, Zakaria Zajac and the python-json-logger Contributors
|
|
2
2
|
All rights reserved.
|
|
3
3
|
|
|
4
4
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
{python-json-logger-2.0.7/src/python_json_logger.egg-info → python-json-logger-3.0.0}/PKG-INFO
RENAMED
|
@@ -1,58 +1,78 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-json-logger
|
|
3
|
-
Version:
|
|
4
|
-
Summary:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: JSON Log Formatter for the Python Logging Package
|
|
5
|
+
Author-email: Zakaria Zajac <zak@madzak.com>
|
|
6
|
+
Maintainer-email: Nicholas Hairs <info+python-json-logger@nicholashairs.com>
|
|
7
|
+
License: BSD-2-Clause License
|
|
8
|
+
Project-URL: GitHub, https://github.com/nhairs/python-json-logger
|
|
9
9
|
Classifier: Development Status :: 6 - Mature
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: License :: OSI Approved :: BSD License
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
|
-
Classifier: Programming Language :: Python
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.7
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.8
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.9
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
20
|
Classifier: Topic :: System :: Logging
|
|
22
|
-
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.7
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
Provides-Extra: lint
|
|
26
|
+
Requires-Dist: validate-pyproject[all]; extra == "lint"
|
|
27
|
+
Requires-Dist: black; extra == "lint"
|
|
28
|
+
Requires-Dist: pylint; extra == "lint"
|
|
29
|
+
Requires-Dist: mypy; extra == "lint"
|
|
30
|
+
Provides-Extra: test
|
|
31
|
+
Requires-Dist: pytest; extra == "test"
|
|
32
|
+
|
|
33
|
+

|
|
27
34
|
[](https://pypi.python.org/pypi/python-json-logger/)
|
|
28
35
|
[](https://pypi.python.org/pypi/python-json-logger/)
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
# Python JSON Logger
|
|
38
|
+
|
|
32
39
|
This library is provided to allow standard python logging to output log data as json objects. With JSON we can make our logs more readable by machines and we can stop writing custom parsers for syslog type records.
|
|
33
40
|
|
|
34
|
-
News
|
|
35
|
-
=======
|
|
36
|
-
Hi, I see this package is quiet alive and I am sorry for ignoring it so long. I will be stepping up my maintenance of this package so please allow me a week to get things back in order (and most likely a new minor version) and I'll post and update here once I am caught up.
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
### 🚨 Important 🚨
|
|
43
|
+
|
|
44
|
+
This repository is a maintained fork of [madzak/python-json-logger](https://github.com/madzak/python-json-logger) pending [a PEP 541 request](https://github.com/pypi/support/issues/3607) for the PyPI package. The future direction of the project is being discussed [here](https://github.com/nhairs/python-json-logger/issues/1).
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
### Install via pip / PyPI
|
|
49
|
+
|
|
50
|
+
Until the PEP 541 request is complete you will need to use one of the alternative methods below.
|
|
51
|
+
|
|
52
|
+
### Install from GitHub
|
|
41
53
|
|
|
42
|
-
|
|
54
|
+
```shell
|
|
55
|
+
pip install 'python-json-logger@git+https://github.com/nhairs/python-json-logger.git'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
To install a specific version:
|
|
43
59
|
|
|
44
|
-
|
|
60
|
+
```shell
|
|
61
|
+
pip install 'python-json-logger@git+https://github.com/nhairs/python-json-logger.git@v2.0.7'
|
|
62
|
+
```
|
|
45
63
|
|
|
46
|
-
https://pypi.python.org/pypi/python-json-logger
|
|
47
64
|
|
|
48
|
-
|
|
65
|
+
### Install from Source
|
|
49
66
|
|
|
50
|
-
|
|
67
|
+
```shell
|
|
68
|
+
git clone https://github.com/nhairs/python-json-logger.git
|
|
69
|
+
cd python-json-logger
|
|
70
|
+
pip install -e .
|
|
71
|
+
```
|
|
51
72
|
|
|
52
|
-
Usage
|
|
53
|
-
=====
|
|
73
|
+
## Usage
|
|
54
74
|
|
|
55
|
-
|
|
75
|
+
### Integrating with Python's logging framework
|
|
56
76
|
|
|
57
77
|
Json outputs are provided by the JsonFormatter logging formatter. You can add the custom formatter like below:
|
|
58
78
|
|
|
@@ -70,7 +90,7 @@ Json outputs are provided by the JsonFormatter logging formatter. You can add th
|
|
|
70
90
|
logger.addHandler(logHandler)
|
|
71
91
|
```
|
|
72
92
|
|
|
73
|
-
|
|
93
|
+
### Customizing fields
|
|
74
94
|
|
|
75
95
|
The fmt parser can also be overidden if you want to have required fields that differ from the default of just `message`.
|
|
76
96
|
|
|
@@ -112,7 +132,7 @@ formatter = CustomJsonFormatter('%(timestamp)s %(level)s %(name)s %(message)s')
|
|
|
112
132
|
|
|
113
133
|
Items added to the log record will be included in *every* log message, no matter what the format requires.
|
|
114
134
|
|
|
115
|
-
|
|
135
|
+
### Adding custom object serialization
|
|
116
136
|
|
|
117
137
|
For custom handling of object serialization you can specify default json object translator or provide a custom encoder
|
|
118
138
|
|
|
@@ -129,7 +149,7 @@ logger.info({"special": "value", "run": 12})
|
|
|
129
149
|
logger.info("classic message", extra={"special": "value", "run": 12})
|
|
130
150
|
```
|
|
131
151
|
|
|
132
|
-
|
|
152
|
+
### Using a Config File
|
|
133
153
|
|
|
134
154
|
To use the module with a config file using the [`fileConfig` function](https://docs.python.org/3/library/logging.config.html#logging.config.fileConfig), use the class `pythonjsonlogger.jsonlogger.JsonFormatter`. Here is a sample config file.
|
|
135
155
|
|
|
@@ -162,8 +182,7 @@ format = %(message)s
|
|
|
162
182
|
class = pythonjsonlogger.jsonlogger.JsonFormatter
|
|
163
183
|
```
|
|
164
184
|
|
|
165
|
-
Example Output
|
|
166
|
-
==============
|
|
185
|
+
## Example Output
|
|
167
186
|
|
|
168
187
|
Sample JSON with a full formatter (basically the log message from the unit test). Every log message will appear on 1 line like a typical logger.
|
|
169
188
|
|
|
@@ -191,9 +210,14 @@ Sample JSON with a full formatter (basically the log message from the unit test)
|
|
|
191
210
|
}
|
|
192
211
|
```
|
|
193
212
|
|
|
194
|
-
|
|
195
|
-
|
|
213
|
+
## License
|
|
214
|
+
|
|
215
|
+
This project is licensed under the BSD 2 Clause License - see [`LICENSE`](https://github.com/nhairs/python-json-logger/blob/main/LICENSE)
|
|
216
|
+
|
|
217
|
+
## Authors and Maintainers
|
|
218
|
+
|
|
219
|
+
This project was originally authored by [Zakaria Zajac](https://github.com/madzak) and our wonderful [contributors](https://github.com/nhairs/python-json-logger/graphs/contributors)
|
|
196
220
|
|
|
197
|
-
|
|
221
|
+
It is currently maintained by:
|
|
198
222
|
|
|
199
|
-
- [
|
|
223
|
+
- [Nicholas Hairs](https://github.com/nhairs) - [nicholashairs.com](https://www.nicholashairs.com)
|
|
@@ -1,33 +1,46 @@
|
|
|
1
|
-

|
|
2
2
|
[](https://pypi.python.org/pypi/python-json-logger/)
|
|
3
3
|
[](https://pypi.python.org/pypi/python-json-logger/)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
# Python JSON Logger
|
|
6
|
+
|
|
7
7
|
This library is provided to allow standard python logging to output log data as json objects. With JSON we can make our logs more readable by machines and we can stop writing custom parsers for syslog type records.
|
|
8
8
|
|
|
9
|
-
News
|
|
10
|
-
=======
|
|
11
|
-
Hi, I see this package is quiet alive and I am sorry for ignoring it so long. I will be stepping up my maintenance of this package so please allow me a week to get things back in order (and most likely a new minor version) and I'll post and update here once I am caught up.
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
### 🚨 Important 🚨
|
|
11
|
+
|
|
12
|
+
This repository is a maintained fork of [madzak/python-json-logger](https://github.com/madzak/python-json-logger) pending [a PEP 541 request](https://github.com/pypi/support/issues/3607) for the PyPI package. The future direction of the project is being discussed [here](https://github.com/nhairs/python-json-logger/issues/1).
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
## Installation
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
### Install via pip / PyPI
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
Until the PEP 541 request is complete you will need to use one of the alternative methods below.
|
|
22
19
|
|
|
23
|
-
|
|
20
|
+
### Install from GitHub
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
```shell
|
|
23
|
+
pip install 'python-json-logger@git+https://github.com/nhairs/python-json-logger.git'
|
|
24
|
+
```
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
=====
|
|
26
|
+
To install a specific version:
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
```shell
|
|
29
|
+
pip install 'python-json-logger@git+https://github.com/nhairs/python-json-logger.git@v2.0.7'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Install from Source
|
|
34
|
+
|
|
35
|
+
```shell
|
|
36
|
+
git clone https://github.com/nhairs/python-json-logger.git
|
|
37
|
+
cd python-json-logger
|
|
38
|
+
pip install -e .
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### Integrating with Python's logging framework
|
|
31
44
|
|
|
32
45
|
Json outputs are provided by the JsonFormatter logging formatter. You can add the custom formatter like below:
|
|
33
46
|
|
|
@@ -45,7 +58,7 @@ Json outputs are provided by the JsonFormatter logging formatter. You can add th
|
|
|
45
58
|
logger.addHandler(logHandler)
|
|
46
59
|
```
|
|
47
60
|
|
|
48
|
-
|
|
61
|
+
### Customizing fields
|
|
49
62
|
|
|
50
63
|
The fmt parser can also be overidden if you want to have required fields that differ from the default of just `message`.
|
|
51
64
|
|
|
@@ -87,7 +100,7 @@ formatter = CustomJsonFormatter('%(timestamp)s %(level)s %(name)s %(message)s')
|
|
|
87
100
|
|
|
88
101
|
Items added to the log record will be included in *every* log message, no matter what the format requires.
|
|
89
102
|
|
|
90
|
-
|
|
103
|
+
### Adding custom object serialization
|
|
91
104
|
|
|
92
105
|
For custom handling of object serialization you can specify default json object translator or provide a custom encoder
|
|
93
106
|
|
|
@@ -104,7 +117,7 @@ logger.info({"special": "value", "run": 12})
|
|
|
104
117
|
logger.info("classic message", extra={"special": "value", "run": 12})
|
|
105
118
|
```
|
|
106
119
|
|
|
107
|
-
|
|
120
|
+
### Using a Config File
|
|
108
121
|
|
|
109
122
|
To use the module with a config file using the [`fileConfig` function](https://docs.python.org/3/library/logging.config.html#logging.config.fileConfig), use the class `pythonjsonlogger.jsonlogger.JsonFormatter`. Here is a sample config file.
|
|
110
123
|
|
|
@@ -137,8 +150,7 @@ format = %(message)s
|
|
|
137
150
|
class = pythonjsonlogger.jsonlogger.JsonFormatter
|
|
138
151
|
```
|
|
139
152
|
|
|
140
|
-
Example Output
|
|
141
|
-
==============
|
|
153
|
+
## Example Output
|
|
142
154
|
|
|
143
155
|
Sample JSON with a full formatter (basically the log message from the unit test). Every log message will appear on 1 line like a typical logger.
|
|
144
156
|
|
|
@@ -166,9 +178,14 @@ Sample JSON with a full formatter (basically the log message from the unit test)
|
|
|
166
178
|
}
|
|
167
179
|
```
|
|
168
180
|
|
|
169
|
-
|
|
170
|
-
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
This project is licensed under the BSD 2 Clause License - see [`LICENSE`](https://github.com/nhairs/python-json-logger/blob/main/LICENSE)
|
|
184
|
+
|
|
185
|
+
## Authors and Maintainers
|
|
186
|
+
|
|
187
|
+
This project was originally authored by [Zakaria Zajac](https://github.com/madzak) and our wonderful [contributors](https://github.com/nhairs/python-json-logger/graphs/contributors)
|
|
171
188
|
|
|
172
|
-
|
|
189
|
+
It is currently maintained by:
|
|
173
190
|
|
|
174
|
-
- [
|
|
191
|
+
- [Nicholas Hairs](https://github.com/nhairs) - [nicholashairs.com](https://www.nicholashairs.com)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "python-json-logger"
|
|
7
|
+
version = "3.0.0"
|
|
8
|
+
description = "JSON Log Formatter for the Python Logging Package"
|
|
9
|
+
authors = [
|
|
10
|
+
{name = "Zakaria Zajac", email = "zak@madzak.com"},
|
|
11
|
+
]
|
|
12
|
+
maintainers = [
|
|
13
|
+
{name = "Nicholas Hairs", email = "info+python-json-logger@nicholashairs.com"},
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
# Dependency Information
|
|
17
|
+
requires-python = ">=3.7"
|
|
18
|
+
# dependencies = []
|
|
19
|
+
|
|
20
|
+
# Extra information
|
|
21
|
+
readme = "README.md"
|
|
22
|
+
license = {text = "BSD-2-Clause License"}
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 6 - Mature",
|
|
25
|
+
"Intended Audience :: Developers",
|
|
26
|
+
"License :: OSI Approved :: BSD License",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
29
|
+
"Programming Language :: Python :: 3.7",
|
|
30
|
+
"Programming Language :: Python :: 3.8",
|
|
31
|
+
"Programming Language :: Python :: 3.9",
|
|
32
|
+
"Programming Language :: Python :: 3.10",
|
|
33
|
+
"Programming Language :: Python :: 3.11",
|
|
34
|
+
"Programming Language :: Python :: 3.12",
|
|
35
|
+
"Topic :: System :: Logging",
|
|
36
|
+
"Typing :: Typed",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
# homepage = "https://nhairs.github.io/python-json-logger/latest/"
|
|
41
|
+
GitHub = "https://github.com/nhairs/python-json-logger"
|
|
42
|
+
|
|
43
|
+
[project.optional-dependencies]
|
|
44
|
+
lint = [
|
|
45
|
+
"validate-pyproject[all]",
|
|
46
|
+
"black",
|
|
47
|
+
"pylint",
|
|
48
|
+
"mypy",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
test = [
|
|
52
|
+
"pytest",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
#docs = [
|
|
56
|
+
# "black",
|
|
57
|
+
# "mkdocs",
|
|
58
|
+
# "mkdocs-material>=8.5",
|
|
59
|
+
# "mkdocs-awesome-pages-plugin",
|
|
60
|
+
# "mdx_truly_sane_lists",
|
|
61
|
+
# "mkdocstrings[python]",
|
|
62
|
+
# "mkdocs-gen-files",
|
|
63
|
+
# "mkdocs-literate-nav",
|
|
64
|
+
# "mike",
|
|
65
|
+
#]
|
|
66
|
+
|
|
67
|
+
[tool.setuptools.packages.find]
|
|
68
|
+
where = ["src"]
|
|
69
|
+
include = ["pythonjsonlogger*"]
|
|
70
|
+
|
|
71
|
+
[tool.setuptools.package-data]
|
|
72
|
+
pythonjsonlogger = ["py.typed"]
|
|
73
|
+
|
|
74
|
+
[tool.black]
|
|
75
|
+
line-length = 100
|
{python-json-logger-2.0.7 → python-json-logger-3.0.0/src/python_json_logger.egg-info}/PKG-INFO
RENAMED
|
@@ -1,58 +1,78 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-json-logger
|
|
3
|
-
Version:
|
|
4
|
-
Summary:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: JSON Log Formatter for the Python Logging Package
|
|
5
|
+
Author-email: Zakaria Zajac <zak@madzak.com>
|
|
6
|
+
Maintainer-email: Nicholas Hairs <info+python-json-logger@nicholashairs.com>
|
|
7
|
+
License: BSD-2-Clause License
|
|
8
|
+
Project-URL: GitHub, https://github.com/nhairs/python-json-logger
|
|
9
9
|
Classifier: Development Status :: 6 - Mature
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: License :: OSI Approved :: BSD License
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
|
-
Classifier: Programming Language :: Python
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.7
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.8
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.9
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
20
|
Classifier: Topic :: System :: Logging
|
|
22
|
-
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.7
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
Provides-Extra: lint
|
|
26
|
+
Requires-Dist: validate-pyproject[all]; extra == "lint"
|
|
27
|
+
Requires-Dist: black; extra == "lint"
|
|
28
|
+
Requires-Dist: pylint; extra == "lint"
|
|
29
|
+
Requires-Dist: mypy; extra == "lint"
|
|
30
|
+
Provides-Extra: test
|
|
31
|
+
Requires-Dist: pytest; extra == "test"
|
|
32
|
+
|
|
33
|
+

|
|
27
34
|
[](https://pypi.python.org/pypi/python-json-logger/)
|
|
28
35
|
[](https://pypi.python.org/pypi/python-json-logger/)
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
# Python JSON Logger
|
|
38
|
+
|
|
32
39
|
This library is provided to allow standard python logging to output log data as json objects. With JSON we can make our logs more readable by machines and we can stop writing custom parsers for syslog type records.
|
|
33
40
|
|
|
34
|
-
News
|
|
35
|
-
=======
|
|
36
|
-
Hi, I see this package is quiet alive and I am sorry for ignoring it so long. I will be stepping up my maintenance of this package so please allow me a week to get things back in order (and most likely a new minor version) and I'll post and update here once I am caught up.
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
### 🚨 Important 🚨
|
|
43
|
+
|
|
44
|
+
This repository is a maintained fork of [madzak/python-json-logger](https://github.com/madzak/python-json-logger) pending [a PEP 541 request](https://github.com/pypi/support/issues/3607) for the PyPI package. The future direction of the project is being discussed [here](https://github.com/nhairs/python-json-logger/issues/1).
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
### Install via pip / PyPI
|
|
49
|
+
|
|
50
|
+
Until the PEP 541 request is complete you will need to use one of the alternative methods below.
|
|
51
|
+
|
|
52
|
+
### Install from GitHub
|
|
41
53
|
|
|
42
|
-
|
|
54
|
+
```shell
|
|
55
|
+
pip install 'python-json-logger@git+https://github.com/nhairs/python-json-logger.git'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
To install a specific version:
|
|
43
59
|
|
|
44
|
-
|
|
60
|
+
```shell
|
|
61
|
+
pip install 'python-json-logger@git+https://github.com/nhairs/python-json-logger.git@v2.0.7'
|
|
62
|
+
```
|
|
45
63
|
|
|
46
|
-
https://pypi.python.org/pypi/python-json-logger
|
|
47
64
|
|
|
48
|
-
|
|
65
|
+
### Install from Source
|
|
49
66
|
|
|
50
|
-
|
|
67
|
+
```shell
|
|
68
|
+
git clone https://github.com/nhairs/python-json-logger.git
|
|
69
|
+
cd python-json-logger
|
|
70
|
+
pip install -e .
|
|
71
|
+
```
|
|
51
72
|
|
|
52
|
-
Usage
|
|
53
|
-
=====
|
|
73
|
+
## Usage
|
|
54
74
|
|
|
55
|
-
|
|
75
|
+
### Integrating with Python's logging framework
|
|
56
76
|
|
|
57
77
|
Json outputs are provided by the JsonFormatter logging formatter. You can add the custom formatter like below:
|
|
58
78
|
|
|
@@ -70,7 +90,7 @@ Json outputs are provided by the JsonFormatter logging formatter. You can add th
|
|
|
70
90
|
logger.addHandler(logHandler)
|
|
71
91
|
```
|
|
72
92
|
|
|
73
|
-
|
|
93
|
+
### Customizing fields
|
|
74
94
|
|
|
75
95
|
The fmt parser can also be overidden if you want to have required fields that differ from the default of just `message`.
|
|
76
96
|
|
|
@@ -112,7 +132,7 @@ formatter = CustomJsonFormatter('%(timestamp)s %(level)s %(name)s %(message)s')
|
|
|
112
132
|
|
|
113
133
|
Items added to the log record will be included in *every* log message, no matter what the format requires.
|
|
114
134
|
|
|
115
|
-
|
|
135
|
+
### Adding custom object serialization
|
|
116
136
|
|
|
117
137
|
For custom handling of object serialization you can specify default json object translator or provide a custom encoder
|
|
118
138
|
|
|
@@ -129,7 +149,7 @@ logger.info({"special": "value", "run": 12})
|
|
|
129
149
|
logger.info("classic message", extra={"special": "value", "run": 12})
|
|
130
150
|
```
|
|
131
151
|
|
|
132
|
-
|
|
152
|
+
### Using a Config File
|
|
133
153
|
|
|
134
154
|
To use the module with a config file using the [`fileConfig` function](https://docs.python.org/3/library/logging.config.html#logging.config.fileConfig), use the class `pythonjsonlogger.jsonlogger.JsonFormatter`. Here is a sample config file.
|
|
135
155
|
|
|
@@ -162,8 +182,7 @@ format = %(message)s
|
|
|
162
182
|
class = pythonjsonlogger.jsonlogger.JsonFormatter
|
|
163
183
|
```
|
|
164
184
|
|
|
165
|
-
Example Output
|
|
166
|
-
==============
|
|
185
|
+
## Example Output
|
|
167
186
|
|
|
168
187
|
Sample JSON with a full formatter (basically the log message from the unit test). Every log message will appear on 1 line like a typical logger.
|
|
169
188
|
|
|
@@ -191,9 +210,14 @@ Sample JSON with a full formatter (basically the log message from the unit test)
|
|
|
191
210
|
}
|
|
192
211
|
```
|
|
193
212
|
|
|
194
|
-
|
|
195
|
-
|
|
213
|
+
## License
|
|
214
|
+
|
|
215
|
+
This project is licensed under the BSD 2 Clause License - see [`LICENSE`](https://github.com/nhairs/python-json-logger/blob/main/LICENSE)
|
|
216
|
+
|
|
217
|
+
## Authors and Maintainers
|
|
218
|
+
|
|
219
|
+
This project was originally authored by [Zakaria Zajac](https://github.com/madzak) and our wonderful [contributors](https://github.com/nhairs/python-json-logger/graphs/contributors)
|
|
196
220
|
|
|
197
|
-
|
|
221
|
+
It is currently maintained by:
|
|
198
222
|
|
|
199
|
-
- [
|
|
223
|
+
- [Nicholas Hairs](https://github.com/nhairs) - [nicholashairs.com](https://www.nicholashairs.com)
|
{python-json-logger-2.0.7 → python-json-logger-3.0.0}/src/python_json_logger.egg-info/SOURCES.txt
RENAMED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
LICENSE
|
|
2
2
|
MANIFEST.in
|
|
3
3
|
README.md
|
|
4
|
+
pyproject.toml
|
|
4
5
|
setup.cfg
|
|
5
|
-
setup.py
|
|
6
6
|
src/python_json_logger.egg-info/PKG-INFO
|
|
7
7
|
src/python_json_logger.egg-info/SOURCES.txt
|
|
8
8
|
src/python_json_logger.egg-info/dependency_links.txt
|
|
9
|
+
src/python_json_logger.egg-info/requires.txt
|
|
9
10
|
src/python_json_logger.egg-info/top_level.txt
|
|
10
11
|
src/pythonjsonlogger/__init__.py
|
|
11
12
|
src/pythonjsonlogger/jsonlogger.py
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
2
|
This library is provided to allow standard python logging
|
|
3
3
|
to output log data as JSON formatted strings
|
|
4
|
-
|
|
4
|
+
"""
|
|
5
|
+
|
|
5
6
|
import logging
|
|
6
7
|
import json
|
|
7
8
|
import re
|
|
8
|
-
from datetime import date, datetime, time, timezone
|
|
9
9
|
import traceback
|
|
10
10
|
import importlib
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
from datetime import date, datetime, time, timezone
|
|
12
|
+
import sys
|
|
13
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
13
14
|
|
|
14
15
|
from inspect import istraceback
|
|
15
16
|
|
|
@@ -17,19 +18,45 @@ from collections import OrderedDict
|
|
|
17
18
|
|
|
18
19
|
# skip natural LogRecord attributes
|
|
19
20
|
# http://docs.python.org/library/logging.html#logrecord-attributes
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
# Changed in 3.0.0, is now list[str] instead of tuple[str, ...]
|
|
22
|
+
RESERVED_ATTRS: List[str] = [
|
|
23
|
+
"args",
|
|
24
|
+
"asctime",
|
|
25
|
+
"created",
|
|
26
|
+
"exc_info",
|
|
27
|
+
"exc_text",
|
|
28
|
+
"filename",
|
|
29
|
+
"funcName",
|
|
30
|
+
"levelname",
|
|
31
|
+
"levelno",
|
|
32
|
+
"lineno",
|
|
33
|
+
"module",
|
|
34
|
+
"msecs",
|
|
35
|
+
"message",
|
|
36
|
+
"msg",
|
|
37
|
+
"name",
|
|
38
|
+
"pathname",
|
|
39
|
+
"process",
|
|
40
|
+
"processName",
|
|
41
|
+
"relativeCreated",
|
|
42
|
+
"stack_info",
|
|
43
|
+
"thread",
|
|
44
|
+
"threadName",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
if sys.version_info >= (3, 12):
|
|
48
|
+
# taskName added in python 3.12
|
|
49
|
+
RESERVED_ATTRS.append("taskName")
|
|
50
|
+
RESERVED_ATTRS.sort()
|
|
51
|
+
|
|
52
|
+
OptionalCallableOrStr = Optional[Union[Callable, str]]
|
|
26
53
|
|
|
27
54
|
|
|
28
55
|
def merge_record_extra(
|
|
29
56
|
record: logging.LogRecord,
|
|
30
57
|
target: Dict,
|
|
31
58
|
reserved: Union[Dict, List],
|
|
32
|
-
rename_fields: Optional[Dict[str,str]] = None,
|
|
59
|
+
rename_fields: Optional[Dict[str, str]] = None,
|
|
33
60
|
) -> Dict:
|
|
34
61
|
"""
|
|
35
62
|
Merges extra attributes from LogRecord object into target dictionary
|
|
@@ -44,10 +71,8 @@ def merge_record_extra(
|
|
|
44
71
|
rename_fields = {}
|
|
45
72
|
for key, value in record.__dict__.items():
|
|
46
73
|
# this allows to have numeric keys
|
|
47
|
-
if
|
|
48
|
-
|
|
49
|
-
and key.startswith('_'))):
|
|
50
|
-
target[rename_fields.get(key,key)] = value
|
|
74
|
+
if key not in reserved and not (hasattr(key, "startswith") and key.startswith("_")):
|
|
75
|
+
target[rename_fields.get(key, key)] = value
|
|
51
76
|
return target
|
|
52
77
|
|
|
53
78
|
|
|
@@ -56,30 +81,34 @@ class JsonEncoder(json.JSONEncoder):
|
|
|
56
81
|
A custom encoder extending the default JSONEncoder
|
|
57
82
|
"""
|
|
58
83
|
|
|
59
|
-
def default(self,
|
|
60
|
-
if isinstance(
|
|
61
|
-
return self.format_datetime_obj(
|
|
84
|
+
def default(self, o: Any) -> Any:
|
|
85
|
+
if isinstance(o, (date, datetime, time)):
|
|
86
|
+
return self.format_datetime_obj(o)
|
|
62
87
|
|
|
63
|
-
|
|
64
|
-
return
|
|
88
|
+
if istraceback(o):
|
|
89
|
+
return "".join(traceback.format_tb(o)).strip()
|
|
65
90
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return str(obj)
|
|
91
|
+
# pylint: disable=unidiomatic-typecheck
|
|
92
|
+
if type(o) == Exception or isinstance(o, Exception) or type(o) == type:
|
|
93
|
+
return str(o)
|
|
70
94
|
|
|
71
95
|
try:
|
|
72
|
-
return super(
|
|
96
|
+
return super().default(o)
|
|
73
97
|
|
|
74
98
|
except TypeError:
|
|
75
99
|
try:
|
|
76
|
-
return str(
|
|
100
|
+
return str(o)
|
|
77
101
|
|
|
78
|
-
except Exception:
|
|
102
|
+
except Exception: # pylint: disable=broad-exception-caught
|
|
79
103
|
return None
|
|
80
104
|
|
|
81
|
-
def format_datetime_obj(self,
|
|
82
|
-
|
|
105
|
+
def format_datetime_obj(self, o):
|
|
106
|
+
"""Format datetime objects found in self.default
|
|
107
|
+
|
|
108
|
+
This allows subclasses to change the datetime format without understanding the
|
|
109
|
+
internals of the default method.
|
|
110
|
+
"""
|
|
111
|
+
return o.isoformat()
|
|
83
112
|
|
|
84
113
|
|
|
85
114
|
class JsonFormatter(logging.Formatter):
|
|
@@ -89,22 +118,35 @@ class JsonFormatter(logging.Formatter):
|
|
|
89
118
|
json default encoder
|
|
90
119
|
"""
|
|
91
120
|
|
|
92
|
-
|
|
121
|
+
# pylint: disable=too-many-arguments
|
|
122
|
+
def __init__(
|
|
123
|
+
self,
|
|
124
|
+
*args: Any,
|
|
125
|
+
json_default: OptionalCallableOrStr = None,
|
|
126
|
+
json_encoder: OptionalCallableOrStr = None,
|
|
127
|
+
json_serialiser: Union[Callable, str] = json.dumps,
|
|
128
|
+
json_indent: Optional[Union[int, str]] = None,
|
|
129
|
+
json_ensure_ascii: bool = True,
|
|
130
|
+
prefix: str = "",
|
|
131
|
+
rename_fields: Optional[dict] = None,
|
|
132
|
+
static_fields: Optional[dict] = None,
|
|
133
|
+
reserved_attrs: Union[Tuple[str, ...], List[str], None] = None,
|
|
134
|
+
timestamp: Union[bool, str] = False,
|
|
135
|
+
**kwargs: Any,
|
|
136
|
+
) -> None:
|
|
93
137
|
"""
|
|
94
138
|
:param json_default: a function for encoding non-standard objects
|
|
95
139
|
as outlined in https://docs.python.org/3/library/json.html
|
|
96
140
|
:param json_encoder: optional custom encoder
|
|
97
141
|
:param json_serializer: a :meth:`json.dumps`-compatible callable
|
|
98
142
|
that will be used to serialize the log record.
|
|
99
|
-
:param json_indent:
|
|
100
|
-
|
|
143
|
+
:param json_indent: indent parameter for json.dumps
|
|
144
|
+
:param json_ensure_ascii: ensure_ascii parameter for json.dumps
|
|
101
145
|
:param prefix: an optional string prefix added at the beginning of
|
|
102
146
|
the formatted string
|
|
103
147
|
:param rename_fields: an optional dict, used to rename field names in the output.
|
|
104
148
|
Rename message to @message: {'message': '@message'}
|
|
105
149
|
:param static_fields: an optional dict, used to add fields with static values to all logs
|
|
106
|
-
:param json_indent: indent parameter for json.dumps
|
|
107
|
-
:param json_ensure_ascii: ensure_ascii parameter for json.dumps
|
|
108
150
|
:param reserved_attrs: an optional list of fields that will be skipped when
|
|
109
151
|
outputting json log record. Defaults to all log record attributes:
|
|
110
152
|
http://docs.python.org/library/logging.html#logrecord-attributes
|
|
@@ -113,17 +155,18 @@ class JsonFormatter(logging.Formatter):
|
|
|
113
155
|
to log record using string as key. If True boolean is passed, timestamp key
|
|
114
156
|
will be "timestamp". Defaults to False/off.
|
|
115
157
|
"""
|
|
116
|
-
self.json_default = self._str_to_fn(
|
|
117
|
-
self.json_encoder = self._str_to_fn(
|
|
118
|
-
self.json_serializer = self._str_to_fn(
|
|
119
|
-
self.json_indent =
|
|
120
|
-
self.json_ensure_ascii =
|
|
121
|
-
self.prefix =
|
|
122
|
-
self.rename_fields =
|
|
123
|
-
self.static_fields =
|
|
124
|
-
reserved_attrs
|
|
158
|
+
self.json_default = self._str_to_fn(json_default)
|
|
159
|
+
self.json_encoder = self._str_to_fn(json_encoder)
|
|
160
|
+
self.json_serializer = self._str_to_fn(json_serialiser)
|
|
161
|
+
self.json_indent = json_indent
|
|
162
|
+
self.json_ensure_ascii = json_ensure_ascii
|
|
163
|
+
self.prefix = prefix
|
|
164
|
+
self.rename_fields = rename_fields or {}
|
|
165
|
+
self.static_fields = static_fields or {}
|
|
166
|
+
if reserved_attrs is None:
|
|
167
|
+
reserved_attrs = RESERVED_ATTRS
|
|
125
168
|
self.reserved_attrs = dict(zip(reserved_attrs, reserved_attrs))
|
|
126
|
-
self.timestamp =
|
|
169
|
+
self.timestamp = timestamp
|
|
127
170
|
|
|
128
171
|
# super(JsonFormatter, self).__init__(*args, **kwargs)
|
|
129
172
|
logging.Formatter.__init__(self, *args, **kwargs)
|
|
@@ -131,9 +174,9 @@ class JsonFormatter(logging.Formatter):
|
|
|
131
174
|
self.json_encoder = JsonEncoder
|
|
132
175
|
|
|
133
176
|
self._required_fields = self.parse()
|
|
134
|
-
self._skip_fields = dict(zip(self._required_fields,
|
|
135
|
-
self._required_fields))
|
|
177
|
+
self._skip_fields = dict(zip(self._required_fields, self._required_fields))
|
|
136
178
|
self._skip_fields.update(self.reserved_attrs)
|
|
179
|
+
return
|
|
137
180
|
|
|
138
181
|
def _str_to_fn(self, fn_as_str):
|
|
139
182
|
"""
|
|
@@ -146,7 +189,7 @@ class JsonFormatter(logging.Formatter):
|
|
|
146
189
|
if not isinstance(fn_as_str, str):
|
|
147
190
|
return fn_as_str
|
|
148
191
|
|
|
149
|
-
path, _, function = fn_as_str.rpartition(
|
|
192
|
+
path, _, function = fn_as_str.rpartition(".")
|
|
150
193
|
module = importlib.import_module(path)
|
|
151
194
|
return getattr(module, function)
|
|
152
195
|
|
|
@@ -158,22 +201,26 @@ class JsonFormatter(logging.Formatter):
|
|
|
158
201
|
to include in all log messages.
|
|
159
202
|
"""
|
|
160
203
|
if isinstance(self._style, logging.StringTemplateStyle):
|
|
161
|
-
formatter_style_pattern = re.compile(r
|
|
204
|
+
formatter_style_pattern = re.compile(r"\$\{(.+?)\}", re.IGNORECASE)
|
|
162
205
|
elif isinstance(self._style, logging.StrFormatStyle):
|
|
163
|
-
formatter_style_pattern = re.compile(r
|
|
206
|
+
formatter_style_pattern = re.compile(r"\{(.+?)\}", re.IGNORECASE)
|
|
164
207
|
# PercentStyle is parent class of StringTemplateStyle and StrFormatStyle so
|
|
165
208
|
# it needs to be checked last.
|
|
166
209
|
elif isinstance(self._style, logging.PercentStyle):
|
|
167
|
-
formatter_style_pattern = re.compile(r
|
|
210
|
+
formatter_style_pattern = re.compile(r"%\((.+?)\)", re.IGNORECASE)
|
|
168
211
|
else:
|
|
169
|
-
raise ValueError(
|
|
212
|
+
raise ValueError(f"Invalid format: {self._fmt!r}")
|
|
170
213
|
|
|
171
214
|
if self._fmt:
|
|
172
215
|
return formatter_style_pattern.findall(self._fmt)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
216
|
+
return []
|
|
217
|
+
|
|
218
|
+
def add_fields(
|
|
219
|
+
self,
|
|
220
|
+
log_record: Dict[str, Any],
|
|
221
|
+
record: logging.LogRecord,
|
|
222
|
+
message_dict: Dict[str, Any],
|
|
223
|
+
) -> None:
|
|
177
224
|
"""
|
|
178
225
|
Override this method to implement custom logic for adding fields.
|
|
179
226
|
"""
|
|
@@ -182,42 +229,53 @@ class JsonFormatter(logging.Formatter):
|
|
|
182
229
|
|
|
183
230
|
log_record.update(self.static_fields)
|
|
184
231
|
log_record.update(message_dict)
|
|
185
|
-
merge_record_extra(
|
|
232
|
+
merge_record_extra(
|
|
233
|
+
record,
|
|
234
|
+
log_record,
|
|
235
|
+
reserved=self._skip_fields,
|
|
236
|
+
rename_fields=self.rename_fields,
|
|
237
|
+
)
|
|
186
238
|
|
|
187
239
|
if self.timestamp:
|
|
188
|
-
|
|
240
|
+
# TODO: Can this use isinstance instead?
|
|
241
|
+
# pylint: disable=unidiomatic-typecheck
|
|
242
|
+
key = self.timestamp if type(self.timestamp) == str else "timestamp"
|
|
189
243
|
log_record[key] = datetime.fromtimestamp(record.created, tz=timezone.utc)
|
|
190
244
|
|
|
191
245
|
self._perform_rename_log_fields(log_record)
|
|
246
|
+
return
|
|
192
247
|
|
|
193
|
-
def _perform_rename_log_fields(self, log_record):
|
|
248
|
+
def _perform_rename_log_fields(self, log_record: Dict[str, Any]) -> None:
|
|
194
249
|
for old_field_name, new_field_name in self.rename_fields.items():
|
|
195
250
|
log_record[new_field_name] = log_record[old_field_name]
|
|
196
251
|
del log_record[old_field_name]
|
|
252
|
+
return
|
|
197
253
|
|
|
198
|
-
def process_log_record(self, log_record):
|
|
254
|
+
def process_log_record(self, log_record: Dict[str, Any]) -> Dict[str, Any]:
|
|
199
255
|
"""
|
|
200
256
|
Override this method to implement custom logic
|
|
201
257
|
on the possibly ordered dictionary.
|
|
202
258
|
"""
|
|
203
259
|
return log_record
|
|
204
260
|
|
|
205
|
-
def jsonify_log_record(self, log_record):
|
|
261
|
+
def jsonify_log_record(self, log_record: Dict[str, Any]) -> str:
|
|
206
262
|
"""Returns a json string of the log record."""
|
|
207
|
-
return self.json_serializer(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
263
|
+
return self.json_serializer(
|
|
264
|
+
log_record,
|
|
265
|
+
default=self.json_default,
|
|
266
|
+
cls=self.json_encoder,
|
|
267
|
+
indent=self.json_indent,
|
|
268
|
+
ensure_ascii=self.json_ensure_ascii,
|
|
269
|
+
)
|
|
212
270
|
|
|
213
271
|
def serialize_log_record(self, log_record: Dict[str, Any]) -> str:
|
|
214
272
|
"""Returns the final representation of the log record."""
|
|
215
|
-
return
|
|
273
|
+
return self.prefix + self.jsonify_log_record(log_record)
|
|
216
274
|
|
|
217
275
|
def format(self, record: logging.LogRecord) -> str:
|
|
218
276
|
"""Formats a log record and serializes to json"""
|
|
219
277
|
message_dict: Dict[str, Any] = {}
|
|
220
|
-
#
|
|
278
|
+
# TODO: logging.LogRecord.msg and logging.LogRecord.message in typeshed
|
|
221
279
|
# are always type of str. We shouldn't need to override that.
|
|
222
280
|
if isinstance(record.msg, dict):
|
|
223
281
|
message_dict = record.msg
|
|
@@ -230,14 +288,14 @@ class JsonFormatter(logging.Formatter):
|
|
|
230
288
|
|
|
231
289
|
# Display formatted exception, but allow overriding it in the
|
|
232
290
|
# user-supplied dict.
|
|
233
|
-
if record.exc_info and not message_dict.get(
|
|
234
|
-
message_dict[
|
|
235
|
-
if not message_dict.get(
|
|
236
|
-
message_dict[
|
|
291
|
+
if record.exc_info and not message_dict.get("exc_info"):
|
|
292
|
+
message_dict["exc_info"] = self.formatException(record.exc_info)
|
|
293
|
+
if not message_dict.get("exc_info") and record.exc_text:
|
|
294
|
+
message_dict["exc_info"] = record.exc_text
|
|
237
295
|
# Display formatted record of stack frames
|
|
238
296
|
# default format is a string returned from :func:`traceback.print_stack`
|
|
239
|
-
if record.stack_info and not message_dict.get(
|
|
240
|
-
message_dict[
|
|
297
|
+
if record.stack_info and not message_dict.get("stack_info"):
|
|
298
|
+
message_dict["stack_info"] = self.formatStack(record.stack_info)
|
|
241
299
|
|
|
242
300
|
log_record: Dict[str, Any] = OrderedDict()
|
|
243
301
|
self.add_fields(log_record, record, message_dict)
|
|
@@ -1,27 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
import unittest
|
|
3
|
-
import unittest.mock
|
|
1
|
+
import datetime
|
|
4
2
|
import logging
|
|
3
|
+
from io import StringIO
|
|
5
4
|
import json
|
|
5
|
+
import random
|
|
6
6
|
import sys
|
|
7
7
|
import traceback
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
try:
|
|
11
|
-
import xmlrunner # noqa
|
|
12
|
-
except ImportError:
|
|
13
|
-
pass
|
|
14
|
-
|
|
15
|
-
from io import StringIO
|
|
8
|
+
import unittest
|
|
9
|
+
import unittest.mock
|
|
16
10
|
|
|
17
|
-
sys.path.append(
|
|
11
|
+
sys.path.append("src/python-json-logger")
|
|
18
12
|
from pythonjsonlogger import jsonlogger
|
|
19
|
-
import datetime
|
|
20
13
|
|
|
21
14
|
|
|
22
15
|
class TestJsonLogger(unittest.TestCase):
|
|
23
16
|
def setUp(self):
|
|
24
|
-
self.log = logging.getLogger("logging-test-{
|
|
17
|
+
self.log = logging.getLogger(f"logging-test-{random.randint(1, 101)}")
|
|
25
18
|
self.log.setLevel(logging.DEBUG)
|
|
26
19
|
self.buffer = StringIO()
|
|
27
20
|
|
|
@@ -41,7 +34,7 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
41
34
|
def test_percentage_format(self):
|
|
42
35
|
fr = jsonlogger.JsonFormatter(
|
|
43
36
|
# All kind of different styles to check the regex
|
|
44
|
-
|
|
37
|
+
"[%(levelname)8s] %(message)s %(filename)s:%(lineno)d %(asctime)"
|
|
45
38
|
)
|
|
46
39
|
self.log_handler.setFormatter(fr)
|
|
47
40
|
|
|
@@ -50,10 +43,10 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
50
43
|
log_json = json.loads(self.buffer.getvalue())
|
|
51
44
|
|
|
52
45
|
self.assertEqual(log_json["message"], msg)
|
|
53
|
-
self.assertEqual(log_json.keys(), {
|
|
46
|
+
self.assertEqual(log_json.keys(), {"levelname", "message", "filename", "lineno", "asctime"})
|
|
54
47
|
|
|
55
48
|
def test_rename_base_field(self):
|
|
56
|
-
fr = jsonlogger.JsonFormatter(rename_fields={
|
|
49
|
+
fr = jsonlogger.JsonFormatter(rename_fields={"message": "@message"})
|
|
57
50
|
self.log_handler.setFormatter(fr)
|
|
58
51
|
|
|
59
52
|
msg = "testing logging format"
|
|
@@ -63,7 +56,7 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
63
56
|
self.assertEqual(log_json["@message"], msg)
|
|
64
57
|
|
|
65
58
|
def test_rename_nonexistent_field(self):
|
|
66
|
-
fr = jsonlogger.JsonFormatter(rename_fields={
|
|
59
|
+
fr = jsonlogger.JsonFormatter(rename_fields={"nonexistent_key": "new_name"})
|
|
67
60
|
self.log_handler.setFormatter(fr)
|
|
68
61
|
|
|
69
62
|
stderr_watcher = StringIO()
|
|
@@ -73,7 +66,7 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
73
66
|
self.assertTrue("KeyError: 'nonexistent_key'" in stderr_watcher.getvalue())
|
|
74
67
|
|
|
75
68
|
def test_add_static_fields(self):
|
|
76
|
-
fr = jsonlogger.JsonFormatter(static_fields={
|
|
69
|
+
fr = jsonlogger.JsonFormatter(static_fields={"log_stream": "kafka"})
|
|
77
70
|
|
|
78
71
|
self.log_handler.setFormatter(fr)
|
|
79
72
|
|
|
@@ -86,27 +79,27 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
86
79
|
|
|
87
80
|
def test_format_keys(self):
|
|
88
81
|
supported_keys = [
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
82
|
+
"asctime",
|
|
83
|
+
"created",
|
|
84
|
+
"filename",
|
|
85
|
+
"funcName",
|
|
86
|
+
"levelname",
|
|
87
|
+
"levelno",
|
|
88
|
+
"lineno",
|
|
89
|
+
"module",
|
|
90
|
+
"msecs",
|
|
91
|
+
"message",
|
|
92
|
+
"name",
|
|
93
|
+
"pathname",
|
|
94
|
+
"process",
|
|
95
|
+
"processName",
|
|
96
|
+
"relativeCreated",
|
|
97
|
+
"thread",
|
|
98
|
+
"threadName",
|
|
106
99
|
]
|
|
107
100
|
|
|
108
|
-
log_format = lambda x: [
|
|
109
|
-
custom_format =
|
|
101
|
+
log_format = lambda x: [f"%({i:s})s" for i in x]
|
|
102
|
+
custom_format = " ".join(log_format(supported_keys))
|
|
110
103
|
|
|
111
104
|
fr = jsonlogger.JsonFormatter(custom_format)
|
|
112
105
|
self.log_handler.setFormatter(fr)
|
|
@@ -121,7 +114,7 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
121
114
|
self.assertTrue(True)
|
|
122
115
|
|
|
123
116
|
def test_unknown_format_key(self):
|
|
124
|
-
fr = jsonlogger.JsonFormatter(
|
|
117
|
+
fr = jsonlogger.JsonFormatter("%(unknown_key)s %(message)s")
|
|
125
118
|
|
|
126
119
|
self.log_handler.setFormatter(fr)
|
|
127
120
|
msg = "testing unknown logging format"
|
|
@@ -134,8 +127,7 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
134
127
|
fr = jsonlogger.JsonFormatter()
|
|
135
128
|
self.log_handler.setFormatter(fr)
|
|
136
129
|
|
|
137
|
-
msg = {"text": "testing logging", "num": 1, 5: "9",
|
|
138
|
-
"nested": {"more": "data"}}
|
|
130
|
+
msg = {"text": "testing logging", "num": 1, 5: "9", "nested": {"more": "data"}}
|
|
139
131
|
|
|
140
132
|
self.log.info(msg)
|
|
141
133
|
log_json = json.loads(self.buffer.getvalue())
|
|
@@ -149,8 +141,7 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
149
141
|
fr = jsonlogger.JsonFormatter()
|
|
150
142
|
self.log_handler.setFormatter(fr)
|
|
151
143
|
|
|
152
|
-
extra = {"text": "testing logging", "num": 1, 5: "9",
|
|
153
|
-
"nested": {"more": "data"}}
|
|
144
|
+
extra = {"text": "testing logging", "num": 1, 5: "9", "nested": {"more": "data"}}
|
|
154
145
|
self.log.info("hello", extra=extra)
|
|
155
146
|
log_json = json.loads(self.buffer.getvalue())
|
|
156
147
|
self.assertEqual(log_json.get("text"), extra["text"])
|
|
@@ -163,19 +154,20 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
163
154
|
fr = jsonlogger.JsonFormatter()
|
|
164
155
|
self.log_handler.setFormatter(fr)
|
|
165
156
|
|
|
166
|
-
msg = {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
157
|
+
msg = {
|
|
158
|
+
"adate": datetime.datetime(1999, 12, 31, 23, 59),
|
|
159
|
+
"otherdate": datetime.date(1789, 7, 14),
|
|
160
|
+
"otherdatetime": datetime.datetime(1789, 7, 14, 23, 59),
|
|
161
|
+
"otherdatetimeagain": datetime.datetime(1900, 1, 1),
|
|
162
|
+
}
|
|
170
163
|
self.log.info(msg)
|
|
171
164
|
log_json = json.loads(self.buffer.getvalue())
|
|
172
165
|
self.assertEqual(log_json.get("adate"), "1999-12-31T23:59:00")
|
|
173
166
|
self.assertEqual(log_json.get("otherdate"), "1789-07-14")
|
|
174
167
|
self.assertEqual(log_json.get("otherdatetime"), "1789-07-14T23:59:00")
|
|
175
|
-
self.assertEqual(log_json.get("otherdatetimeagain"),
|
|
176
|
-
"1900-01-01T00:00:00")
|
|
168
|
+
self.assertEqual(log_json.get("otherdatetimeagain"), "1900-01-01T00:00:00")
|
|
177
169
|
|
|
178
|
-
@unittest.mock.patch(
|
|
170
|
+
@unittest.mock.patch("time.time", return_value=1500000000.0)
|
|
179
171
|
def test_json_default_encoder_with_timestamp(self, time_mock):
|
|
180
172
|
fr = jsonlogger.JsonFormatter(timestamp=True)
|
|
181
173
|
self.log_handler.setFormatter(fr)
|
|
@@ -189,11 +181,11 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
189
181
|
def test_json_custom_default(self):
|
|
190
182
|
def custom(o):
|
|
191
183
|
return "very custom"
|
|
184
|
+
|
|
192
185
|
fr = jsonlogger.JsonFormatter(json_default=custom)
|
|
193
186
|
self.log_handler.setFormatter(fr)
|
|
194
187
|
|
|
195
|
-
msg = {"adate": datetime.datetime(1999, 12, 31, 23, 59),
|
|
196
|
-
"normal": "value"}
|
|
188
|
+
msg = {"adate": datetime.datetime(1999, 12, 31, 23, 59), "normal": "value"}
|
|
197
189
|
self.log.info(msg)
|
|
198
190
|
log_json = json.loads(self.buffer.getvalue())
|
|
199
191
|
self.assertEqual(log_json.get("adate"), "very custom")
|
|
@@ -215,12 +207,12 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
215
207
|
|
|
216
208
|
def get_traceback_from_exception_followed_by_log_call(self) -> str:
|
|
217
209
|
try:
|
|
218
|
-
raise Exception(
|
|
210
|
+
raise Exception("test")
|
|
219
211
|
except Exception:
|
|
220
212
|
self.log.exception("hello")
|
|
221
213
|
str_traceback = traceback.format_exc()
|
|
222
214
|
# Formatter removes trailing new line
|
|
223
|
-
if str_traceback.endswith(
|
|
215
|
+
if str_traceback.endswith("\n"):
|
|
224
216
|
str_traceback = str_traceback[:-1]
|
|
225
217
|
|
|
226
218
|
return str_traceback
|
|
@@ -245,14 +237,14 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
245
237
|
def test_ensure_ascii_true(self):
|
|
246
238
|
fr = jsonlogger.JsonFormatter()
|
|
247
239
|
self.log_handler.setFormatter(fr)
|
|
248
|
-
self.log.info(
|
|
240
|
+
self.log.info("Привет")
|
|
249
241
|
msg = self.buffer.getvalue().split('"message": "', 1)[1].split('"', 1)[0]
|
|
250
242
|
self.assertEqual(msg, r"\u041f\u0440\u0438\u0432\u0435\u0442")
|
|
251
243
|
|
|
252
244
|
def test_ensure_ascii_false(self):
|
|
253
245
|
fr = jsonlogger.JsonFormatter(json_ensure_ascii=False)
|
|
254
246
|
self.log_handler.setFormatter(fr)
|
|
255
|
-
self.log.info(
|
|
247
|
+
self.log.info("Привет")
|
|
256
248
|
msg = self.buffer.getvalue().split('"message": "', 1)[1].split('"', 1)[0]
|
|
257
249
|
self.assertEqual(msg, "Привет")
|
|
258
250
|
|
|
@@ -262,10 +254,11 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
262
254
|
return (z.real, z.imag)
|
|
263
255
|
else:
|
|
264
256
|
type_name = z.__class__.__name__
|
|
265
|
-
raise TypeError("Object of type '{}' is no JSON serializable"
|
|
257
|
+
raise TypeError(f"Object of type '{type_name}' is no JSON serializable")
|
|
266
258
|
|
|
267
|
-
formatter = jsonlogger.JsonFormatter(
|
|
268
|
-
|
|
259
|
+
formatter = jsonlogger.JsonFormatter(
|
|
260
|
+
json_default=encode_complex, json_encoder=json.JSONEncoder
|
|
261
|
+
)
|
|
269
262
|
self.log_handler.setFormatter(formatter)
|
|
270
263
|
|
|
271
264
|
value = {
|
|
@@ -274,44 +267,43 @@ class TestJsonLogger(unittest.TestCase):
|
|
|
274
267
|
|
|
275
268
|
self.log.info(" message", extra=value)
|
|
276
269
|
msg = self.buffer.getvalue()
|
|
277
|
-
self.assertEqual(msg,
|
|
270
|
+
self.assertEqual(msg, '{"message": " message", "special": [3.0, 8.0]}\n')
|
|
278
271
|
|
|
279
272
|
def test_rename_reserved_attrs(self):
|
|
280
|
-
log_format = lambda x: [
|
|
273
|
+
log_format = lambda x: [f"%({i:s})s" for i in x]
|
|
281
274
|
reserved_attrs_map = {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
275
|
+
"exc_info": "error.type",
|
|
276
|
+
"exc_text": "error.message",
|
|
277
|
+
"funcName": "log.origin.function",
|
|
278
|
+
"levelname": "log.level",
|
|
279
|
+
"module": "log.origin.file.name",
|
|
280
|
+
"processName": "process.name",
|
|
281
|
+
"threadName": "process.thread.name",
|
|
282
|
+
"msg": "log.message",
|
|
290
283
|
}
|
|
291
284
|
|
|
292
|
-
custom_format =
|
|
293
|
-
reserved_attrs = [
|
|
294
|
-
|
|
285
|
+
custom_format = " ".join(log_format(reserved_attrs_map.keys()))
|
|
286
|
+
reserved_attrs = [
|
|
287
|
+
_ for _ in jsonlogger.RESERVED_ATTRS if _ not in list(reserved_attrs_map.keys())
|
|
288
|
+
]
|
|
289
|
+
formatter = jsonlogger.JsonFormatter(
|
|
290
|
+
custom_format, reserved_attrs=reserved_attrs, rename_fields=reserved_attrs_map
|
|
291
|
+
)
|
|
295
292
|
self.log_handler.setFormatter(formatter)
|
|
296
293
|
self.log.info("message")
|
|
297
294
|
|
|
298
295
|
msg = self.buffer.getvalue()
|
|
299
|
-
self.assertEqual(
|
|
296
|
+
self.assertEqual(
|
|
297
|
+
msg,
|
|
298
|
+
'{"error.type": null, "error.message": null, "log.origin.function": "test_rename_reserved_attrs", "log.level": "INFO", "log.origin.file.name": "test_jsonlogger", "process.name": "MainProcess", "process.thread.name": "MainThread", "log.message": "message"}\n',
|
|
299
|
+
)
|
|
300
300
|
|
|
301
301
|
def test_merge_record_extra(self):
|
|
302
|
-
record = logging.LogRecord(
|
|
302
|
+
record = logging.LogRecord(
|
|
303
|
+
"name", level=1, pathname="", lineno=1, msg="Some message", args=None, exc_info=None
|
|
304
|
+
)
|
|
303
305
|
output = jsonlogger.merge_record_extra(record, target=dict(foo="bar"), reserved=[])
|
|
304
306
|
self.assertIn("foo", output)
|
|
305
307
|
self.assertIn("msg", output)
|
|
306
308
|
self.assertEqual(output["foo"], "bar")
|
|
307
309
|
self.assertEqual(output["msg"], "Some message")
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if __name__ == '__main__':
|
|
311
|
-
if len(sys.argv[1:]) > 0:
|
|
312
|
-
if sys.argv[1] == 'xml':
|
|
313
|
-
testSuite = unittest.TestLoader().loadTestsFromTestCase(
|
|
314
|
-
TestJsonLogger)
|
|
315
|
-
xmlrunner.XMLTestRunner(output='reports').run(testSuite)
|
|
316
|
-
else:
|
|
317
|
-
unittest.main()
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
from os import path
|
|
2
|
-
from setuptools import setup, find_packages
|
|
3
|
-
|
|
4
|
-
# read the contents of your README file
|
|
5
|
-
this_directory = path.abspath(path.dirname(__file__))
|
|
6
|
-
with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
|
|
7
|
-
long_description = f.read()
|
|
8
|
-
|
|
9
|
-
setup(
|
|
10
|
-
name="python-json-logger",
|
|
11
|
-
version="2.0.7",
|
|
12
|
-
url="http://github.com/madzak/python-json-logger",
|
|
13
|
-
license="BSD",
|
|
14
|
-
include_package_data=True,
|
|
15
|
-
description="A python library adding a json log formatter",
|
|
16
|
-
long_description=long_description,
|
|
17
|
-
long_description_content_type='text/markdown',
|
|
18
|
-
author="Zakaria Zajac",
|
|
19
|
-
author_email="zak@madzak.com",
|
|
20
|
-
package_dir={'': 'src'},
|
|
21
|
-
package_data={"pythonjsonlogger": ["py.typed"]},
|
|
22
|
-
packages=find_packages("src", exclude="tests"),
|
|
23
|
-
# https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
|
|
24
|
-
python_requires=">=3.6",
|
|
25
|
-
test_suite="tests.tests",
|
|
26
|
-
classifiers=[
|
|
27
|
-
'Development Status :: 6 - Mature',
|
|
28
|
-
'Intended Audience :: Developers',
|
|
29
|
-
'License :: OSI Approved :: BSD License',
|
|
30
|
-
'Operating System :: OS Independent',
|
|
31
|
-
'Programming Language :: Python',
|
|
32
|
-
'Programming Language :: Python :: 3',
|
|
33
|
-
'Programming Language :: Python :: 3.6',
|
|
34
|
-
'Programming Language :: Python :: 3.7',
|
|
35
|
-
'Programming Language :: Python :: 3.8',
|
|
36
|
-
'Programming Language :: Python :: 3.9',
|
|
37
|
-
'Programming Language :: Python :: 3.10',
|
|
38
|
-
'Programming Language :: Python :: 3.11',
|
|
39
|
-
'Topic :: System :: Logging',
|
|
40
|
-
]
|
|
41
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python-json-logger-2.0.7 → python-json-logger-3.0.0}/src/python_json_logger.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|