auditry


Nameauditry JSON
Version 0.2.1 PyPI version JSON
download
home_pageNone
SummaryObservability middleware for FastAPI and Quart with request/response logging, correlation IDs, and sensitive data redaction
upload_time2025-10-30 15:10:29
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseMIT
keywords fastapi quart observability logging middleware correlation-id redaction
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # auditry

A clean, framework-agnostic observability middleware for FastAPI and Quart that provides comprehensive request/response logging, correlation ID tracking, business event extraction, and sensitive data redaction.

[![PyPI version](https://badge.fury.io/py/auditry.svg)](https://badge.fury.io/py/auditry)
[![Python Versions](https://img.shields.io/pypi/pyversions/auditry.svg)](https://pypi.org/project/auditry/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Installation

### For FastAPI

```bash
pip install auditry[fastapi]
```

### For Quart

```bash
pip install auditry[quart]
```

### For both frameworks

```bash
pip install auditry[all]
```

## Quick Start

### FastAPI

```python
from fastapi import FastAPI
from auditry import configure_logging, ObservabilityConfig, get_logger
from auditry.fastapi import create_middleware

# Configure structured logging at startup
configure_logging(level="INFO")

app = FastAPI()

# Add observability middleware (single line!)
app = create_middleware(
    app,
    config=ObservabilityConfig(service_name="my-service")
)

logger = get_logger(__name__)

@app.get("/")
async def root():
    logger.info("Hello World")
    return {"message": "Hello World"}
```

### Quart

```python
from quart import Quart
from auditry import configure_logging, ObservabilityConfig, get_logger
from auditry.quart import create_middleware

# Configure structured logging at startup
configure_logging(level="INFO")

app = Quart(__name__)

# Add observability middleware (single line!)
app = create_middleware(
    app,
    config=ObservabilityConfig(service_name="my-service")
)

logger = get_logger(__name__)

@app.route("/")
async def root():
    logger.info("Hello World")
    return {"message": "Hello World"}
```

## Configuration

### Required Configuration

```python
config = ObservabilityConfig(
    service_name="your-service-name",  # REQUIRED
)
```

**Note:** The `service_name` is required and must be provided. This ensures all services have meaningful names in logs rather than generic defaults.

### Full Configuration Options

```python
config = ObservabilityConfig(
    # REQUIRED: Service name for log filtering (no default)
    service_name="my-service-name",

    # Correlation ID header name (default: X-Correlation-ID)
    # Use this if your org uses a different header, such as X-Request-ID
    correlation_id_header="X-Correlation-ID",

    # Maximum request/response body size to log (default: 10KB)
    payload_size_limit=10_240,

    # Additional sensitive field patterns to redact
    additional_redaction_patterns=["internal_id", "employee_ssn"],

    # Whether to log request headers (default: True)
    log_request_headers=True,

    # Whether to log response headers (default: False)
    log_response_headers=False,

    # Whether to log query parameters (default: True)
    log_query_params=True,

    # Whether to log request bodies for all endpoints (default: True)
    # Set to False for applications handling sensitive data
    log_request_body=True,

    # Whether to log response bodies for all endpoints (default: True)
    # Set to False for applications returning sensitive data
    log_response_body=True,
)

# For FastAPI:
from auditry.fastapi import create_middleware
app = create_middleware(app, config)

# For Quart:
from auditry.quart import create_middleware
app = create_middleware(app, config)
```

## Correlation IDs

Correlation IDs are automatically handled:

- **Incoming requests**: Extracts from `X-Correlation-ID` header (or your custom header)
- **Generated if missing**: Creates a new UUID if no correlation ID provided
- **Added to response**: Returns the correlation ID in the response header
- **Included in logs**: Automatically included in all structured logs

### Using Correlation IDs in Your Code

```python
from auditry import get_logger, get_correlation_id

logger = get_logger(__name__)

@app.get("/users/{user_id}")
async def get_user(user_id: str):
    # Correlation ID is automatically available
    correlation_id = get_correlation_id()

    # All logs automatically include the correlation ID
    logger.info(f"Fetching user {user_id}")

    return {"user_id": user_id, "correlation_id": correlation_id}
```

### Propagating to Downstream Services

```python
import httpx
from auditry import get_correlation_id

@app.get("/proxy")
async def proxy_request():
    # Get the current correlation ID
    correlation_id = get_correlation_id()

    # Pass it to downstream services
    async with httpx.AsyncClient() as client:
        response = await client.get(
            "https://downstream-service.com/api/data",
            headers={"X-Correlation-ID": correlation_id}  # Use your org's header name
        )

    return response.json()
```

## User Tracking

The middleware automatically extracts user IDs from your authentication system and includes them in logs.

### FastAPI User Tracking

```python
from fastapi import Request, Depends

async def get_current_user(request: Request):
    # Your authentication logic here
    user_id = "user-123"

    # Set user_id in request state for auditry to capture
    request.state.user_id = user_id
    # OR if you have a user object:
    # request.state.user = user_object  # Must have .id or .user_id attribute

    return user_id

@app.get("/protected")
async def protected_route(user_id: str = Depends(get_current_user)):
    return {"message": "Protected content"}
```

### Quart User Tracking

```python
from quart import request

@app.before_request
async def authenticate():
    # Your authentication logic here

    # Set user on request for auditry to capture
    request.current_user = AuthenticatedUser(id="user-123")
    # OR use g.user or g.user_id
    # from quart import g
    # g.user_id = "user-123"
```

The middleware automatically finds the user ID from these locations:
- **FastAPI**: `request.state.user_id` or `request.state.user.id`
- **Quart**: `request.current_user.id`, `g.user.id`, or `g.user_id`

## Business Event Tagging (For Analytics)

Tag specific endpoints as "business events" to make analytics queries easier for your sales/product teams.

### Configuration

Tag endpoints in your middleware config - zero code changes needed in your actual endpoints:

```python
from auditry import ObservabilityConfig, BusinessEventConfig

config = ObservabilityConfig(
    service_name="my-service-name",

    # Define which endpoints to tag for analytics
    business_events={
        "POST /workflows": BusinessEventConfig(
            event_type="workflow.created",
            extract_from_request=["file_id"],  # Pull file_id from request body
            extract_from_response=["id"],       # Pull workflow id from response
        ),
        "DELETE /workflows/{workflow_id}": BusinessEventConfig(
            event_type="workflow.deleted",
            extract_from_path=["workflow_id"],    # Pull workflow_id from URL path
        ),
    },
)

# Apply to your framework
from auditry.fastapi import create_middleware  # or auditry.quart
app = create_middleware(app, config)
```

### Log Output with Event Tags

Regular log (no tagging):
```json
{
  "service": "my-service-name",
  "message": "Request completed: POST /workflows - Status: 201",
  "request": {...},
  "response": {...}
}
```

Tagged business event log:
```json
{
  "service": "my-service-name",
  "message": "Request completed: POST /workflows - Status: 201",
  "event_type": "workflow.created",          // ← Filterable in log platform
  "business_context": {
    "file_id": "file_123",                   // ← From request body
    "id": "workflow_789"                    // ← From response body
  },
  "request": {...},
  "response": {...}
}
```

### Supported Extract Locations

- `extract_from_request`: Fields from request JSON body
- `extract_from_response`: Fields from response JSON body  
- `extract_from_path`: Parameters from URL path (e.g., `/workflows/{workflow_id}`)

## Log Output

All logs are structured JSON, ready for log aggregators:

```json
{
  "timestamp": "2025-10-28T12:34:56.789012+00:00",
  "level": "INFO",
  "service": "my-service-name",
  "correlation_id": "550e8400-e29b-41d4-a716-446655440000",
  "message": "Request completed: POST /workflows - Status: 201 - Duration: 45.23ms",
  "request": {
    "method": "POST",
    "path": "/workflows",
    "query_params": {},
    "headers": {"user-agent": "curl/7.64.1", "authorization": "[REDACTED]"},
    "body": {"name": "My Workflow", "password": "[REDACTED]"},
    "user_id": "user_12345"
  },
  "response": {
    "status_code": 201,
    "duration_ms": 45.23,
    "body": {"id": "workflow_789", "name": "My Workflow"}
  }
}
```

## Sensitive Data Handling

### Automatic Redaction

Automatically redacts these sensitive field patterns in all logged requests/responses:

- `password`
- `token`
- `api_key` / `apikey`
- `secret`
- `authorization`
- `ssn` / `social_security_number`
- `credit_card` / `creditcard`
- `x-api-key`

Add custom patterns via configuration:

```python
config = ObservabilityConfig(
    service_name="my-service-name",
    additional_redaction_patterns=["internal_token", "employee_id"],
)
```

### Disabling Body Logging (Application-Wide)

For applications handling sensitive data, you can disable logging of request and/or response bodies across the entire application:

```python
config = ObservabilityConfig(
    service_name="my-service-name",

    # Disable request body logging for all endpoints
    log_request_body=False,

    # Disable response body logging for all endpoints
    log_response_body=False,
)
```

When body logging is disabled, logs will show `[BODY_LOGGING_DISABLED]` instead of the actual content, while still logging metadata like headers, status codes, and timing information.
## Best Practices

### 1. Configure Logging Early

Call `configure_logging()` at application startup, before any other code:

```python
from auditry import configure_logging

# First thing in your app
configure_logging(level="INFO")

app = FastAPI()
# ... rest of your app
```

### 2. Use Structured Logging

Always use `get_logger(__name__)` instead of standard Python logging:

```python
from auditry import get_logger

logger = get_logger(__name__)

# Good - structured with correlation ID
logger.info("Processing payment", amount=100.50, currency="USD")

# Bad - loses structured data
import logging
logging.info("Processing payment")
```

### 3. Propagate Correlation IDs

When calling downstream services, always pass the correlation ID:

```python
from auditry import get_correlation_id

correlation_id = get_correlation_id()
headers = {"X-Correlation-ID": correlation_id}  # Use your org's header name
response = await client.get(url, headers=headers)
```

### 4. Customize for Your Organization

Match your org's conventions:

```python
config = ObservabilityConfig(
    service_name="my-service-name",
    correlation_id_header="X-Request-ID",  # If your org uses this header instead
    additional_redaction_patterns=["ssn", "tax_id"],  # Your sensitive fields
)
```

## Example Output: Success vs Failure

### Successful Request

```json
{
  "level": "INFO",
  "service": "my-service-name",
  "correlation_id": "abc-123",
  "message": "Request completed: POST /workflows - Status: 201 - Duration: 45ms",
  "request": {...},
  "response": {...}
}
```

### Failed Request

```json
{
  "level": "ERROR",
  "service": "my-service-name",
  "correlation_id": "abc-123",
  "message": "Request failed: POST /workflows - Error: ValueError: Invalid name",
  "request": {...},
  "exception_type": "ValueError",
  "exception_message": "Invalid name",
  "execution_duration_ms": 12.34
}
```

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Contributing

Contributions welcome! Please submit a Pull Request.

## Support

For issues and questions: [GitHub Issues](https://github.com/lst4rk/auditry/issues)

## Author

**Liv Stark** - [livstark.work@gmail.com](mailto:livstark.work@gmail.com)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "auditry",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "fastapi, quart, observability, logging, middleware, correlation-id, redaction",
    "author": null,
    "author_email": "Liv Stark <livstark.work@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/1e/0f/f64c0922dfbd5dbf7289fd4afbb37650bc9fba0d04ee6fbfd318b6f4c7d4/auditry-0.2.1.tar.gz",
    "platform": null,
    "description": "# auditry\n\nA clean, framework-agnostic observability middleware for FastAPI and Quart that provides comprehensive request/response logging, correlation ID tracking, business event extraction, and sensitive data redaction.\n\n[![PyPI version](https://badge.fury.io/py/auditry.svg)](https://badge.fury.io/py/auditry)\n[![Python Versions](https://img.shields.io/pypi/pyversions/auditry.svg)](https://pypi.org/project/auditry/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## Installation\n\n### For FastAPI\n\n```bash\npip install auditry[fastapi]\n```\n\n### For Quart\n\n```bash\npip install auditry[quart]\n```\n\n### For both frameworks\n\n```bash\npip install auditry[all]\n```\n\n## Quick Start\n\n### FastAPI\n\n```python\nfrom fastapi import FastAPI\nfrom auditry import configure_logging, ObservabilityConfig, get_logger\nfrom auditry.fastapi import create_middleware\n\n# Configure structured logging at startup\nconfigure_logging(level=\"INFO\")\n\napp = FastAPI()\n\n# Add observability middleware (single line!)\napp = create_middleware(\n    app,\n    config=ObservabilityConfig(service_name=\"my-service\")\n)\n\nlogger = get_logger(__name__)\n\n@app.get(\"/\")\nasync def root():\n    logger.info(\"Hello World\")\n    return {\"message\": \"Hello World\"}\n```\n\n### Quart\n\n```python\nfrom quart import Quart\nfrom auditry import configure_logging, ObservabilityConfig, get_logger\nfrom auditry.quart import create_middleware\n\n# Configure structured logging at startup\nconfigure_logging(level=\"INFO\")\n\napp = Quart(__name__)\n\n# Add observability middleware (single line!)\napp = create_middleware(\n    app,\n    config=ObservabilityConfig(service_name=\"my-service\")\n)\n\nlogger = get_logger(__name__)\n\n@app.route(\"/\")\nasync def root():\n    logger.info(\"Hello World\")\n    return {\"message\": \"Hello World\"}\n```\n\n## Configuration\n\n### Required Configuration\n\n```python\nconfig = ObservabilityConfig(\n    service_name=\"your-service-name\",  # REQUIRED\n)\n```\n\n**Note:** The `service_name` is required and must be provided. This ensures all services have meaningful names in logs rather than generic defaults.\n\n### Full Configuration Options\n\n```python\nconfig = ObservabilityConfig(\n    # REQUIRED: Service name for log filtering (no default)\n    service_name=\"my-service-name\",\n\n    # Correlation ID header name (default: X-Correlation-ID)\n    # Use this if your org uses a different header, such as X-Request-ID\n    correlation_id_header=\"X-Correlation-ID\",\n\n    # Maximum request/response body size to log (default: 10KB)\n    payload_size_limit=10_240,\n\n    # Additional sensitive field patterns to redact\n    additional_redaction_patterns=[\"internal_id\", \"employee_ssn\"],\n\n    # Whether to log request headers (default: True)\n    log_request_headers=True,\n\n    # Whether to log response headers (default: False)\n    log_response_headers=False,\n\n    # Whether to log query parameters (default: True)\n    log_query_params=True,\n\n    # Whether to log request bodies for all endpoints (default: True)\n    # Set to False for applications handling sensitive data\n    log_request_body=True,\n\n    # Whether to log response bodies for all endpoints (default: True)\n    # Set to False for applications returning sensitive data\n    log_response_body=True,\n)\n\n# For FastAPI:\nfrom auditry.fastapi import create_middleware\napp = create_middleware(app, config)\n\n# For Quart:\nfrom auditry.quart import create_middleware\napp = create_middleware(app, config)\n```\n\n## Correlation IDs\n\nCorrelation IDs are automatically handled:\n\n- **Incoming requests**: Extracts from `X-Correlation-ID` header (or your custom header)\n- **Generated if missing**: Creates a new UUID if no correlation ID provided\n- **Added to response**: Returns the correlation ID in the response header\n- **Included in logs**: Automatically included in all structured logs\n\n### Using Correlation IDs in Your Code\n\n```python\nfrom auditry import get_logger, get_correlation_id\n\nlogger = get_logger(__name__)\n\n@app.get(\"/users/{user_id}\")\nasync def get_user(user_id: str):\n    # Correlation ID is automatically available\n    correlation_id = get_correlation_id()\n\n    # All logs automatically include the correlation ID\n    logger.info(f\"Fetching user {user_id}\")\n\n    return {\"user_id\": user_id, \"correlation_id\": correlation_id}\n```\n\n### Propagating to Downstream Services\n\n```python\nimport httpx\nfrom auditry import get_correlation_id\n\n@app.get(\"/proxy\")\nasync def proxy_request():\n    # Get the current correlation ID\n    correlation_id = get_correlation_id()\n\n    # Pass it to downstream services\n    async with httpx.AsyncClient() as client:\n        response = await client.get(\n            \"https://downstream-service.com/api/data\",\n            headers={\"X-Correlation-ID\": correlation_id}  # Use your org's header name\n        )\n\n    return response.json()\n```\n\n## User Tracking\n\nThe middleware automatically extracts user IDs from your authentication system and includes them in logs.\n\n### FastAPI User Tracking\n\n```python\nfrom fastapi import Request, Depends\n\nasync def get_current_user(request: Request):\n    # Your authentication logic here\n    user_id = \"user-123\"\n\n    # Set user_id in request state for auditry to capture\n    request.state.user_id = user_id\n    # OR if you have a user object:\n    # request.state.user = user_object  # Must have .id or .user_id attribute\n\n    return user_id\n\n@app.get(\"/protected\")\nasync def protected_route(user_id: str = Depends(get_current_user)):\n    return {\"message\": \"Protected content\"}\n```\n\n### Quart User Tracking\n\n```python\nfrom quart import request\n\n@app.before_request\nasync def authenticate():\n    # Your authentication logic here\n\n    # Set user on request for auditry to capture\n    request.current_user = AuthenticatedUser(id=\"user-123\")\n    # OR use g.user or g.user_id\n    # from quart import g\n    # g.user_id = \"user-123\"\n```\n\nThe middleware automatically finds the user ID from these locations:\n- **FastAPI**: `request.state.user_id` or `request.state.user.id`\n- **Quart**: `request.current_user.id`, `g.user.id`, or `g.user_id`\n\n## Business Event Tagging (For Analytics)\n\nTag specific endpoints as \"business events\" to make analytics queries easier for your sales/product teams.\n\n### Configuration\n\nTag endpoints in your middleware config - zero code changes needed in your actual endpoints:\n\n```python\nfrom auditry import ObservabilityConfig, BusinessEventConfig\n\nconfig = ObservabilityConfig(\n    service_name=\"my-service-name\",\n\n    # Define which endpoints to tag for analytics\n    business_events={\n        \"POST /workflows\": BusinessEventConfig(\n            event_type=\"workflow.created\",\n            extract_from_request=[\"file_id\"],  # Pull file_id from request body\n            extract_from_response=[\"id\"],       # Pull workflow id from response\n        ),\n        \"DELETE /workflows/{workflow_id}\": BusinessEventConfig(\n            event_type=\"workflow.deleted\",\n            extract_from_path=[\"workflow_id\"],    # Pull workflow_id from URL path\n        ),\n    },\n)\n\n# Apply to your framework\nfrom auditry.fastapi import create_middleware  # or auditry.quart\napp = create_middleware(app, config)\n```\n\n### Log Output with Event Tags\n\nRegular log (no tagging):\n```json\n{\n  \"service\": \"my-service-name\",\n  \"message\": \"Request completed: POST /workflows - Status: 201\",\n  \"request\": {...},\n  \"response\": {...}\n}\n```\n\nTagged business event log:\n```json\n{\n  \"service\": \"my-service-name\",\n  \"message\": \"Request completed: POST /workflows - Status: 201\",\n  \"event_type\": \"workflow.created\",          // \u2190 Filterable in log platform\n  \"business_context\": {\n    \"file_id\": \"file_123\",                   // \u2190 From request body\n    \"id\": \"workflow_789\"                    // \u2190 From response body\n  },\n  \"request\": {...},\n  \"response\": {...}\n}\n```\n\n### Supported Extract Locations\n\n- `extract_from_request`: Fields from request JSON body\n- `extract_from_response`: Fields from response JSON body  \n- `extract_from_path`: Parameters from URL path (e.g., `/workflows/{workflow_id}`)\n\n## Log Output\n\nAll logs are structured JSON, ready for log aggregators:\n\n```json\n{\n  \"timestamp\": \"2025-10-28T12:34:56.789012+00:00\",\n  \"level\": \"INFO\",\n  \"service\": \"my-service-name\",\n  \"correlation_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"message\": \"Request completed: POST /workflows - Status: 201 - Duration: 45.23ms\",\n  \"request\": {\n    \"method\": \"POST\",\n    \"path\": \"/workflows\",\n    \"query_params\": {},\n    \"headers\": {\"user-agent\": \"curl/7.64.1\", \"authorization\": \"[REDACTED]\"},\n    \"body\": {\"name\": \"My Workflow\", \"password\": \"[REDACTED]\"},\n    \"user_id\": \"user_12345\"\n  },\n  \"response\": {\n    \"status_code\": 201,\n    \"duration_ms\": 45.23,\n    \"body\": {\"id\": \"workflow_789\", \"name\": \"My Workflow\"}\n  }\n}\n```\n\n## Sensitive Data Handling\n\n### Automatic Redaction\n\nAutomatically redacts these sensitive field patterns in all logged requests/responses:\n\n- `password`\n- `token`\n- `api_key` / `apikey`\n- `secret`\n- `authorization`\n- `ssn` / `social_security_number`\n- `credit_card` / `creditcard`\n- `x-api-key`\n\nAdd custom patterns via configuration:\n\n```python\nconfig = ObservabilityConfig(\n    service_name=\"my-service-name\",\n    additional_redaction_patterns=[\"internal_token\", \"employee_id\"],\n)\n```\n\n### Disabling Body Logging (Application-Wide)\n\nFor applications handling sensitive data, you can disable logging of request and/or response bodies across the entire application:\n\n```python\nconfig = ObservabilityConfig(\n    service_name=\"my-service-name\",\n\n    # Disable request body logging for all endpoints\n    log_request_body=False,\n\n    # Disable response body logging for all endpoints\n    log_response_body=False,\n)\n```\n\nWhen body logging is disabled, logs will show `[BODY_LOGGING_DISABLED]` instead of the actual content, while still logging metadata like headers, status codes, and timing information.\n## Best Practices\n\n### 1. Configure Logging Early\n\nCall `configure_logging()` at application startup, before any other code:\n\n```python\nfrom auditry import configure_logging\n\n# First thing in your app\nconfigure_logging(level=\"INFO\")\n\napp = FastAPI()\n# ... rest of your app\n```\n\n### 2. Use Structured Logging\n\nAlways use `get_logger(__name__)` instead of standard Python logging:\n\n```python\nfrom auditry import get_logger\n\nlogger = get_logger(__name__)\n\n# Good - structured with correlation ID\nlogger.info(\"Processing payment\", amount=100.50, currency=\"USD\")\n\n# Bad - loses structured data\nimport logging\nlogging.info(\"Processing payment\")\n```\n\n### 3. Propagate Correlation IDs\n\nWhen calling downstream services, always pass the correlation ID:\n\n```python\nfrom auditry import get_correlation_id\n\ncorrelation_id = get_correlation_id()\nheaders = {\"X-Correlation-ID\": correlation_id}  # Use your org's header name\nresponse = await client.get(url, headers=headers)\n```\n\n### 4. Customize for Your Organization\n\nMatch your org's conventions:\n\n```python\nconfig = ObservabilityConfig(\n    service_name=\"my-service-name\",\n    correlation_id_header=\"X-Request-ID\",  # If your org uses this header instead\n    additional_redaction_patterns=[\"ssn\", \"tax_id\"],  # Your sensitive fields\n)\n```\n\n## Example Output: Success vs Failure\n\n### Successful Request\n\n```json\n{\n  \"level\": \"INFO\",\n  \"service\": \"my-service-name\",\n  \"correlation_id\": \"abc-123\",\n  \"message\": \"Request completed: POST /workflows - Status: 201 - Duration: 45ms\",\n  \"request\": {...},\n  \"response\": {...}\n}\n```\n\n### Failed Request\n\n```json\n{\n  \"level\": \"ERROR\",\n  \"service\": \"my-service-name\",\n  \"correlation_id\": \"abc-123\",\n  \"message\": \"Request failed: POST /workflows - Error: ValueError: Invalid name\",\n  \"request\": {...},\n  \"exception_type\": \"ValueError\",\n  \"exception_message\": \"Invalid name\",\n  \"execution_duration_ms\": 12.34\n}\n```\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Contributing\n\nContributions welcome! Please submit a Pull Request.\n\n## Support\n\nFor issues and questions: [GitHub Issues](https://github.com/lst4rk/auditry/issues)\n\n## Author\n\n**Liv Stark** - [livstark.work@gmail.com](mailto:livstark.work@gmail.com)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Observability middleware for FastAPI and Quart with request/response logging, correlation IDs, and sensitive data redaction",
    "version": "0.2.1",
    "project_urls": {
        "Homepage": "https://github.com/lst4rk/auditry",
        "Issues": "https://github.com/lst4rk/auditry/issues",
        "Repository": "https://github.com/lst4rk/auditry"
    },
    "split_keywords": [
        "fastapi",
        " quart",
        " observability",
        " logging",
        " middleware",
        " correlation-id",
        " redaction"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c3279244ca078c1b14e0176b799784701aa59121728f7fb1e9f333a68b628cc8",
                "md5": "2fee2e3ce590226fca247a4e55679db9",
                "sha256": "37afc35caa99e311af29b2a59e04bcad611ae4bf8ffb6c32f16104b2fde0f8e4"
            },
            "downloads": -1,
            "filename": "auditry-0.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "2fee2e3ce590226fca247a4e55679db9",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 22635,
            "upload_time": "2025-10-30T15:10:28",
            "upload_time_iso_8601": "2025-10-30T15:10:28.271615Z",
            "url": "https://files.pythonhosted.org/packages/c3/27/9244ca078c1b14e0176b799784701aa59121728f7fb1e9f333a68b628cc8/auditry-0.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1e0ff64c0922dfbd5dbf7289fd4afbb37650bc9fba0d04ee6fbfd318b6f4c7d4",
                "md5": "f3ccd6bc767512a87cf84975406d9034",
                "sha256": "be1be17f1c84773db484a08cfe1a92d681488e03b338a05acba9e72350fcd382"
            },
            "downloads": -1,
            "filename": "auditry-0.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "f3ccd6bc767512a87cf84975406d9034",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 23613,
            "upload_time": "2025-10-30T15:10:29",
            "upload_time_iso_8601": "2025-10-30T15:10:29.602026Z",
            "url": "https://files.pythonhosted.org/packages/1e/0f/f64c0922dfbd5dbf7289fd4afbb37650bc9fba0d04ee6fbfd318b6f4c7d4/auditry-0.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-30 15:10:29",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "lst4rk",
    "github_project": "auditry",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "auditry"
}
        
Elapsed time: 3.99518s