# Structured Logger
[](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[](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"
}