Repository: Colin-b/logging_json (language: python)

Issue:
Dict configuration example is broken
Executing dict configuratio example yields following exception:
```
Traceback (most recent call last):
  File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/config.py", line 543, in configure
    formatters[name] = self.configure_formatter(
  File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/config.py", line 652, in configure_formatter
    if '()' in config:
TypeError: argument of type 'JSONFormatter' is not iterable

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/matus/test2.py", line 13, in <module>
    logging.config.dictConfig({
  File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/config.py", line 809, in dictConfig
    dictConfigClass(config).configure()
  File "/usr/local/Cellar/python@3.9/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/config.py", line 546, in configure
    raise ValueError('Unable to configure '
ValueError: Unable to configure formatter 'json'
```
Fix typo in README.md



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..2359852
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,36 @@
+name: Release
+
+on:
+  push:
+    branches:
+      - master
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        python-version: ['3.6', '3.7', '3.8', '3.9', '3.10']
+
+    steps:
+    - uses: actions/checkout@v2
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v2
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        python -m pip install .[testing]
+    - name: Test with pytest
+      run: |
+        pytest --cov=logging_json --cov-fail-under=100 --cov-report=term-missing
+    - name: Create packages
+      run: |
+        python -m pip install wheel
+        python setup.py sdist bdist_wheel
+    - name: Publish packages
+      run: |
+        python -m pip install twine
+        python -m twine upload dist/* --skip-existing --username __token__ --password ${{ secrets.pypi_password }}
\ No newline at end of file
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 8e38558..361d202 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,5 +1,5 @@
 repos:
   - repo: https://github.com/psf/black
-    rev: 21.9b0
+    rev: 21.11b1
     hooks:
       - id: black
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index a8ee29e..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: python
-python:
-  - "3.6"
-  - "3.7"
-  - "3.8"
-  - "3.9"
-  - "3.10-dev"
-install:
-  - pip install .[testing]
-script:
-  - pytest --cov=logging_json --cov-fail-under=100
-deploy:
-  provider: pypi
-  username: __token__
-  edge: true
-  distributions: "sdist bdist_wheel"
-  skip_existing: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 041478e..3f13c1a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+## [0.2.0] - 2021-11-24
+### Added
+- Added `message_field_name` parameter.
+
 ## [0.1.0] - 2021-10-04
 ### Fixed
 - Handle `extra` logging parameter.
@@ -14,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Added
 - Public release.
 
-[Unreleased]: https://github.com/Colin-b/healthpy/compare/v0.1.0...HEAD
+[Unreleased]: https://github.com/Colin-b/healthpy/compare/v0.2.0...HEAD
+[0.2.0]: https://github.com/Colin-b/healthpy/compare/v0.1.0...v0.2.0
 [0.1.0]: https://github.com/Colin-b/healthpy/compare/v0.0.1...v0.1.0
 [0.0.1]: https://github.com/Colin-b/healthpy/releases/tag/v0.0.1
diff --git a/README.md b/README.md
index af45d7f..fdd165e 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,10 @@
 
 <p align="center">
 <a href="https://pypi.org/project/logging_json/"><img alt="pypi version" src="https://img.shields.io/pypi/v/logging_json"></a>
-<a href="https://travis-ci.com/Colin-b/logging_json"><img alt="Build status" src="https://api.travis-ci.com/Colin-b/logging_json.svg?branch=master"></a>
-<a href="https://travis-ci.com/Colin-b/logging_json"><img alt="Coverage" src="https://img.shields.io/badge/coverage-100%25-brightgreen"></a>
+<a href="https://github.com/Colin-b/logging_json/actions"><img alt="Build status" src="https://github.com/Colin-b/logging_json/workflows/Release/badge.svg"></a>
+<a href="https://github.com/Colin-b/logging_json/actions"><img alt="Coverage" src="https://img.shields.io/badge/coverage-100%25-brightgreen"></a>
 <a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
-<a href="https://travis-ci.com/Colin-b/logging_json"><img alt="Number of tests" src="https://img.shields.io/badge/tests-15 passed-blue"></a>
+<a href="https://github.com/Colin-b/logging_json/actions"><img alt="Number of tests" src="https://img.shields.io/badge/tests-17 passed-blue"></a>
 <a href="https://pypi.org/project/logging_json/"><img alt="Number of downloads" src="https://img.shields.io/pypi/dm/logging_json"></a>
 </p>
 
@@ -33,7 +33,7 @@ It must be a dictionary where keys are the keys to be appended to the resulting
 
 #### Logging exceptions, a specific case
 
-If an exception is loggued, the `exception` key will be appended to the resulting JSON dictionary.
+If an exception is logged, the `exception` key will be appended to the resulting JSON dictionary.
 
 This dictionary will contains 3 keys:
 * `type`: The name of the exception class (useful when the message is blank).
@@ -56,6 +56,7 @@ The resulting JSON dictionary will be the one you provided (with the [additional
 
 Anything not logged using a dictionary will be handled by the standard formatter and it can result in one of the 2 output:
 * A JSON dictionary, if [additional fields](#adding-additional-fields-and-values) are set or if `extra` parameter is used while logging, with the message available in the `msg` key of the resulting JSON dictionary.
+  Default `msg` key name can be changed by `message_field_name` parameter of the `logging_json.JSONFormatter` instance.
 * The formatted record, if no [additional fields](#adding-additional-fields-and-values) are set. 
 
 This handles the usual string logging as in the following:
@@ -88,24 +89,25 @@ You can configure your logging as advertise by python, by using the `logging.con
 
 ```python
 import logging.config
-import logging_json
-import sys
-
-formatter = logging_json.JSONFormatter(fields={
-    "level_name": "levelname",
-    "thread_name": "threadName",
-    "process_name": "processName"
-})
-handler = logging.StreamHandler(stream=sys.stdout)
-handler.setFormatter(formatter)
 
 logging.config.dictConfig({
     "version": 1,
     "formatters": {
-        "json": formatter
+        "json": {
+            '()': 'logging_json.JSONFormatter',
+            'fields':{
+                "level_name": "levelname",
+                "thread_name": "threadName",
+                "process_name": "processName"
+            }
+        }
     },
     "handlers": {
-        "standard_output": handler,
+        "standard_output": {
+            'class': 'logging.StreamHandler',
+            'formatter': 'json',
+            'stream': 'ext://sys.stdout'
+        },
     },
     "loggers": {
         "my_app": {"level": "DEBUG"}
diff --git a/logging_json/_formatter.py b/logging_json/_formatter.py
index 6ee7d92..01336e6 100644
--- a/logging_json/_formatter.py
+++ b/logging_json/_formatter.py
@@ -49,11 +49,18 @@ def _value(record: logging.LogRecord, field_name_or_value: Any) -> Any:
 
 
 class JSONFormatter(logging.Formatter):
-    def __init__(self, *args, fields: Dict[str, Any] = None, **kwargs):
+    def __init__(
+        self,
+        *args,
+        fields: Dict[str, Any] = None,
+        message_field_name: str = "msg",
+        **kwargs,
+    ):
         # Allow to provide any formatter setting (useful to provide a custom date format)
         super().__init__(*args, **kwargs)
         self.fields = fields or {}
         self.usesTime = lambda: "asctime" in self.fields.values()
+        self.message_field_name = message_field_name
 
     def format(self, record: logging.LogRecord):
         # Let python set every additional record field
@@ -66,7 +73,7 @@ def format(self, record: logging.LogRecord):
         if isinstance(record.msg, collections.abc.Mapping):
             message.update(record.msg)
         else:
-            message["msg"] = super().formatMessage(record)
+            message[self.message_field_name] = super().formatMessage(record)
 
         message.update(_extra_attributes(record))
 
@@ -79,7 +86,7 @@ def format(self, record: logging.LogRecord):
 
         return (
             super().formatMessage(record)
-            if (len(message) == 1 and "msg" in message)
+            if (len(message) == 1 and self.message_field_name in message)
             else json.dumps(message)
         )
 
diff --git a/logging_json/version.py b/logging_json/version.py
index 43c94ee..03431df 100644
--- a/logging_json/version.py
+++ b/logging_json/version.py
@@ -3,4 +3,4 @@
 # Major should be incremented in case there is a breaking change. (eg: 2.5.8 -> 3.0.0)
 # Minor should be incremented in case there is an enhancement. (eg: 2.5.8 -> 2.6.0)
 # Patch should be incremented in case there is a bug fix. (eg: 2.5.8 -> 2.5.9)
-__version__ = "0.1.0"
+__version__ = "0.2.0"
diff --git a/setup.py b/setup.py
index 3642b75..a18d42a 100644
--- a/setup.py
+++ b/setup.py
@@ -29,6 +29,7 @@
         "Programming Language :: Python :: 3.7",
         "Programming Language :: Python :: 3.8",
         "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
         "Topic :: Software Development :: Build Tools",
     ],
     keywords=["logging", "json"],
@@ -37,7 +38,7 @@
     extras_require={
         "testing": [
             # Used to check coverage
-            "pytest-cov==2.*",
+            "pytest-cov==3.*",
         ]
     },
     python_requires=">=3.6",


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..6d5cf5a
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,25 @@
+name: Test
+
+on: [push]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        python-version: ['3.6', '3.7', '3.8', '3.9', '3.10']
+
+    steps:
+    - uses: actions/checkout@v2
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v2
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        python -m pip install .[testing]
+    - name: Test with pytest
+      run: |
+        pytest --cov=logging_json --cov-fail-under=100 --cov-report=term-missing
\ No newline at end of file
diff --git a/tests/test_formatter.py b/tests/test_formatter.py
index 313a5e0..6410a77 100644
--- a/tests/test_formatter.py
+++ b/tests/test_formatter.py
@@ -33,12 +33,26 @@ def test_str_with_args_message(caplog):
     assert fmt(caplog) == "message 1"
 
 
+def test_str_with_message_field_name(caplog):
+    caplog.set_level("INFO")
+    logging.info("message 1")
+    assert fmt(caplog, message_field_name="message") == "message 1"
+
+
 def test_str_with_extra_message(caplog):
     caplog.set_level("INFO")
     logging.info("message 1", extra={"key1": "value 1"})
     assert dict_fmt(caplog) == {"msg": "message 1", "key1": "value 1"}
 
 
+def test_str_with_message_field_name_and_fields(caplog):
+    caplog.set_level("INFO")
+    logging.info("message 1")
+    assert dict_fmt(
+        caplog, message_field_name="message", fields={"level": "levelname"}
+    ) == {"message": "message 1", "level": "INFO"}
+
+
 def test_str_with_args_and_extra_message(caplog):
     caplog.set_level("INFO")
     logging.info("message %s", "1", extra={"key1": "value 1"})