structured-logger-railway


Namestructured-logger-railway JSON
Version 1.5.2 PyPI version JSON
download
home_pageNone
SummaryA flexible structured JSON logger for Python applications
upload_time2025-10-10 07:14:42
maintainerNone
docs_urlNone
authorNikita Yastreb, Patrick Ward
requires_python>=3.8
licenseMIT
keywords logging json structured railway cloud docker kubernetes
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Structured Logger

[![PyPI version](https://badge.fury.io/py/structured-logger-railway.svg)](https://pypi.org/project/structured-logger-railway/)

A flexible, configurable structured JSON logger for Python applications. Perfect for cloud deployments, containerized applications, and log aggregation systems like ELK, Splunk, or cloud logging services.

## Features

- ๐Ÿš€ **Structured JSON logging** with automatic serialization of complex objects
- โš™๏ธ **Highly configurable** with sensible defaults
- ๐ŸŒ **Environment-aware** formatting (JSON for production, readable for development)
- ๐Ÿ”ง **Custom field support** for tracing, user context, and more
- ๐Ÿ“ฆ **Easy integration** with existing Python logging
- ๐ŸŽฏ **Type-safe** with full type hints
- ๐Ÿฆ„ **Uvicorn integration** - automatically formats uvicorn logs as structured JSON
- ๐Ÿฆ… **Gunicorn integration** - automatically formats gunicorn logs as structured JSON
- โšก **Zero dependencies** - uses only Python standard library

## Installation

```bash
pip install structured-logger-railway
```

## Quick Start

### Basic Usage

```python
from structured_logger import get_logger

logger = get_logger(__name__)

logger.info("Application started")
logger.error("Something went wrong", extra={"user_id": "12345"})
```

**Output in development:**
```
2024-01-15 10:30:45,123 [INFO] myapp: Application started
2024-01-15 10:30:45,124 [ERROR] myapp: Something went wrong
```

**Output in production:**
```json
{"time": "2024-01-15 10:30:45,123", "level": "INFO", "message": "Application started", "module": "myapp"}
{"time": "2024-01-15 10:30:45,124", "level": "ERROR", "message": "Something went wrong", "module": "myapp", "user_id": "12345"}
```

### Custom Configuration

```python
from structured_logger import get_logger, LoggerConfig

# Custom configuration
config = LoggerConfig(
    custom_fields=["user_id", "request_id", "trace_id"],
    production_env_vars=["ENV", "ENVIRONMENT"],
    production_env_values=["prod", "production", "staging"],
    dev_format="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
)

logger = get_logger(__name__, config=config)
```

### Force JSON or Development Format

```python
# Always use JSON formatting
logger = get_logger(__name__, force_json=True)

# Always use development formatting
logger = get_logger(__name__, force_dev=True)
```

### Root Logger Setup

```python
from structured_logger import setup_root_logger

# Setup root logger for entire application
setup_root_logger()

# Now all loggers will use structured format
import logging
logger = logging.getLogger("myapp")
logger.info("This will be structured")
```

## Advanced Usage

### Custom Serializers

```python
from datetime import datetime
from structured_logger import LoggerConfig, get_logger

def serialize_datetime(dt):
    return dt.isoformat()

config = LoggerConfig(
    custom_serializers={
        datetime: serialize_datetime
    }
)

logger = get_logger(__name__, config=config)
logger.info("Current time", extra={"timestamp": datetime.now()})
```

### Context Fields

```python
import logging
from structured_logger import get_logger

logger = get_logger(__name__)

# Add context to log record
class ContextFilter(logging.Filter):
    def filter(self, record):
        record.user_id = getattr(self, 'user_id', None)
        record.request_id = getattr(self, 'request_id', None)
        return True

context_filter = ContextFilter()
logger.addFilter(context_filter)

# Set context
context_filter.user_id = "user123"
context_filter.request_id = "req456"

logger.info("Processing request")  # Will include user_id and request_id
```

### Exception Logging

```python
try:
    raise ValueError("Something went wrong")
except Exception:
    logger.exception("An error occurred", extra={"operation": "data_processing"})
```

**JSON Output:**
```json
{
  "time": "2024-01-15 10:30:45,123",
  "level": "ERROR", 
  "message": "An error occurred",
  "module": "myapp",
  "operation": "data_processing",
  "exception": "Traceback (most recent call last):\n  File \"example.py\", line 2, in <module>\n    raise ValueError(\"Something went wrong\")\nValueError: Something went wrong"
}
```

## Configuration Options

### LoggerConfig Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `production_env_vars` | `List[str]` | `["RAILWAY_ENVIRONMENT", "ENV", "ENVIRONMENT", "NODE_ENV"]` | Environment variables to check for production |
| `production_env_values` | `List[str]` | `["prod", "production", "staging"]` | Values that indicate production environment |
| `log_level_env_var` | `str` | `"LOG_LEVEL"` | Environment variable for log level |
| `default_log_level` | `str` | `"INFO"` | Default log level |
| `custom_fields` | `List[str]` | `["user_id", "company_id", "request_id", "trace_id", "span_id"]` | Fields to extract from log records |
| `time_format` | `Optional[str]` | `None` | Custom time format |
| `dev_format` | `str` | `"%(asctime)s [%(levelname)s] %(name)s: %(message)s"` | Format string for development |
| `custom_serializers` | `Dict[type, Callable]` | `{}` | Custom serializers for specific types |
| `include_extra_attrs` | `bool` | `True` | Whether to include extra attributes |
| `excluded_attrs` | `List[str]` | Standard logging fields | Fields to exclude from extra attributes |
| `override_uvicorn_loggers` | `bool` | `True` | Enable structured formatting for uvicorn loggers |
| `uvicorn_loggers` | `List[str]` | `["uvicorn", "uvicorn.access", "uvicorn.error", "uvicorn.asgi"]` | List of uvicorn loggers to override |
| `override_gunicorn_loggers` | `bool` | `True` | Enable structured formatting for gunicorn loggers |
| `gunicorn_loggers` | `List[str]` | `["gunicorn", "gunicorn.access", "gunicorn.error"]` | List of gunicorn loggers to override |
| `override_library_loggers` | `bool` | `True` | Enable structured formatting for third-party library loggers (httpx, sqlalchemy, etc.) |
| `library_loggers` | `List[str]` | `["httpx", "httpcore", "sqlalchemy", "starlette", "fastapi", ...]` | List of library loggers to override |

### Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `LOG_LEVEL` | Set logging level | `INFO` |
| `RAILWAY_ENVIRONMENT` | Railway deployment indicator | - |
| `ENV` | Environment indicator | - |
| `ENVIRONMENT` | Environment indicator | - |
| `NODE_ENV` | Node.js style environment | - |

## Framework Integration

### Flask with Gunicorn Integration

```python
from flask import Flask, request, g
from structured_logger import get_logger, setup_gunicorn_logging
import uuid

# Option 1: Simple gunicorn setup (recommended)
setup_gunicorn_logging(force_json=True)

# Option 2: Full configuration with gunicorn override
config = LoggerConfig(
    override_gunicorn_loggers=True,  # Enable structured gunicorn logs
    custom_fields=["request_id", "user_id"],
    include_extra_attrs=True,
)

app = Flask(__name__)
logger = get_logger(__name__, config=config)

@app.before_request
def before_request():
    g.request_id = str(uuid.uuid4())

@app.after_request
def after_request(response):
    logger.info(
        "Request processed",
        extra={
            "request_id": getattr(g, 'request_id', None),
            "method": request.method,
            "path": request.path,
            "status": response.status_code
        }
    )
    return response

# Run with: gunicorn --workers 4 --bind 0.0.0.0:8000 myapp:app
# Gunicorn access logs and error logs will now be structured JSON!
```

### Automatic Logger Overrides (Enabled by Default!)

**All server and library logs are automatically formatted as JSON!** This includes:
- **Uvicorn**: `uvicorn`, `uvicorn.access`, `uvicorn.error`, `uvicorn.asgi`
- **Gunicorn**: `gunicorn`, `gunicorn.access`, `gunicorn.error`
- **HTTP Clients**: `httpx`, `httpcore`, `urllib3`, `requests`, `aiohttp`
- **Database**: `sqlalchemy` (including engine, pool, orm)
- **Frameworks**: `starlette`, `fastapi`
- **Async**: `asyncio`

```python
from structured_logger import get_logger

# That's it! Everything is automatic!
logger = get_logger(__name__)

# All logs are now JSON formatted:
# โœ“ Your application logs
# โœ“ Uvicorn/Gunicorn logs (automatic!)
# โœ“ Third-party library logs (automatic!)
```

**To disable specific overrides:**

```python
from structured_logger import LoggerConfig, get_logger

config = LoggerConfig(
    override_uvicorn_loggers=False,   # Disable uvicorn override
    override_gunicorn_loggers=False,  # Disable gunicorn override
    override_library_loggers=False,   # Disable library override
)
logger = get_logger(__name__, config=config)
```

### FastAPI with Uvicorn Integration

```python
from fastapi import FastAPI, Request
from structured_logger import get_logger
import uuid
import time

# Simple setup - everything is automatic!
logger = get_logger(__name__)

# Or with custom fields
from structured_logger import LoggerConfig

config = LoggerConfig(
    custom_fields=["request_id", "user_id"],
    include_extra_attrs=True,
    # All overrides are enabled by default:
    # override_uvicorn_loggers=True
    # override_library_loggers=True
    # override_gunicorn_loggers=True
)

app = FastAPI()
logger = get_logger(__name__, config=config)

@app.middleware("http")
async def log_requests(request: Request, call_next):
    request_id = str(uuid.uuid4())
    start_time = time.time()
    
    response = await call_next(request)
    
    process_time = time.time() - start_time
    logger.info(
        "Request processed",
        extra={
            "request_id": request_id,
            "method": request.method,
            "path": request.url.path,
            "status": response.status_code,
            "duration": process_time
        }
    )
    
    return response

if __name__ == "__main__":
    import uvicorn
    # Uvicorn access logs and error logs will now be structured JSON!
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

### Django

```python
# settings.py
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'structured': {
            'level': 'INFO',
            'class': 'structured_logger.logger.StructuredLogHandler',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['structured'],
            'level': 'INFO',
            'propagate': True,
        },
        'myapp': {
            'handlers': ['structured'],
            'level': 'INFO',
            'propagate': True,
        },
    },
}
```

## Railway.app Compatibility

This library maintains full compatibility with Railway.app deployments. The original Railway-specific functionality is preserved:

```python
# These work exactly like before
from structured_logger import get_railway_logger

logger = get_railway_logger(__name__)
logger.info("Deployed to Railway!")
```

## Development

```bash
# Clone the repository
git clone https://github.com/zee229/structured-logger.git
cd structured-logger

# Install development dependencies
pip install -e .

# Run examples
python examples/basic_usage.py
python examples/custom_config.py
```

## Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

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

## Uvicorn Integration

New in v1.3.0! Automatically format uvicorn logs as structured JSON for better log parsing and analysis.

### Quick Setup

```python
from structured_logger import setup_uvicorn_logging

# This will override all uvicorn loggers with structured formatting
setup_uvicorn_logging(force_json=True)
```

### Configuration Options

```python
from structured_logger import LoggerConfig, get_logger

config = LoggerConfig(
    override_uvicorn_loggers=True,  # Enable uvicorn override
    uvicorn_loggers=[               # Customize which loggers to override
        "uvicorn",
        "uvicorn.access", 
        "uvicorn.error",
        "uvicorn.asgi"
    ],
    custom_fields=["request_id", "user_id"],
)

logger = get_logger(__name__, config=config)
```

### What Gets Formatted

With uvicorn integration enabled, these logs are automatically structured:

- **uvicorn**: Main uvicorn logger
- **uvicorn.access**: HTTP access logs
- **uvicorn.error**: Error logs
- **uvicorn.asgi**: ASGI-related logs

**Before (plain text):**
```
INFO:     127.0.0.1:52000 - "GET /users/123 HTTP/1.1" 200 OK
```

**After (structured JSON):**
```json
{"time": "2024-01-01T12:00:00", "level": "INFO", "message": "127.0.0.1:52000 - \"GET /users/123 HTTP/1.1\" 200 OK", "module": "uvicorn.access"}
```

## Changelog

### 1.3.0
- โœจ **New**: Uvicorn logger integration for structured FastAPI logs
- ๐Ÿ”ง Added `setup_uvicorn_logging()` convenience function
- ๐Ÿ“ Enhanced documentation with uvicorn examples
- ๐Ÿงช Comprehensive test coverage for uvicorn integration

### 1.0.0
- Initial release
- Flexible configuration system
- Environment-aware formatting
- Custom serializers support
- Full backward compatibility with Railway logger

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "structured-logger-railway",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "logging, json, structured, railway, cloud, docker, kubernetes",
    "author": "Nikita Yastreb, Patrick Ward",
    "author_email": "Nikita Yastreb <yastrebnikita723@gmail.com>, Patrick Ward <pward17@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/97/17/03d73c148e1827c47bbe33d547484998d7540fac56cca4b2b6c844acb327/structured_logger_railway-1.5.2.tar.gz",
    "platform": null,
    "description": "# Structured Logger\n\n[![PyPI version](https://badge.fury.io/py/structured-logger-railway.svg)](https://pypi.org/project/structured-logger-railway/)\n\nA flexible, configurable structured JSON logger for Python applications. Perfect for cloud deployments, containerized applications, and log aggregation systems like ELK, Splunk, or cloud logging services.\n\n## Features\n\n- \ud83d\ude80 **Structured JSON logging** with automatic serialization of complex objects\n- \u2699\ufe0f **Highly configurable** with sensible defaults\n- \ud83c\udf0d **Environment-aware** formatting (JSON for production, readable for development)\n- \ud83d\udd27 **Custom field support** for tracing, user context, and more\n- \ud83d\udce6 **Easy integration** with existing Python logging\n- \ud83c\udfaf **Type-safe** with full type hints\n- \ud83e\udd84 **Uvicorn integration** - automatically formats uvicorn logs as structured JSON\n- \ud83e\udd85 **Gunicorn integration** - automatically formats gunicorn logs as structured JSON\n- \u26a1 **Zero dependencies** - uses only Python standard library\n\n## Installation\n\n```bash\npip install structured-logger-railway\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\nfrom structured_logger import get_logger\n\nlogger = get_logger(__name__)\n\nlogger.info(\"Application started\")\nlogger.error(\"Something went wrong\", extra={\"user_id\": \"12345\"})\n```\n\n**Output in development:**\n```\n2024-01-15 10:30:45,123 [INFO] myapp: Application started\n2024-01-15 10:30:45,124 [ERROR] myapp: Something went wrong\n```\n\n**Output in production:**\n```json\n{\"time\": \"2024-01-15 10:30:45,123\", \"level\": \"INFO\", \"message\": \"Application started\", \"module\": \"myapp\"}\n{\"time\": \"2024-01-15 10:30:45,124\", \"level\": \"ERROR\", \"message\": \"Something went wrong\", \"module\": \"myapp\", \"user_id\": \"12345\"}\n```\n\n### Custom Configuration\n\n```python\nfrom structured_logger import get_logger, LoggerConfig\n\n# Custom configuration\nconfig = LoggerConfig(\n    custom_fields=[\"user_id\", \"request_id\", \"trace_id\"],\n    production_env_vars=[\"ENV\", \"ENVIRONMENT\"],\n    production_env_values=[\"prod\", \"production\", \"staging\"],\n    dev_format=\"%(asctime)s [%(levelname)s] %(name)s: %(message)s\"\n)\n\nlogger = get_logger(__name__, config=config)\n```\n\n### Force JSON or Development Format\n\n```python\n# Always use JSON formatting\nlogger = get_logger(__name__, force_json=True)\n\n# Always use development formatting\nlogger = get_logger(__name__, force_dev=True)\n```\n\n### Root Logger Setup\n\n```python\nfrom structured_logger import setup_root_logger\n\n# Setup root logger for entire application\nsetup_root_logger()\n\n# Now all loggers will use structured format\nimport logging\nlogger = logging.getLogger(\"myapp\")\nlogger.info(\"This will be structured\")\n```\n\n## Advanced Usage\n\n### Custom Serializers\n\n```python\nfrom datetime import datetime\nfrom structured_logger import LoggerConfig, get_logger\n\ndef serialize_datetime(dt):\n    return dt.isoformat()\n\nconfig = LoggerConfig(\n    custom_serializers={\n        datetime: serialize_datetime\n    }\n)\n\nlogger = get_logger(__name__, config=config)\nlogger.info(\"Current time\", extra={\"timestamp\": datetime.now()})\n```\n\n### Context Fields\n\n```python\nimport logging\nfrom structured_logger import get_logger\n\nlogger = get_logger(__name__)\n\n# Add context to log record\nclass ContextFilter(logging.Filter):\n    def filter(self, record):\n        record.user_id = getattr(self, 'user_id', None)\n        record.request_id = getattr(self, 'request_id', None)\n        return True\n\ncontext_filter = ContextFilter()\nlogger.addFilter(context_filter)\n\n# Set context\ncontext_filter.user_id = \"user123\"\ncontext_filter.request_id = \"req456\"\n\nlogger.info(\"Processing request\")  # Will include user_id and request_id\n```\n\n### Exception Logging\n\n```python\ntry:\n    raise ValueError(\"Something went wrong\")\nexcept Exception:\n    logger.exception(\"An error occurred\", extra={\"operation\": \"data_processing\"})\n```\n\n**JSON Output:**\n```json\n{\n  \"time\": \"2024-01-15 10:30:45,123\",\n  \"level\": \"ERROR\", \n  \"message\": \"An error occurred\",\n  \"module\": \"myapp\",\n  \"operation\": \"data_processing\",\n  \"exception\": \"Traceback (most recent call last):\\n  File \\\"example.py\\\", line 2, in <module>\\n    raise ValueError(\\\"Something went wrong\\\")\\nValueError: Something went wrong\"\n}\n```\n\n## Configuration Options\n\n### LoggerConfig Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `production_env_vars` | `List[str]` | `[\"RAILWAY_ENVIRONMENT\", \"ENV\", \"ENVIRONMENT\", \"NODE_ENV\"]` | Environment variables to check for production |\n| `production_env_values` | `List[str]` | `[\"prod\", \"production\", \"staging\"]` | Values that indicate production environment |\n| `log_level_env_var` | `str` | `\"LOG_LEVEL\"` | Environment variable for log level |\n| `default_log_level` | `str` | `\"INFO\"` | Default log level |\n| `custom_fields` | `List[str]` | `[\"user_id\", \"company_id\", \"request_id\", \"trace_id\", \"span_id\"]` | Fields to extract from log records |\n| `time_format` | `Optional[str]` | `None` | Custom time format |\n| `dev_format` | `str` | `\"%(asctime)s [%(levelname)s] %(name)s: %(message)s\"` | Format string for development |\n| `custom_serializers` | `Dict[type, Callable]` | `{}` | Custom serializers for specific types |\n| `include_extra_attrs` | `bool` | `True` | Whether to include extra attributes |\n| `excluded_attrs` | `List[str]` | Standard logging fields | Fields to exclude from extra attributes |\n| `override_uvicorn_loggers` | `bool` | `True` | Enable structured formatting for uvicorn loggers |\n| `uvicorn_loggers` | `List[str]` | `[\"uvicorn\", \"uvicorn.access\", \"uvicorn.error\", \"uvicorn.asgi\"]` | List of uvicorn loggers to override |\n| `override_gunicorn_loggers` | `bool` | `True` | Enable structured formatting for gunicorn loggers |\n| `gunicorn_loggers` | `List[str]` | `[\"gunicorn\", \"gunicorn.access\", \"gunicorn.error\"]` | List of gunicorn loggers to override |\n| `override_library_loggers` | `bool` | `True` | Enable structured formatting for third-party library loggers (httpx, sqlalchemy, etc.) |\n| `library_loggers` | `List[str]` | `[\"httpx\", \"httpcore\", \"sqlalchemy\", \"starlette\", \"fastapi\", ...]` | List of library loggers to override |\n\n### Environment Variables\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `LOG_LEVEL` | Set logging level | `INFO` |\n| `RAILWAY_ENVIRONMENT` | Railway deployment indicator | - |\n| `ENV` | Environment indicator | - |\n| `ENVIRONMENT` | Environment indicator | - |\n| `NODE_ENV` | Node.js style environment | - |\n\n## Framework Integration\n\n### Flask with Gunicorn Integration\n\n```python\nfrom flask import Flask, request, g\nfrom structured_logger import get_logger, setup_gunicorn_logging\nimport uuid\n\n# Option 1: Simple gunicorn setup (recommended)\nsetup_gunicorn_logging(force_json=True)\n\n# Option 2: Full configuration with gunicorn override\nconfig = LoggerConfig(\n    override_gunicorn_loggers=True,  # Enable structured gunicorn logs\n    custom_fields=[\"request_id\", \"user_id\"],\n    include_extra_attrs=True,\n)\n\napp = Flask(__name__)\nlogger = get_logger(__name__, config=config)\n\n@app.before_request\ndef before_request():\n    g.request_id = str(uuid.uuid4())\n\n@app.after_request\ndef after_request(response):\n    logger.info(\n        \"Request processed\",\n        extra={\n            \"request_id\": getattr(g, 'request_id', None),\n            \"method\": request.method,\n            \"path\": request.path,\n            \"status\": response.status_code\n        }\n    )\n    return response\n\n# Run with: gunicorn --workers 4 --bind 0.0.0.0:8000 myapp:app\n# Gunicorn access logs and error logs will now be structured JSON!\n```\n\n### Automatic Logger Overrides (Enabled by Default!)\n\n**All server and library logs are automatically formatted as JSON!** This includes:\n- **Uvicorn**: `uvicorn`, `uvicorn.access`, `uvicorn.error`, `uvicorn.asgi`\n- **Gunicorn**: `gunicorn`, `gunicorn.access`, `gunicorn.error`\n- **HTTP Clients**: `httpx`, `httpcore`, `urllib3`, `requests`, `aiohttp`\n- **Database**: `sqlalchemy` (including engine, pool, orm)\n- **Frameworks**: `starlette`, `fastapi`\n- **Async**: `asyncio`\n\n```python\nfrom structured_logger import get_logger\n\n# That's it! Everything is automatic!\nlogger = get_logger(__name__)\n\n# All logs are now JSON formatted:\n# \u2713 Your application logs\n# \u2713 Uvicorn/Gunicorn logs (automatic!)\n# \u2713 Third-party library logs (automatic!)\n```\n\n**To disable specific overrides:**\n\n```python\nfrom structured_logger import LoggerConfig, get_logger\n\nconfig = LoggerConfig(\n    override_uvicorn_loggers=False,   # Disable uvicorn override\n    override_gunicorn_loggers=False,  # Disable gunicorn override\n    override_library_loggers=False,   # Disable library override\n)\nlogger = get_logger(__name__, config=config)\n```\n\n### FastAPI with Uvicorn Integration\n\n```python\nfrom fastapi import FastAPI, Request\nfrom structured_logger import get_logger\nimport uuid\nimport time\n\n# Simple setup - everything is automatic!\nlogger = get_logger(__name__)\n\n# Or with custom fields\nfrom structured_logger import LoggerConfig\n\nconfig = LoggerConfig(\n    custom_fields=[\"request_id\", \"user_id\"],\n    include_extra_attrs=True,\n    # All overrides are enabled by default:\n    # override_uvicorn_loggers=True\n    # override_library_loggers=True\n    # override_gunicorn_loggers=True\n)\n\napp = FastAPI()\nlogger = get_logger(__name__, config=config)\n\n@app.middleware(\"http\")\nasync def log_requests(request: Request, call_next):\n    request_id = str(uuid.uuid4())\n    start_time = time.time()\n    \n    response = await call_next(request)\n    \n    process_time = time.time() - start_time\n    logger.info(\n        \"Request processed\",\n        extra={\n            \"request_id\": request_id,\n            \"method\": request.method,\n            \"path\": request.url.path,\n            \"status\": response.status_code,\n            \"duration\": process_time\n        }\n    )\n    \n    return response\n\nif __name__ == \"__main__\":\n    import uvicorn\n    # Uvicorn access logs and error logs will now be structured JSON!\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\n### Django\n\n```python\n# settings.py\nLOGGING = {\n    'version': 1,\n    'disable_existing_loggers': False,\n    'handlers': {\n        'structured': {\n            'level': 'INFO',\n            'class': 'structured_logger.logger.StructuredLogHandler',\n        },\n    },\n    'loggers': {\n        'django': {\n            'handlers': ['structured'],\n            'level': 'INFO',\n            'propagate': True,\n        },\n        'myapp': {\n            'handlers': ['structured'],\n            'level': 'INFO',\n            'propagate': True,\n        },\n    },\n}\n```\n\n## Railway.app Compatibility\n\nThis library maintains full compatibility with Railway.app deployments. The original Railway-specific functionality is preserved:\n\n```python\n# These work exactly like before\nfrom structured_logger import get_railway_logger\n\nlogger = get_railway_logger(__name__)\nlogger.info(\"Deployed to Railway!\")\n```\n\n## Development\n\n```bash\n# Clone the repository\ngit clone https://github.com/zee229/structured-logger.git\ncd structured-logger\n\n# Install development dependencies\npip install -e .\n\n# Run examples\npython examples/basic_usage.py\npython examples/custom_config.py\n```\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Uvicorn Integration\n\nNew in v1.3.0! Automatically format uvicorn logs as structured JSON for better log parsing and analysis.\n\n### Quick Setup\n\n```python\nfrom structured_logger import setup_uvicorn_logging\n\n# This will override all uvicorn loggers with structured formatting\nsetup_uvicorn_logging(force_json=True)\n```\n\n### Configuration Options\n\n```python\nfrom structured_logger import LoggerConfig, get_logger\n\nconfig = LoggerConfig(\n    override_uvicorn_loggers=True,  # Enable uvicorn override\n    uvicorn_loggers=[               # Customize which loggers to override\n        \"uvicorn\",\n        \"uvicorn.access\", \n        \"uvicorn.error\",\n        \"uvicorn.asgi\"\n    ],\n    custom_fields=[\"request_id\", \"user_id\"],\n)\n\nlogger = get_logger(__name__, config=config)\n```\n\n### What Gets Formatted\n\nWith uvicorn integration enabled, these logs are automatically structured:\n\n- **uvicorn**: Main uvicorn logger\n- **uvicorn.access**: HTTP access logs\n- **uvicorn.error**: Error logs\n- **uvicorn.asgi**: ASGI-related logs\n\n**Before (plain text):**\n```\nINFO:     127.0.0.1:52000 - \"GET /users/123 HTTP/1.1\" 200 OK\n```\n\n**After (structured JSON):**\n```json\n{\"time\": \"2024-01-01T12:00:00\", \"level\": \"INFO\", \"message\": \"127.0.0.1:52000 - \\\"GET /users/123 HTTP/1.1\\\" 200 OK\", \"module\": \"uvicorn.access\"}\n```\n\n## Changelog\n\n### 1.3.0\n- \u2728 **New**: Uvicorn logger integration for structured FastAPI logs\n- \ud83d\udd27 Added `setup_uvicorn_logging()` convenience function\n- \ud83d\udcdd Enhanced documentation with uvicorn examples\n- \ud83e\uddea Comprehensive test coverage for uvicorn integration\n\n### 1.0.0\n- Initial release\n- Flexible configuration system\n- Environment-aware formatting\n- Custom serializers support\n- Full backward compatibility with Railway logger\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A flexible structured JSON logger for Python applications",
    "version": "1.5.2",
    "project_urls": {
        "Bug Tracker": "https://github.com/zee229/structured-logger/issues",
        "Documentation": "https://github.com/zee229/structured-logger#readme",
        "Homepage": "https://github.com/zee229/structured-logger",
        "Repository": "https://github.com/zee229/structured-logger.git"
    },
    "split_keywords": [
        "logging",
        " json",
        " structured",
        " railway",
        " cloud",
        " docker",
        " kubernetes"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6943df2dca771db3b1272c08b278112d5fe0b044779d151a1cdc360c5151fc2f",
                "md5": "b7df51a229dbc55c8abefafc5b79e6dc",
                "sha256": "05e03bafd3fac8335a5734595d8a3bc1da95298c054ea541a13dd2140db0a599"
            },
            "downloads": -1,
            "filename": "structured_logger_railway-1.5.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b7df51a229dbc55c8abefafc5b79e6dc",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 20424,
            "upload_time": "2025-10-10T07:14:41",
            "upload_time_iso_8601": "2025-10-10T07:14:41.188800Z",
            "url": "https://files.pythonhosted.org/packages/69/43/df2dca771db3b1272c08b278112d5fe0b044779d151a1cdc360c5151fc2f/structured_logger_railway-1.5.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "971703d73c148e1827c47bbe33d547484998d7540fac56cca4b2b6c844acb327",
                "md5": "106557dab35c858a8bef147e59e3177b",
                "sha256": "87fc07dd69a3a9d4513720dd2157c183ebed9c0be19bb11a7e77694200598f64"
            },
            "downloads": -1,
            "filename": "structured_logger_railway-1.5.2.tar.gz",
            "has_sig": false,
            "md5_digest": "106557dab35c858a8bef147e59e3177b",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 18049,
            "upload_time": "2025-10-10T07:14:42",
            "upload_time_iso_8601": "2025-10-10T07:14:42.343161Z",
            "url": "https://files.pythonhosted.org/packages/97/17/03d73c148e1827c47bbe33d547484998d7540fac56cca4b2b6c844acb327/structured_logger_railway-1.5.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-10 07:14:42",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "zee229",
    "github_project": "structured-logger",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "structured-logger-railway"
}
        
Elapsed time: 2.17789s