Metadata-Version: 2.5
Name: tjzegmott-python-logging-loki
Version: 0.1.0
Summary: Python logging handler for Grafana Loki
Project-URL: Homepage, https://github.com/tjzegmott/python-logging-loki
Project-URL: Documentation, https://tjzegmott.github.io/python-logging-loki
Project-URL: Repository, https://github.com/tjzegmott/python-logging-loki
Project-URL: Issues, https://github.com/tjzegmott/python-logging-loki/issues
Project-URL: Changelog, https://github.com/tjzegmott/python-logging-loki/blob/main/CHANGELOG.md
Author-email: Tarik Zegmott <tzegmott@gmail.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
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: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Logging
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: requests>=2.32.4
Requires-Dist: rfc3339>=6.1
Description-Content-Type: text/markdown

# 🚀 tjzegmott-python-logging-loki

[![CI](https://github.com/tjzegmott/python-logging-loki/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/tjzegmott/python-logging-loki/actions/workflows/continuous-integration.yml)
[![PyPI version](https://badge.fury.io/py/tjzegmott-python-logging-loki.svg)](https://badge.fury.io/py/tjzegmott-python-logging-loki)
[![codecov](https://codecov.io/gh/tjzegmott/python-logging-loki/branch/main/graph/badge.svg)](https://codecov.io/gh/tjzegmott/python-logging-loki)
[![Python](https://img.shields.io/badge/python-3.8.1+-blue.svg)](https://www.python.org/)
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![ty](https://img.shields.io/badge/type--checked-ty-blue?labelColor=orange)](https://github.com/astral-sh/ty)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/tjzegmott/python-logging-loki/blob/main/LICENSE)

Send Python logs directly to [Grafana Loki](https://grafana.com/loki) with minimal configuration.

|   What   |                            Where                            |
| :------: | :---------------------------------------------------------: |
|  Source  |     <https://github.com/tjzegmott/python-logging-loki>      |
|   PyPI   |         `pip install tjzegmott-python-logging-loki`         |
| Releases | <https://github.com/tjzegmott/python-logging-loki/releases> |

---

## ✨ Features

- 📤 **Direct Integration** - Send logs straight to Loki
- 🔐 **Authentication Support** - Basic auth and custom headers
- 🏷️ **Custom Labels** - Flexible tagging system
- ⚡ **Async Support** - Non-blocking queue handler included
- 🔒 **SSL Verification** - Configurable SSL/TLS settings
- 🎯 **Multi-tenant** - Support for Loki multi-tenancy

---

## 📦 Installation

```bash
pip install tjzegmott-python-logging-loki
```

Or using uv (recommended):

```bash
uv add logging_loki

```

---

## 🎯 Quick Start

### Basic Usage

```python
import logging
import logging_loki

handler = logging_loki.LokiHandler(
    url="https://loki.example.com/loki/api/v1/push",
    tags={"app": "my-application"},
    auth=("username", "password"),
    version="2"
)

logger = logging.getLogger("my-app")
logger.addHandler(handler)
logger.info("Application started", extra={"tags": {"env": "production"}})
```

### Async/Non-blocking Mode

For high-throughput applications, use the queue handler to avoid blocking:

```python
import logging.handlers
import logging_loki
from multiprocessing import Queue

handler = logging_loki.LokiQueueHandler(
    Queue(-1),
    url="https://loki.example.com/loki/api/v1/push",
    tags={"app": "my-application"},
    version="2"
)

logger = logging.getLogger("my-app")
logger.addHandler(handler)
logger.info("Non-blocking log message")
```

---

## ⚙️ Configuration Options

| Parameter    | Type    | Default    | Description                                   |
| ------------ | ------- | ---------- | --------------------------------------------- |
| `url`        | `str`   | _required_ | Loki push endpoint URL                        |
| `tags`       | `dict`  | `{}`       | Default labels for all logs                   |
| `auth`       | `tuple` | `None`     | Basic auth credentials `(username, password)` |
| `headers`    | `dict`  | `None`     | Custom HTTP headers (e.g., for multi-tenancy) |
| `version`    | `str`   | `"1"`      | Loki API version (`"0"`, `"1"`, or `"2"`)     |
| `verify_ssl` | `bool`  | `True`     | Enable/disable SSL certificate verification   |
| `suppress_errors` | `bool` | `False` | Silently swallow delivery failures instead of printing the standard logging `--- Logging error ---` traceback |

---

## 🚨 Error Handling

By default, if a log record can't be delivered to Loki (network failure, TLS error,
or an unexpected HTTP status code such as `405 Method Not Allowed`), Python's standard
logging machinery prints a `--- Logging error ---` traceback to stderr for every failed
record (see [`logging.Handler.handleError`](https://docs.python.org/3/library/logging.html#logging.Handler.handleError)).

A `405` typically means the request never reached Loki's push endpoint as a `POST` -
check for things like an `http://` → `https://` redirect, a reverse proxy/ingress that
only allows `GET` on that path, or a URL that doesn't end in `/loki/api/v1/push`. Test
with `curl -X POST <url>` to confirm the endpoint accepts `POST` requests directly.

If you'd rather not have delivery failures spam your application logs while you
investigate (or you're fine losing occasional log lines), set `suppress_errors=True`:

```python
handler = logging_loki.LokiHandler(
    url="https://loki.example.com/loki/api/v1/push",
    tags={"app": "my-application"},
    version="2",
    suppress_errors=True,
)
```

The handler still closes/resets its HTTP session on failure so subsequent attempts
start clean; it just skips the noisy stderr traceback.

---

## 🏷️ Labels

Logs are automatically labeled with:

- **severity** - Log level (INFO, ERROR, etc.)
- **logger** - Logger name
- **Custom tags** - From handler and `extra={"tags": {...}}`

```python
logger.error(
    "Database connection failed",
    extra={"tags": {"service": "api", "region": "us-east"}}
)
```

---

## 🔐 Multi-tenant Setup

```python
handler = logging_loki.LokiHandler(
    url="https://loki.example.com/loki/api/v1/push",
    headers={"X-Scope-OrgID": "tenant-1"},
    tags={"app": "my-app"}
)
```

---

## Development

### Prerequisites

- Python 3.8+
- [uv](https://docs.astral.sh/uv/) for package management

### Setup

```bash
git clone https://github.com/tjzegmott/python-logging-loki.git
cd python-logging-loki
make install
```

### Running Tests

```bash
make test

# With coverage
make test-cov

# Across all Python versions
make test-matrix
```

### Code Quality

```bash
# Run all checks (lint, format, type-check)
make verify

# Auto-fix lint and format issues
make fix
```

### Prek

```bash
prek install
prek run --all-files
```

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Acknowledgements

Based on [python-logging-loki](https://github.com/GreyZmeem/python-logging-loki) by GreyZmeem.
