Metadata-Version: 2.4
Name: python-devops-logging-decorators
Version: 0.1.3
Summary: Factory-based Python logging decorators by handler and level
Author: wilso
License-Expression: Apache-2.0
Project-URL: Homepage, https://bitbucket.org/ssw1991/python_devops
Project-URL: Repository, https://bitbucket.org/ssw1991/python_devops
Project-URL: Documentation, https://bitbucket.org/ssw1991/python_devops
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
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: Topic :: Software Development :: Libraries
Classifier: Topic :: System :: Logging
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs>=1.6.0; extra == "docs"
Requires-Dist: mkdocs-material>=9.6.0; extra == "docs"
Requires-Dist: mkdocstrings[python]>=0.30.0; extra == "docs"
Dynamic: license-file

# Logging Decorators
A small Python library that uses a **factory pattern** to build function decorators for logging.

You get:

- Level decorators (`@debug`, `@info`, ...)
- Handler decorators (`@stream`, `@file`, `@rotating_file`, `@timed_rotating_file`)
- Per-handler + per-level decorators (`@debug_stream`, `@error_file`, `@info_rotating_file`, ...)

## Install (editable)

```bash
pip install -e .
```

## Install from PyPI

```bash
pip install python-devops-logging-decorators
```

Import path remains:

```python
import logging_decorators
```

## Documentation site

This project uses **MkDocs Material** for documentation.

Install the docs extras and run the docs site locally:

```bash
pip install -e .[docs]
mkdocs serve
```

The docs site lives in the `docs/` folder and is configured by `mkdocs.yml`.

## Quick start

```python
from logging_decorators import info, debug_stream, error_file


@info
def add(a: int, b: int) -> int:
    return a + b


@debug_stream
def multiply(a: int, b: int) -> int:
    return a * b


@error_file(filename="errors.log")
def will_fail() -> None:
    raise RuntimeError("boom")


@error_file(
    filename="errors.log",
    formatter="%(levelname)s :: %(message)s",
)
def will_fail_with_custom_format() -> None:
    raise RuntimeError("boom")
```

## Factory usage

```python
from logging_decorators import LoggingDecoratorFactory

factory = LoggingDecoratorFactory(logger_name="my_app")

custom = factory.create(
    handler="file",
    level="WARNING",
    filename="app.log",
)


@custom
def run() -> None:
    print("running")
```

The default formatter is text-based:

`%(asctime)s | %(levelname)s | %(name)s | %(message)s`

You can pass either:

- a format string (for example `formatter="%(levelname)s :: %(message)s"`)
- a `logging.Formatter` instance

You can also use a structured JSON preset:

- `formatter_preset="json"`

### Optional runtime metadata features

You can enable timing, argument logging (with redaction), and context injection.

```python
from logging_decorators import error_file


@error_file(
    filename="pipeline.log",
    formatter="%(correlation_id)s | %(pipeline)s | %(message)s",
    log_duration=True,
    log_arguments=True,
    redact_fields=["password", "token"],
    correlation_id="deploy-2026-06-13",
    extra={"pipeline": "release"},
)
def deploy(password: str, token: str) -> None:
    raise RuntimeError("deploy failed")
```

Argument logging is configured **per decorator**, so you can enable it only where needed:

```python
from logging_decorators import info_file


@info_file(
    filename="users.log",
    log_arguments=True,
    redact_fields=["password"],
)
def create_user(username: str, password: str) -> None:
    print(f"creating user {username}")
```

That decorator will log the call with arguments, but the password value will be redacted.

Run a small per-decorator arguments demo:

```bash
python examples/per_decorator_args_demo.py
```

It shows one decorator with `log_arguments=True` and another without it.

### Structured JSON logs

```python
from logging_decorators import error_file


@error_file(
    filename="structured.log",
    formatter_preset="json",
    correlation_id="corr-42",
    extra={"pipeline": "release"},
)
def run_job() -> None:
    raise RuntimeError("job failed")
```

## Demo

Run the formatter demo:

```bash
python examples/formatter_demo.py
```

It writes to `examples/formatter_demo_<timestamp>.log` and demonstrates both formatter styles.

Run the stream-only formatter demo:

```bash
python examples/stream_formatter_demo.py
```

It prints both formatter styles directly to the console.

Run the advanced features demo:

```bash
python examples/advanced_features_demo.py
```

It demonstrates timing, argument redaction, context injection, and JSON output together.

## Available generated decorators

### By level (stream handler)

- `debug`
- `info`
- `warning`
- `error`
- `critical`

### By handler (level defaults to `INFO`)

- `stream`
- `file`
- `rotating_file`
- `timed_rotating_file`

### By level + handler

For each level and each handler, decorators are generated with:

`<level>_<handler>`

Examples:

- `debug_stream`
- `info_file`
- `warning_rotating_file`
- `error_timed_rotating_file`

All named decorators are explicitly defined in
`src/logging_decorators/decorators.py` for easy discovery/navigation.

## Create your own named decorators

You can create project-specific decorator names with `LoggingDecoratorFactory`.

For most new code, prefer passing a `DecoratorOptions` instance to `create(...)` when you want to reuse the same runtime behavior settings.

### Option 1: simple alias in your module

```python
from logging_decorators import LoggingDecoratorFactory

factory = LoggingDecoratorFactory(logger_name="orders")

# Named decorator for this module
audit_error = factory.create(
    handler="file",
    level="ERROR",
    filename="audit.log",
)


@audit_error
def charge_customer() -> None:
    raise RuntimeError("payment failed")
```

### Option 2: shared decorators module for your app

Create `my_decorators.py` in your project:

```python
import logging

from logging_decorators import LoggingDecoratorFactory

factory = LoggingDecoratorFactory(logger_name="my_app")

db_warning = factory.create(
    handler="rotating_file",
    level="WARNING",
    filename="db.log",
    max_bytes=1_000_000,
    backup_count=5,
)

api_error = factory.create(
    handler="file",
    level="ERROR",
    filename="api-errors.log",
    formatter=logging.Formatter("%(levelname)s :: %(message)s"),
)
```

Then use them anywhere:

```python
from my_decorators import api_error, db_warning


@db_warning
def fetch_user() -> None:
    ...


@api_error
def process_request() -> None:
    raise RuntimeError("request failed")
```

Run a complete custom-named decorators example:

```bash
python examples/custom_named_decorators.py
```

Run a demo that uses `DecoratorOptions` directly:

```bash
python examples/decorator_options_demo.py
```

It shows reusable per-decorator settings for argument logging, redaction, timing, and context.

Run a combined advanced `DecoratorOptions` demo:

```bash
python examples/decorator_options_advanced_demo.py
```

It shows JSON formatting, duration logging, argument redaction, and context injection in one example.

## Compatibility helper

`build_named_decorators(...)` remains available as a compatibility helper for projects that want the old dynamic generation pattern.

## License

This project is licensed under the Apache License 2.0.

See [LICENSE](LICENSE).

Additional attributions and notices are documented in [NOTICE](NOTICE).

For publishing steps, see the docs page: `docs/release-checklist.md`.
