Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions .github/workflows/test-suite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:
name: "Python Lint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: astral-sh/setup-uv@v3
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0

- name: Lint with tox
run: uvx tox -e lint
Expand All @@ -34,8 +34,19 @@ jobs:
- macos-latest

steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v3
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0

- name: Test with tox
run: uvx tox

docs:
name: "Python Docs"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0

- name: Build docs with tox
run: uvx tox -e docs
97 changes: 97 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Configuration file for Sphinx documentation generator.
# Generated automatically by sphinx-mkdocs-migrate from plan: synthetic
import os
import sys
sys.path.insert(0, os.path.abspath('../src'))
sys.path.insert(0, os.path.abspath('..'))

project = 'Python JSON Logger'
copyright = 'Python JSON Logger Contributors'
author = 'Documentation Authors'

extensions = [
'myst_parser',
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx.ext.napoleon',
'sphinx_copybutton',
'sphinx_design',
'sphinx_immaterial',
]

source_suffix = {
'.md': 'markdown',
}

html_theme = 'sphinx_immaterial'
html_title = 'Python JSON Logger'
html_baseurl = 'https://nhairs.github.io/python-json-logger'
autosummary_generate = False
add_module_names = False
autoclass_content = 'both'
exclude_patterns = ['.DS_Store', 'Thumbs.db', '_build']

html_theme_options = { 'edit_uri': 'tree/master/docs',
'features': [ 'navigation.instant',
'navigation.sections',
'navigation.indexes',
'navigation.expand',
'navigation.top',
'content.code.annotate',
'content.code.copy',
'toc.follow'],
'globaltoc_collapse': False,
'icon': {'logo': 'material/code-braces'},
'palette': [ { 'primary': 'amber',
'scheme': 'default',
'toggle': { 'icon': 'material/weather-night',
'name': 'Switch to dark mode'}},
{ 'primary': 'amber',
'scheme': 'slate',
'toggle': { 'icon': 'material/weather-sunny',
'name': 'Switch to light mode'}}],
'repo_name': 'nhairs/python-json-logger',
'repo_url': 'https://github.com/nhairs/python-json-logger',
'site_url': 'https://nhairs.github.io/python-json-logger',
'social': [ { 'icon': 'fontawesome/brands/github',
'link': 'https://github.com/nhairs/python-json-logger'}],
'version_dropdown': True,
'version_json': 'versions.json'}

object_description_options = [
('py:.*', dict(include_fields_in_toc=False)),
('py:parameter', dict(include_in_toc=False)),
]

myst_enable_extensions = [
'colon_fence',
'deflist',
]

myst_heading_anchors = 3


import re
_re_md_link = re.compile(r'(?<![!])\[(?P<text>[^\]\n]+?)\]\((?P<url>[^\)\s]+)\)')
_re_cross_ref = re.compile(r'(?<![!])\[(?P<text>[^\]\n]+?)\]\[(?P<target>[a-zA-Z_0-9\.]+)\]')
_re_empty_cross_ref = re.compile(r'(?<![!])\[(?P<target>[a-zA-Z_0-9\.]+)\]\[\]')
_re_md_code = re.compile(r'(?<![:`])`(?P<code>[^`\n]+?)`(?!_|\`)')

def process_docstrings(app, what, name, obj, options, lines):
if what == 'module' and getattr(options, 'members', None):
lines.clear()
return
for i in range(len(lines)):
if '[' in lines[i] and '][' in lines[i]:
lines[i] = _re_empty_cross_ref.sub(r':py:obj:`\g<target>`', lines[i])
lines[i] = _re_cross_ref.sub(r':py:obj:`\g<text> <\g<target>>`', lines[i])
if '[' in lines[i] and '](' in lines[i]:
def repl(m):
clean_text = m.group('text').replace('`', '').strip()
return f'`{clean_text} <{m.group("url")}>`_'
lines[i] = _re_md_link.sub(repl, lines[i])
if '`' in lines[i]:
lines[i] = _re_md_code.sub(r'``\g<code>``', lines[i])

def setup(app):
app.connect('autodoc-process-docstring', process_docstrings)
13 changes: 7 additions & 6 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ mkdocs serve
# grip
```

!!! note
In general we will always squash merge pull requests so you do not need to worry about a "clean" commit history.
```{note}
In general we will always squash merge pull requests so you do not need to worry about a "clean" commit history.
```

### 3. Checklist

Expand Down Expand Up @@ -95,11 +96,11 @@ Your code will be reviewed by a maintainer.

If you're not familiar with code review start by reading [this guide](https://google.github.io/eng-practices/review/).

!!! tip "Remember you are not your work"

You might be asked to explain or justify your choices. This is not a criticism of your value as a person!
```{tip} Remember you are not your work
You might be asked to explain or justify your choices. This is not a criticism of your value as a person!

Often this is because there are multiple ways to solve the same problem and the reviewer would like to understand more about the way you solved.
Often this is because there are multiple ways to solve the same problem and the reviewer would like to understand more about the way you solved.
```

## Common Topics

Expand Down
6 changes: 4 additions & 2 deletions docs/cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class SillyFormatter(JsonFormatter):
```


(request-trace-ids)=
## Request / Trace IDs

There are many ways to add consistent request IDs to your logging. The exact method will depend on your needs and application.
Expand Down Expand Up @@ -211,8 +212,9 @@ ENVIRONMENT = os.environ.get('ENVIRONMENT', 'dev')

By the nature of Python's logging library, the JSON formatters will only ever run in handlers which are enabled for the given log level. This saves the performance hit of constructing JSON that is never used - but what about the data we pass into the logger? There are two options available to us: using if statements to avoid the call altogether, or using lazy string evaluation libraries.

!!! note
The below strategies will work for data passed in the `msg` and `extra` arguments.
```{note}
The below strategies will work for data passed in the `msg` and `extra` arguments.
```

To avoid the logging calls we use `logger.isEnabledFor` to ensure that we only start constructing our log messages if the logger is enabled:

Expand Down
15 changes: 14 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This library assumes that you are famliar with the `logging` standard library pa
## Features

- **Standard Library Compatible:** Implement JSON logging without modifying your existing log setup.
- **Supports Multiple JSON Encoders:** In addition to the standard libary's `json` module, also supports the [`orjson`][pythonjsonlogger.orjson], [`msgspec`][pythonjsonlogger.msgspec] JSON encoders.
- **Supports Multiple JSON Encoders:** In addition to the standard libary's `json` module, also supports the [`orjson`](reference/pythonjsonlogger/orjson.md), [`msgspec`](reference/pythonjsonlogger/msgspec.md) JSON encoders.
- **Fully Customizable Output Fields:** Control required, excluded, and static fields including automatically picking up custom attributes on `LogRecord` objects. Fields can be renamed before they are output.
- **Encode Any Type:** Encoders are customized to ensure that something sane is logged for any input including those that aren't supported by default. For example formatting UUID objects into their string representation and bytes objects into a base 64 encoded string.

Expand Down Expand Up @@ -70,3 +70,16 @@ This project was originally authored by [Zakaria Zajac](https://github.com/madza

It is currently maintained by:
- [Nicholas Hairs](https://github.com/nhairs) - [nicholashairs.com](https://www.nicholashairs.com)

```{toctree}
:hidden:
:maxdepth: 2

Home <self>
quickstart
cookbook
changelog
security
contributing
API Reference <reference/pythonjsonlogger/index>
```
30 changes: 17 additions & 13 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

## Installation

!!! note
All versions of this fork use version `>=3.0.0`.
```{note}
All versions of this fork use version `>=3.0.0`.

To use pre-fork versions use `python-json-logger<3`.
To use pre-fork versions use `python-json-logger<3`.
```

### Install via pip

Expand All @@ -24,7 +25,7 @@ pip install 'python-json-logger@https://github.com/nhairs/python-json-logger/rel

## Usage

Python JSON Logger provides [`logging.Formatter`](https://docs.python.org/3/library/logging.html#logging.Formatter) classes that encode the logged message into JSON. Although [a variety of JSON encoders are supported](#alternate-json-encoders), the following examples will use the [JsonFormatter][pythonjsonlogger.json.JsonFormatter] which uses the the `json` module from the standard library.
Python JSON Logger provides [`logging.Formatter`](https://docs.python.org/3/library/logging.html#logging.Formatter) classes that encode the logged message into JSON. Although [a variety of JSON encoders are supported](#alternate-json-encoders), the following examples will use the [JsonFormatter](reference/pythonjsonlogger/json.md) which uses the the `json` module from the standard library.

### Integrating with Python's logging framework

Expand Down Expand Up @@ -76,11 +77,13 @@ logger.info({
})
```

!!! warning
Be aware that if you log using a `dict`, other formatters may not be able to handle it.
```{warning}
Be aware that if you log using a `dict`, other formatters may not be able to handle it.
```

!!! note
Your `dict` is not modified when the formatter adds fields such as `exc_info`.
```{note}
Your `dict` is not modified when the formatter adds fields such as `exc_info`.
```

You can also add additional message fields using the `extra` argument.

Expand All @@ -94,7 +97,7 @@ logger.info(
)
```

Finally, any non-standard attributes added to a `LogRecord` will also be included in the logged data. See [Cookbook: Request / Trace IDs](cookbook.md#request-trace-ids) for an example.
Finally, any non-standard attributes added to a `LogRecord` will also be included in the logged data. See [Cookbook: Request / Trace IDs](request-trace-ids) for an example.

#### Default Fields

Expand Down Expand Up @@ -155,12 +158,13 @@ def my_default(obj):
formatter = JsonFormatter(json_default=my_default)
```

!!! note
When providing your own `json_default`, you likely want to call the original `json_default` for your encoder. Python JSON Logger provides custom default serializers for each encoder that tries very hard to ensure sane output is always logged.
```{note}
When providing your own `json_default`, you likely want to call the original `json_default` for your encoder. Python JSON Logger provides custom default serializers for each encoder that tries very hard to ensure sane output is always logged.
```

### Alternate JSON Encoders

The following JSON encoders are also supported:

- [orjson](https://github.com/ijl/orjson) - [pythonjsonlogger.orjson.OrjsonFormatter][]
- [msgspec](https://github.com/jcrist/msgspec) - [pythonjsonlogger.msgspec.MsgspecFormatter][]
- [orjson](https://github.com/ijl/orjson) - [OrjsonFormatter](reference/pythonjsonlogger/orjson.md)
- [msgspec](https://github.com/jcrist/msgspec) - [MsgspecFormatter](reference/pythonjsonlogger/msgspec.md)
48 changes: 48 additions & 0 deletions docs/reference/pythonjsonlogger/core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# pythonjsonlogger.core

```{eval-rst}
.. automodule:: pythonjsonlogger.core
:no-members:
```

```{eval-rst}
.. currentmodule:: pythonjsonlogger.core

.. rubric:: Classes

.. autosummary::
:nosignatures:

~BaseJsonFormatter

.. rubric:: Functions

.. autosummary::
:nosignatures:

~merge_record_extra

.. rubric:: Attributes

.. autosummary::
:nosignatures:

~LogData
~RESERVED_ATTRS
```

```{eval-rst}
.. currentmodule:: pythonjsonlogger.core

.. autodata:: LogData

.. autodata:: RESERVED_ATTRS

.. autoclass:: BaseJsonFormatter
:members:
:undoc-members:
:show-inheritance:
:inherited-members: Formatter

.. autofunction:: merge_record_extra
```
Loading
Loading