Skip to main content

Finalsa Common Logger

A robust, JSON-configured logger designed for Finalsa projects with built-in correlation ID tracking, structured logging, and AWS Lambda compatibility.

Tests Coverage

Features

  • 🔗 Correlation ID Tracking: Automatic correlation, trace, and span ID injection
  • 📊 Structured JSON Logging: Clean, parseable JSON output for log aggregation
  • AWS Lambda Optimized: Pre-configured for serverless environments
  • 🌐 Access Log Support: Specialized formatter for HTTP access logs
  • 🎯 High Performance: Built on orjson for fast JSON serialization
  • 🔧 Flexible Configuration: Easy setup with sensible defaults
  • 🧪 Well Tested: 98% test coverage with comprehensive integration tests

Installation

# Using uv (recommended)
uv add finalsa-common-logger

# Using pip
pip install finalsa-common-logger

Quick Start

Basic Usage

import logging
from logging.config import dictConfig
from finalsa.common.logger import LAMBDA_DEFAULT_LOGGER

# Apply the default configuration
dictConfig(LAMBDA_DEFAULT_LOGGER)

# Get a logger and start logging
logger = logging.getLogger(__name__)
logger.info("Hello, structured logging!")
logger.error("Something went wrong", extra={"user_id": 12345, "action": "login"})

Output:

{"timestamp": "2024-01-15T12:30:45.123456Z", "level": "INFO", "message": "Hello, structured logging!", "correlation_id": "abc-123", "trace_id": "def-456", "span_id": "ghi-789"}
{"timestamp": "2024-01-15T12:30:46.789012Z", "level": "ERROR", "message": "Something went wrong", "user_id": 12345, "action": "login", "correlation_id": "abc-123", "trace_id": "def-456", "span_id": "ghi-789"}

AWS Lambda Example

import logging
from logging.config import dictConfig
from finalsa.common.logger import LAMBDA_DEFAULT_LOGGER

# Configure logging once at module level
dictConfig(LAMBDA_DEFAULT_LOGGER)
logger = logging.getLogger(__name__)

def lambda_handler(event, context):
    logger.info("Lambda invoked", extra={
        "request_id": context.aws_request_id,
        "function_name": context.function_name
    })
    
    try:
        # Your business logic here
        result = process_event(event)
        logger.info("Lambda completed successfully", extra={"result_count": len(result)})
        return {"statusCode": 200, "body": result}
    
    except Exception as e:
        logger.exception("Lambda execution failed", extra={"event": event})
        return {"statusCode": 500, "body": "Internal server error"}

Access Log Example

import logging
from logging.config import dictConfig
from finalsa.common.logger import LAMBDA_DEFAULT_LOGGER
from finalsa.common.logger.formatter import AccessJsonFormatter

# Setup with access log formatter
config = LAMBDA_DEFAULT_LOGGER.copy()
config['formatters']['access'] = {
    'class': 'finalsa.common.logger.formatter.AccessJsonFormatter'
}
config['handlers']['access'] = {
    'class': 'logging.StreamHandler',
    'formatter': 'access',
    'filters': ['correlation_id']
}
config['loggers']['access'] = {
    'handlers': ['access'],
    'level': 'INFO',
    'propagate': False
}

dictConfig(config)
access_logger = logging.getLogger('access')

# Log HTTP access (ip, method, path, protocol, status_code)
access_logger.info("HTTP Request", "192.168.1.100", "POST", "/api/users", "HTTP/1.1", 201)

Output:

{"timestamp": "2024-01-15T12:30:45.123456Z", "level": "INFO", "client_addr": "192.168.1.100", "method": "POST", "path": "/api/users", "protocol": "HTTP/1.1", "status_code": 201, "correlation_id": "abc-123"}

Configuration

Default Configuration

The LAMBDA_DEFAULT_LOGGER provides a production-ready configuration:

LAMBDA_DEFAULT_LOGGER = {
    'version': 1,
    'disable_existing_loggers': True,
    'filters': {
        'correlation_id': {'()': 'finalsa.common.logger.filter.CorrelationIdFilter'},
    },
    'formatters': {
        'console': {
            'class': 'finalsa.common.logger.CustomJsonFormatter',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'filters': ['correlation_id'],
            'formatter': 'console',
        },
    },
    'loggers': {
        'root': {'handlers': ['console'], 'level': 'INFO', 'propagate': True},
    },
}

Custom Configuration

import logging
from logging.config import dictConfig
from finalsa.common.logger import CorrelationIdFilter, CustomJsonFormatter

# Create your own configuration
CUSTOM_CONFIG = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'correlation_id': {'()': CorrelationIdFilter},
    },
    'formatters': {
        'detailed': {
            'class': CustomJsonFormatter,
            'format': '%(timestamp)s %(level)s %(name)s %(funcName)s:%(lineno)d %(message)s'
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'filters': ['correlation_id'],
            'formatter': 'detailed',
        },
        'file': {
            'class': 'logging.FileHandler',
            'filename': 'app.log',
            'level': 'INFO',
            'filters': ['correlation_id'],
            'formatter': 'detailed',
        }
    },
    'loggers': {
        'myapp': {
            'handlers': ['console', 'file'],
            'level': 'DEBUG',
            'propagate': False
        },
        'root': {
            'handlers': ['console'],
            'level': 'WARNING',
        }
    },
}

dictConfig(CUSTOM_CONFIG)

Components

CorrelationIdFilter

Automatically injects correlation, trace, and span IDs into log records using the finalsa-traceability context.

from finalsa.common.logger import CorrelationIdFilter

# The filter automatically adds these fields to each log record:
# - correlation_id
# - trace_id  
# - span_id

CustomJsonFormatter

A JSON formatter that adds timestamps and normalizes log levels.

from finalsa.common.logger import CustomJsonFormatter

formatter = CustomJsonFormatter()
# Automatically adds:
# - timestamp (ISO 8601 format with microseconds)
# - level (normalized to uppercase)
# - Converts correlation_id to string if present

AccessJsonFormatter

Specialized formatter for HTTP access logs that parses request details from log record arguments.

from finalsa.common.logger.formatter import AccessJsonFormatter

# Expects log record args in this order:
# (client_ip, http_method, path, protocol, status_code)
access_logger.info("Request", "192.168.1.1", "GET", "/api/health", "HTTP/1.1", 200)

Integration with Finalsa Traceability

This logger integrates seamlessly with finalsa-traceability for distributed tracing:

from finalsa.traceability import set_correlation_id, set_trace_id
from finalsa.common.logger import LAMBDA_DEFAULT_LOGGER
import logging

dictConfig(LAMBDA_DEFAULT_LOGGER)
logger = logging.getLogger(__name__)

# Set tracing context
set_correlation_id("user-session-123")
set_trace_id("request-trace-456")

# All subsequent logs will include these IDs
logger.info("Processing user request")  # Will include correlation_id and trace_id

Error Handling

The logger gracefully handles missing dependencies and malformed configurations:

# If finalsa-traceability is not available, correlation IDs will be None
# If log record args are malformed for AccessJsonFormatter, it raises appropriate exceptions
# The logger continues to function even with missing optional fields

Development

Setup

git clone https://github.com/finalsa/finalsa-common-logger.git
cd finalsa-common-logger
uv sync

Running Tests

# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=finalsa.common.logger --cov-report=term-missing

# Run specific test file
uv run pytest tests/test_formatter.py -v

Type Checking

uv run mypy finalsa/

Requirements

  • Python >= 3.10
  • finalsa-traceability >= 1.0.0
  • orjson >= 3.10.15
  • python-json-logger == 3.3.0

License

MIT License - see LICENSE.md for details.

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes with tests
  4. Run the test suite (uv run pytest)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Changelog

v0.1.0

  • Initial release with basic JSON logging
  • Correlation ID filtering
  • AWS Lambda configuration
  • Access log formatter
  • Comprehensive test suite

Release files for finalsa-common-logger 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for finalsa-common-logger 1.0.1
File Size Uploaded
finalsa_common_logger-1.0.1.tar.gz 7.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for finalsa-common-logger 1.0.1
File Interpreter ABI Platform
finalsa_common_logger-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 17.4 kB

Release files / finalsa_common_logger-1.0.1.tar.gz

Download URL finalsa_common_logger-1.0.1.tar.gz
Size 7.8 kB
Tags Source
SHA-256 checksum
How to use checksums
30f26ecc5bee385ef9a6a7bf8f8a37394b167554de852c86fd689b4d9698b499
BLAKE2b-256 checksum
How to use checksums
94598484effb0808933070e12760cb753c0642881bc0c88620c62e7bbe1ec396
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.8.11

Release files / finalsa_common_logger-1.0.1-py3-none-any.whl

Download URL finalsa_common_logger-1.0.1-py3-none-any.whl
Size 9.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
22227df78c5c8ce44b50ace848d0e45fbc6ecf5c5a791efe1d238cafc73becbd
BLAKE2b-256 checksum
How to use checksums
007f32a654ff916b46695fcd19d5a42aa186c5469d67e23edfcb22d269d73c84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.8.11

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files

1.0.0

2 release files

0.1.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page