Metadata-Version: 2.4
Name: certlib-log
Version: 1.0.0b1
Summary: A library extending the standard logging toolbox (e.g., facilitating structured logging with minimal fuss).
Maintainer-email: Jan Kaliszewski <jan.kaliszewski@cert.pl>
License-Expression: BSD-3-Clause
Project-URL: Homepage, https://github.com/CERT-Polska/certlib-log
Project-URL: Documentation, https://certlib-log.readthedocs.io/
Project-URL: Repository, https://github.com/CERT-Polska/certlib-log.git
Project-URL: Issues, https://github.com/CERT-Polska/certlib-log/issues
Project-URL: Changelog, https://github.com/CERT-Polska/certlib-log/blob/main/CHANGELOG.md
Keywords: logging,structured logging,formatting,library
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Logging
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Provides-Extra: dev
Requires-Dist: ast-serialize==0.3.0; extra == "dev"
Requires-Dist: babel==2.18.0; extra == "dev"
Requires-Dist: backrefs==7.0; extra == "dev"
Requires-Dist: black==26.3.1; extra == "dev"
Requires-Dist: build==1.5.0; extra == "dev"
Requires-Dist: certifi==2026.4.22; extra == "dev"
Requires-Dist: charset-normalizer==3.4.7; extra == "dev"
Requires-Dist: click==8.3.3; extra == "dev"
Requires-Dist: colorama==0.4.6; extra == "dev"
Requires-Dist: exceptiongroup==1.3.1; extra == "dev"
Requires-Dist: ghp-import==2.1.0; extra == "dev"
Requires-Dist: griffelib==2.0.2; extra == "dev"
Requires-Dist: idna==3.13; extra == "dev"
Requires-Dist: iniconfig==2.3.0; extra == "dev"
Requires-Dist: jinja2==3.1.6; extra == "dev"
Requires-Dist: librt==0.10.0; extra == "dev"
Requires-Dist: markdown==3.10.2; extra == "dev"
Requires-Dist: markupsafe==3.0.3; extra == "dev"
Requires-Dist: mergedeep==1.3.4; extra == "dev"
Requires-Dist: mkdocs==1.6.1; extra == "dev"
Requires-Dist: mkdocs-autorefs==1.4.4; extra == "dev"
Requires-Dist: mkdocs-get-deps==0.2.2; extra == "dev"
Requires-Dist: mkdocs-material==9.7.6; extra == "dev"
Requires-Dist: mkdocs-material-extensions==1.3.1; extra == "dev"
Requires-Dist: mkdocstrings==1.0.4; extra == "dev"
Requires-Dist: mkdocstrings-python==2.0.3; extra == "dev"
Requires-Dist: mypy==2.0.0; extra == "dev"
Requires-Dist: mypy-extensions==1.1.0; extra == "dev"
Requires-Dist: packaging==26.2; extra == "dev"
Requires-Dist: paginate==0.5.7; extra == "dev"
Requires-Dist: pathspec==1.1.1; extra == "dev"
Requires-Dist: pip-tools==7.5.3; extra == "dev"
Requires-Dist: platformdirs==4.9.6; extra == "dev"
Requires-Dist: pluggy==1.6.0; extra == "dev"
Requires-Dist: pygments==2.20.0; extra == "dev"
Requires-Dist: pymdown-extensions==10.21.2; extra == "dev"
Requires-Dist: pyproject-hooks==1.2.0; extra == "dev"
Requires-Dist: pytest==9.0.3; extra == "dev"
Requires-Dist: python-dateutil==2.9.0.post0; extra == "dev"
Requires-Dist: pytokens==0.4.1; extra == "dev"
Requires-Dist: pyyaml==6.0.3; extra == "dev"
Requires-Dist: pyyaml-env-tag==1.1; extra == "dev"
Requires-Dist: requests==2.33.1; extra == "dev"
Requires-Dist: setuptools-scm==10.0.5; extra == "dev"
Requires-Dist: six==1.17.0; extra == "dev"
Requires-Dist: tomli==2.4.1; extra == "dev"
Requires-Dist: typing-extensions==4.15.0; extra == "dev"
Requires-Dist: urllib3==2.7.0; extra == "dev"
Requires-Dist: vcs-versioning==1.1.1; extra == "dev"
Requires-Dist: watchdog==6.0.0; extra == "dev"
Requires-Dist: wheel==0.47.0; extra == "dev"
Requires-Dist: pip==26.1.1; extra == "dev"
Requires-Dist: setuptools==82.0.1; extra == "dev"
Dynamic: license-file

# `certlib.log`

...is a library that extends the standard [`logging`](https://docs.python.org/3/library/logging.html)
toolset. Among other things, it makes it possible to introduce
*structured logging* with minimal fuss, and/or to start using the
modern `{}`-based style of log message formatting (gradually if
required).


## Basic Info

- **Documentation:** [certlib-log.readthedocs.io](https://certlib-log.readthedocs.io)
- **Home page:** [github.com/CERT-Polska/certlib-log](https://github.com/CERT-Polska/certlib-log)
- **Contributing:** [github.com/CERT-Polska/certlib-log/pulls](https://github.com/CERT-Polska/certlib-log/pulls)

You can install the [`certlib.log`](https://pypi.org/project/certlib-log/)
library by running (typically, in a [*virtual environment*](https://packaging.python.org/en/latest/tutorials/installing-packages/#creating-virtual-environments))
the command: **`python3 -m pip install certlib.log`**

The library is compatible with Python 3.10 and all newer versions of
Python. It uses *only* the Python standard library, i.e., it **does
*not* depend on any third-party packages**.


## Examples

### Configuring *Structured Logging* and *Auto-Makers*

```python
import logging.config

logging.config.dictConfig({
    "formatters": {
        "structured": {
            "()": "certlib.log.StructuredLogsFormatter",
            "defaults": {
                # Each key in this dict should be an *output data* key.
                # Each value should specify the respective *default value*.
                "system": "MyExample",
                "component": "MyAPI",
                "component_type": "web"
            },
            "auto_makers": {
                # Each key in this dict should be an *output data* key.
                # Each value should specify an *argumentless callable*
                # (for example, the `get()` method of some `ContextVar`).
                "client_ip": "myexample.myapi.client_ip_context_var.get",
                "nano_time": "time.time_ns"
            }
        }
    },
    "handlers": {
        "stderr": {
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stderr",
            "formatter": "structured"
        }
    },
    "root": {
        "level": "INFO",
        "handlers": ["stderr"]
    },
    "disable_existing_loggers": False,
    "version": 1
})
```

### Logging Stuff With *`{}`-Formatted Text Message* or *No Text Message*

```python
import datetime as dt
import ipaddress
import logging
from certlib.log import xm   # Note: `xm` is short for `ExtendedMessage`

logger = logging.getLogger(__name__)

...

def example_with_text_message_formatting(city, humidity, error_summary=None):
    if error_summary:
        logger.error(xm(
            'An error occurred: {!r}', error_summary,
            exc_info=True, stack_info=True, stacklevel=2,
        ))

    logger.warning(xm('Humidity in {} is {:.1%}', city, humidity))

    logger.info(xm(
        # (Here: making use of `datetime`-specific format codes...)
        'Today is day #{today:%j} of the year {today:%Y}',
        today=dt.date.today(),

        # Arbitrary data items can also be given (which is especially
        # useful when `certlib.log.StructuredLogsFormatter` is in use).
        some_extra_item=42,
        other_arbitrary_stuff={'foo': [
            {'my-ip': ipaddress.IPv4Address('192.168.0.1')},
            dt.time(12, 59),
        ]},
    ))

def example_with_no_text(temperature, pressure, debug_data_dict, calm=True):
    # (The possibility to focus on pure data, *without* the need
    # to pass any *text-message*-related arguments, is especially
    # handy when `certlib.log.StructuredLogsFormatter` is in use.)

    if calm:
        logger.info(xm(
            # Just data:
            temperature=temperature,
            pressure=pressure,
        ))
    else:
        logger.error(xm(
            # Just data:
            temperature=temperature,
            pressure=pressure,

            # Special arguments:
            exc_info=True,
            stack_info=True,
            stacklevel=2,
        ))

    # Single dict providing data is also OK:
    logger.debug(xm(debug_data_dict))
```

You can find more examples in the [User's Guide](https://certlib-log.readthedocs.io/en/latest/guide/).


## Copyright and License

Copyright (c) 2026, [CERT Polska](https://cert.pl/en/). All rights reserved.

The [`certlib.log`](https://github.com/CERT-Polska/certlib-log) library
is free software; you can redistribute and/or modify it under the terms
of the *BSD 3-Clause "New" or "Revised" License* (see the [`LICENSE.txt`](https://github.com/CERT-Polska/certlib-log/blob/main/LICENSE.txt)
file in the source code repository).
