python-json-logger 2.0.6__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.
@@ -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:
@@ -1,58 +1,78 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-json-logger
3
- Version: 2.0.6
4
- Summary: A python library adding a json log formatter
5
- Home-page: http://github.com/madzak/python-json-logger
6
- Author: Zakaria Zajac
7
- Author-email: zak@madzak.com
8
- License: BSD
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
- Requires-Python: >=3.6
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.7
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
-
26
- ![Build Status](https://github.com/madzak/python-json-logger/actions/workflows/build.yml/badge.svg)
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
+ ![Build Status](https://github.com/nhairs/python-json-logger/actions/workflows/test-suite.yml/badge.svg)
27
34
  [![License](https://img.shields.io/pypi/l/python-json-logger.svg)](https://pypi.python.org/pypi/python-json-logger/)
28
35
  [![Version](https://img.shields.io/pypi/v/python-json-logger.svg)](https://pypi.python.org/pypi/python-json-logger/)
29
36
 
30
- Overview
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
- Installing
39
- ==========
40
- Pip:
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
- pip install python-json-logger
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
- Pypi:
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
- Manual:
65
+ ### Install from Source
49
66
 
50
- python setup.py install
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
- ## Integrating with Python's logging framework
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
- ## Customizing fields
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
- ## Adding custom object serialization
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
- ## Using a Config File
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
- External Examples
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
- - [Wesley Tanaka - Structured log files in Python using python-json-logger](https://wtanaka.com/node/8201)
221
+ It is currently maintained by:
198
222
 
199
- - [Archive](https://web.archive.org/web/20201130054012/https://wtanaka.com/node/8201)
223
+ - [Nicholas Hairs](https://github.com/nhairs) - [nicholashairs.com](https://www.nicholashairs.com)
@@ -1,33 +1,46 @@
1
- ![Build Status](https://github.com/madzak/python-json-logger/actions/workflows/build.yml/badge.svg)
1
+ ![Build Status](https://github.com/nhairs/python-json-logger/actions/workflows/test-suite.yml/badge.svg)
2
2
  [![License](https://img.shields.io/pypi/l/python-json-logger.svg)](https://pypi.python.org/pypi/python-json-logger/)
3
3
  [![Version](https://img.shields.io/pypi/v/python-json-logger.svg)](https://pypi.python.org/pypi/python-json-logger/)
4
4
 
5
- Overview
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
- Installing
14
- ==========
15
- Pip:
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
- pip install python-json-logger
14
+ ## Installation
18
15
 
19
- Pypi:
16
+ ### Install via pip / PyPI
20
17
 
21
- https://pypi.python.org/pypi/python-json-logger
18
+ Until the PEP 541 request is complete you will need to use one of the alternative methods below.
22
19
 
23
- Manual:
20
+ ### Install from GitHub
24
21
 
25
- python setup.py install
22
+ ```shell
23
+ pip install 'python-json-logger@git+https://github.com/nhairs/python-json-logger.git'
24
+ ```
26
25
 
27
- Usage
28
- =====
26
+ To install a specific version:
29
27
 
30
- ## Integrating with Python's logging framework
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
- ## Customizing fields
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
- ## Adding custom object serialization
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
- ## Using a Config File
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
- External Examples
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
- - [Wesley Tanaka - Structured log files in Python using python-json-logger](https://wtanaka.com/node/8201)
189
+ It is currently maintained by:
173
190
 
174
- - [Archive](https://web.archive.org/web/20201130054012/https://wtanaka.com/node/8201)
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
@@ -1,58 +1,78 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-json-logger
3
- Version: 2.0.6
4
- Summary: A python library adding a json log formatter
5
- Home-page: http://github.com/madzak/python-json-logger
6
- Author: Zakaria Zajac
7
- Author-email: zak@madzak.com
8
- License: BSD
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
- Requires-Python: >=3.6
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.7
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
-
26
- ![Build Status](https://github.com/madzak/python-json-logger/actions/workflows/build.yml/badge.svg)
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
+ ![Build Status](https://github.com/nhairs/python-json-logger/actions/workflows/test-suite.yml/badge.svg)
27
34
  [![License](https://img.shields.io/pypi/l/python-json-logger.svg)](https://pypi.python.org/pypi/python-json-logger/)
28
35
  [![Version](https://img.shields.io/pypi/v/python-json-logger.svg)](https://pypi.python.org/pypi/python-json-logger/)
29
36
 
30
- Overview
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
- Installing
39
- ==========
40
- Pip:
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
- pip install python-json-logger
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
- Pypi:
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
- Manual:
65
+ ### Install from Source
49
66
 
50
- python setup.py install
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
- ## Integrating with Python's logging framework
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
- ## Customizing fields
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
- ## Adding custom object serialization
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
- ## Using a Config File
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
- External Examples
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
- - [Wesley Tanaka - Structured log files in Python using python-json-logger](https://wtanaka.com/node/8201)
221
+ It is currently maintained by:
198
222
 
199
- - [Archive](https://web.archive.org/web/20201130054012/https://wtanaka.com/node/8201)
223
+ - [Nicholas Hairs](https://github.com/nhairs) - [nicholashairs.com](https://www.nicholashairs.com)
@@ -1,13 +1,15 @@
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
13
+ src/pythonjsonlogger/py.typed
12
14
  tests/__init__.py
13
- tests/tests.py
15
+ tests/test_jsonlogger.py
@@ -0,0 +1,9 @@
1
+
2
+ [lint]
3
+ validate-pyproject[all]
4
+ black
5
+ pylint
6
+ mypy
7
+
8
+ [test]
9
+ pytest
@@ -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
- from typing import Any, Dict, Optional, Union, List, Tuple
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
- RESERVED_ATTRS: Tuple[str, ...] = (
21
- 'args', 'asctime', 'created', 'exc_info', 'exc_text', 'filename',
22
- 'funcName', 'levelname', 'levelno', 'lineno', 'module',
23
- 'msecs', 'message', 'msg', 'name', 'pathname', 'process',
24
- 'processName', 'relativeCreated', 'stack_info', 'thread', 'threadName')
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 (key not in reserved
48
- and not (hasattr(key, "startswith")
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, obj):
60
- if isinstance(obj, (date, datetime, time)):
61
- return self.format_datetime_obj(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
- elif istraceback(obj):
64
- return ''.join(traceback.format_tb(obj)).strip()
88
+ if istraceback(o):
89
+ return "".join(traceback.format_tb(o)).strip()
65
90
 
66
- elif type(obj) == Exception \
67
- or isinstance(obj, Exception) \
68
- or type(obj) == type:
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(JsonEncoder, self).default(obj)
96
+ return super().default(o)
73
97
 
74
98
  except TypeError:
75
99
  try:
76
- return str(obj)
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, obj):
82
- return obj.isoformat()
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
- def __init__(self, *args, **kwargs):
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: an optional :meth:`json.dumps`-compatible numeric value
100
- that will be used to customize the indent of the output json.
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(kwargs.pop("json_default", None))
117
- self.json_encoder = self._str_to_fn(kwargs.pop("json_encoder", None))
118
- self.json_serializer = self._str_to_fn(kwargs.pop("json_serializer", json.dumps))
119
- self.json_indent = kwargs.pop("json_indent", None)
120
- self.json_ensure_ascii = kwargs.pop("json_ensure_ascii", True)
121
- self.prefix = kwargs.pop("prefix", "")
122
- self.rename_fields = kwargs.pop("rename_fields", {})
123
- self.static_fields = kwargs.pop("static_fields", {})
124
- reserved_attrs = kwargs.pop("reserved_attrs", 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 = kwargs.pop("timestamp", False)
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'\$\{(.+?)\}', re.IGNORECASE)
204
+ formatter_style_pattern = re.compile(r"\$\{(.+?)\}", re.IGNORECASE)
162
205
  elif isinstance(self._style, logging.StrFormatStyle):
163
- formatter_style_pattern = re.compile(r'\{(.+?)\}', re.IGNORECASE)
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'%\((.+?)\)', re.IGNORECASE)
210
+ formatter_style_pattern = re.compile(r"%\((.+?)\)", re.IGNORECASE)
168
211
  else:
169
- raise ValueError('Invalid format: %s' % self._fmt)
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
- else:
174
- return []
175
-
176
- def add_fields(self, log_record: Dict[str, Any], record: logging.LogRecord, message_dict: Dict[str, Any]) -> None:
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(record, log_record, reserved=self._skip_fields, rename_fields=self.rename_fields)
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
- key = self.timestamp if type(self.timestamp) == str else 'timestamp'
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(log_record,
208
- default=self.json_default,
209
- cls=self.json_encoder,
210
- indent=self.json_indent,
211
- ensure_ascii=self.json_ensure_ascii)
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 "%s%s" % (self.prefix, self.jsonify_log_record(log_record))
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
- # FIXME: logging.LogRecord.msg and logging.LogRecord.message in typeshed
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('exc_info'):
234
- message_dict['exc_info'] = self.formatException(record.exc_info)
235
- if not message_dict.get('exc_info') and record.exc_text:
236
- message_dict['exc_info'] = record.exc_text
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('stack_info'):
240
- message_dict['stack_info'] = self.formatStack(record.stack_info)
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)
@@ -0,0 +1 @@
1
+ # PEP-561 marker. https://mypy.readthedocs.io/en/latest/installed_packages.html
@@ -1,27 +1,20 @@
1
- # -*- coding: utf-8 -*-
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 random
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('src/python-json-logger')
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-{}".format(random.randint(1, 101)))
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
- '[%(levelname)8s] %(message)s %(filename)s:%(lineno)d %(asctime)'
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(), {'levelname', 'message', 'filename', 'lineno', 'asctime'})
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={'message': '@message'})
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={'nonexistent_key': 'new_name'})
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={'log_stream': 'kafka'})
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
- 'asctime',
90
- 'created',
91
- 'filename',
92
- 'funcName',
93
- 'levelname',
94
- 'levelno',
95
- 'lineno',
96
- 'module',
97
- 'msecs',
98
- 'message',
99
- 'name',
100
- 'pathname',
101
- 'process',
102
- 'processName',
103
- 'relativeCreated',
104
- 'thread',
105
- 'threadName'
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: ['%({0:s})s'.format(i) for i in x]
109
- custom_format = ' '.join(log_format(supported_keys))
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('%(unknown_key)s %(message)s')
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 = {"adate": datetime.datetime(1999, 12, 31, 23, 59),
167
- "otherdate": datetime.date(1789, 7, 14),
168
- "otherdatetime": datetime.datetime(1789, 7, 14, 23, 59),
169
- "otherdatetimeagain": datetime.datetime(1900, 1, 1)}
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('time.time', return_value=1500000000.0)
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('test')
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('\n'):
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".format(type_name))
257
+ raise TypeError(f"Object of type '{type_name}' is no JSON serializable")
266
258
 
267
- formatter = jsonlogger.JsonFormatter(json_default=encode_complex,
268
- json_encoder=json.JSONEncoder)
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, "{\"message\": \" message\", \"special\": [3.0, 8.0]}\n")
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: ['%({0:s})s'.format(i) for i in x]
273
+ log_format = lambda x: [f"%({i:s})s" for i in x]
281
274
  reserved_attrs_map = {
282
- 'exc_info': 'error.type',
283
- 'exc_text': 'error.message',
284
- 'funcName': 'log.origin.function',
285
- 'levelname': 'log.level',
286
- 'module': 'log.origin.file.name',
287
- 'processName': 'process.name',
288
- 'threadName': 'process.thread.name',
289
- 'msg': 'log.message'
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 = ' '.join(log_format(reserved_attrs_map.keys()))
293
- reserved_attrs = [_ for _ in jsonlogger.RESERVED_ATTRS if _ not in list(reserved_attrs_map.keys())]
294
- formatter = jsonlogger.JsonFormatter(custom_format, reserved_attrs=reserved_attrs, rename_fields=reserved_attrs_map)
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(msg, '{"error.type": null, "error.message": null, "log.origin.function": "test_rename_reserved_attrs", "log.level": "INFO", "log.origin.file.name": "tests", "process.name": "MainProcess", "process.thread.name": "MainThread", "log.message": "message"}\n')
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("name", level=1, pathname="", lineno=1, msg="Some message", args=None, exc_info=None)
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
- self.assertEquals(output["foo"], "bar")
307
- self.assertEquals(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()
308
+ self.assertEqual(output["foo"], "bar")
309
+ self.assertEqual(output["msg"], "Some message")
@@ -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.6",
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={"src/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
- )