Metadata-Version: 2.4
Name: fastapi-logview
Version: 0.1.0
Summary: Structured logging for FastAPI — JSON Lines daily files and a built-in log viewer
Author: OmarGC
License: MIT
Project-URL: Homepage, https://github.com/omargc/fastapi-logview
Project-URL: Repository, https://github.com/omargc/fastapi-logview
Project-URL: Bug Tracker, https://github.com/omargc/fastapi-logview/issues
Keywords: fastapi,logging,structured-logging,observability,jsonlines
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
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: Framework :: FastAPI
Classifier: Topic :: System :: Logging
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastapi>=0.110.0
Requires-Dist: structlog>=24.0.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: uvicorn>=0.29.0; extra == "dev"
Dynamic: license-file

# fastapi-logview

**Structured logging for FastAPI.** Drop-in plugin that adds JSON Lines file logging, automatic request correlation, and a built-in log viewer — zero infrastructure required.

```python
from fastapi import FastAPI
from fastapi_logview import get_log, setup_fastapi_logview

app = FastAPI()
setup_fastapi_logview(app, service_name="my-api", environment="dev")

logger = get_log("my-api")

@app.get("/orders/{order_id}")
def get_order(order_id: str):
    logger.info("order fetched", order_id=order_id, user_id=42)
    return {"order_id": order_id}
```

Open `http://localhost:8000/logs` — your logs are already there.

![fastapi-logview viewer](docs/assets/viewer.png)

For AI assistants/agents, see `LLMS.txt` for project-specific guidance.

---

## Why fastapi-logview

Most logging setups in FastAPI require wiring `structlog` or `loguru` by hand, building a custom middleware, and setting up a separate log viewer. **fastapi-logview gives you all of that in one `setup_fastapi_logview()` call.**

- No external services. No Elasticsearch, no Grafana, no Loki.
- Every log event is a JSON line in a local file — simple to read, grep, ship, or archive.
- The viewer is part of your app. Useful in staging and dev; disable it in prod with one flag.

---

## Install

```bash
pip install fastapi-logview
```

Requires Python 3.10+ and FastAPI 0.110+.

---

## Features

- **Structured JSON Lines** — daily log files at `logs/YYYY-MM-DD.log`, one event per line
- **Automatic request correlation** — every log emitted during a request is tagged with the same `request_id`
- **Built-in log viewer** — filter by level, request, user, trace ID or free-text search at `/logs`
- **Request logging middleware** — auto-captures method, path, status code and duration for every request
- **Timezone-aware display** — store in UTC, display in any IANA timezone
- **Viewer auth** — protect `/logs` with HTTP Basic Auth or an IP allowlist
- **Lightweight** — depends only on FastAPI, Pydantic and structlog
- **100% local** — your logs never leave your server. No data is sent to any external service, not even to the author. Everything stays in your `logs/` directory.

---

## Quickstart

### Minimal

```python
from fastapi import FastAPI
from fastapi_logview import get_log, setup_fastapi_logview

app = FastAPI()
setup_fastapi_logview(app, service_name="payments-api", environment="dev")

logger = get_log("payments")

@app.post("/pay")
def pay(amount: int):
    logger.info("payment initiated", amount=amount)
    return {"status": "ok"}
```

### With custom timezone

```python
setup_fastapi_logview(
    app,
    service_name="payments-api",
    environment="dev",
    display_timezone="America/New_York",
)
```

### Production — disable the viewer

```python
setup_fastapi_logview(
    app,
    service_name="payments-api",
    environment="prod",
    enable_ui=False,
)
```

---

## Log viewer

Mount path: `GET /logs` (configurable via `mount_path`).

| Endpoint | Description |
|---|---|
| `GET /logs` | Viewer UI |
| `GET /logs/api/files` | List available log files |
| `GET /logs/api/events` | Query events with filters |
| `GET /logs/api/events/{event_id}` | Single event detail |
| `GET /logs/api/requests/{request_id}` | All events for a request |
| `GET /logs/api/stats` | Aggregated counts by level |

**Query filters:** `level`, `request_id`, `trace_id`, `user_id`, `search`, `file`, `source`, `limit`, `offset`.

---

## Security

Protect the viewer with a FastAPI dependency passed to `viewer_auth_dependency`.

**HTTP Basic Auth:**

```python
from fastapi_logview.security import basic_auth_dependency

setup_fastapi_logview(
    app,
    service_name="payments-api",
    environment="prod",
    viewer_auth_dependency=basic_auth_dependency(
        username="admin",
        password="supersecret",
    ),
)
```

**IP allowlist:**

```python
from fastapi_logview.security import ip_allowlist_dependency

setup_fastapi_logview(
    app,
    service_name="payments-api",
    environment="prod",
    viewer_auth_dependency=ip_allowlist_dependency(
        allowed_ips=["127.0.0.1"],
        allowed_cidrs=["10.0.0.0/24"],
        trust_proxy_headers=True,
    ),
)
```

You can pass any FastAPI dependency — use your existing auth system if you have one.

---

## Configuration reference

`setup_fastapi_logview(app, **options)`

| Parameter | Type | Default | Description |
|---|---|---|---|
| `app` | `FastAPI` | — | FastAPI application instance |
| `service_name` | `str` | `"fastapi-service"` | Identifier written to every log event |
| `environment` | `str` | `"dev"` | Environment label (`dev`, `staging`, `prod`) |
| `mount_path` | `str` | `"/logs"` | Path where the viewer is mounted |
| `log_dir` | `str` | `"logs"` | Directory for daily `.log` files |
| `enable_ui` | `bool` | `True` | Mount the log viewer UI |
| `enable_request_logging` | `bool` | `True` | Log every HTTP request automatically |
| `return_request_id_header` | `bool` | `True` | Return `X-Request-ID` in responses |
| `display_timezone` | `str` | `"UTC"` | IANA timezone for the viewer (e.g. `"America/New_York"`) |
| `viewer_auth_dependency` | `Callable \| None` | `None` | FastAPI dependency to protect the viewer |
| `log_level` | `str` | `"INFO"` | Minimum level (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`) |
| `max_events_per_query` | `int` | `1000` | Max events returned per viewer API call |

---

## Log format

Each event is a single JSON line in `logs/YYYY-MM-DD.log`:

```json
{
  "timestamp": "2026-03-08T12:00:00.000000+00:00",
  "level": "INFO",
  "logger_name": "payments",
  "message": "payment initiated",
  "request_id": "01HX4K2J...",
  "service_name": "payments-api",
  "environment": "prod",
  "method": "POST",
  "path": "/pay",
  "status_code": 200,
  "duration_ms": 3.2,
  "amount": 150,
  "extra": {},
  "event_id": "01HX4K2J..."
}
```

All extra keyword arguments passed to `logger.info(...)` are included at the top level of the event.

---

## Request correlation

`fastapi-logview` middleware reads the incoming `X-Request-ID` header or generates a new one (UUID). Every log emitted during that request — regardless of which logger — carries the same `request_id`.

```python
# client sends:   X-Request-ID: my-trace-123
# all logs for that request will have:
{"request_id": "my-trace-123", ...}
```

---

## License

MIT — Copyright (c) 2026 OmarGC
