Skip to main content

A flexible structured JSON logger for Python applications

Project description

Structured Logger

PyPI version

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
  • Zero dependencies - uses only Python standard library

Installation

pip install structured-logger-railway

Quick Start

Basic Usage

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:

{"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

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

# 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

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

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

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

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

JSON Output:

{
  "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

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

from flask import Flask, request, g
from structured_logger import get_logger
import uuid

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

@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

FastAPI

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

app = FastAPI()
logger = get_logger(__name__)

@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

Django

# 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:

# These work exactly like before
from structured_logger import get_railway_logger

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

Development

# 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 file for details.

Changelog

1.0.0

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

structured_logger_railway-1.2.1.tar.gz (13.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

structured_logger_railway-1.2.1-py3-none-any.whl (16.5 kB view details)

Uploaded Python 3

File details

Details for the file structured_logger_railway-1.2.1.tar.gz.

File metadata

File hashes

Hashes for structured_logger_railway-1.2.1.tar.gz
Algorithm Hash digest
SHA256 a878fef7e7d2a96dfe7f17a4fbeed9f2f617360acc4a7b012cf4d1727f5027a1
MD5 29cba559f4362adcc321ebfacb8031ca
BLAKE2b-256 b43db7426d3f7d4de29492577fee8204cd8f4b7ade7c7cf8eabb6471c26db64b

See more details on using hashes here.

File details

Details for the file structured_logger_railway-1.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for structured_logger_railway-1.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f7c744a92f01dc0493da6eb85d20d8685d06f701c750a464a929d1c94f6ac947
MD5 15a391f101a825e6fbcabdc3254a6877
BLAKE2b-256 58fb4d43a6b0ab5d82013ee830ddb7fdfaff60d706bcf62404685eeefec42fd7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page