Skip to main content

A json configured logger for Finalsa projects

Project description

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 >= 4.0.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

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

finalsa_common_logger-1.0.2.tar.gz (7.8 kB view details)

Uploaded Source

Built Distribution

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

finalsa_common_logger-1.0.2-py3-none-any.whl (9.6 kB view details)

Uploaded Python 3

File details

Details for the file finalsa_common_logger-1.0.2.tar.gz.

File metadata

  • Download URL: finalsa_common_logger-1.0.2.tar.gz
  • Upload date:
  • Size: 7.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for finalsa_common_logger-1.0.2.tar.gz
Algorithm Hash digest
SHA256 635cbdf4262d10ef6566bcf3a0085f096e417430d2680fc84acfb1ec33b4175e
MD5 eed62aa92d4be6310f9866353f7dfa9b
BLAKE2b-256 462591ed218d9a44e699684b23c9fcff99704022ad98b61fe99d82aa5304238b

See more details on using hashes here.

File details

Details for the file finalsa_common_logger-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: finalsa_common_logger-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 9.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for finalsa_common_logger-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0e71b274a2de7ba227d470cdf174b3d53c238c206530692c7b8a7183535d0893
MD5 7e5b1170ab102eaa569b7b5fa98f1935
BLAKE2b-256 ec3bfa6eb1471c4ffb7fe7590ea4b9ed359b46969616a7e80e6f9432ef48550b

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