Skip to content

Logger Configuration API

Configuration classes, presets, and utilities for the logger module.

Main Configuration

LoggerConfig

LoggerConfig

Bases: BaseModel

Logger instance configuration.

Source code in src/jinpy_utils/logger/config.py
class LoggerConfig(BaseModel):
    """Logger instance configuration."""

    name: str = Field(..., description="Logger name/identifier")
    level: LogLevel | None = Field(
        default=None,
        description="Override global level",
    )
    backends: list[str] | None = Field(
        default=None,
        description="Backend names to use (None = use all global backends)",
    )
    context: dict[str, Any] = Field(
        default_factory=dict,
        description="Default context",
    )
    correlation_id: str | None = Field(default=None, description="Fixed correlation ID")

    model_config = ConfigDict(extra="allow", use_enum_values=True)

GlobalLoggerConfig

GlobalLoggerConfig

Bases: BaseModel

Global logger configuration following 12-factor app principles.

Source code in src/jinpy_utils/logger/config.py
class GlobalLoggerConfig(BaseModel):
    """Global logger configuration following 12-factor app principles."""

    # Basic settings
    app_name: str = Field(default="jinpy-utils", description="Application name")
    environment: str = Field(
        default="development",
        description="Environment name",
    )
    version: str = Field(default="1.0.0", description="Application version")

    # Default log settings
    default_level: LogLevel = LogLevel.INFO
    correlation_id_header: str = Field(default="X-Correlation-ID")
    enable_correlation_ids: bool = True
    enable_structured_context: bool = True

    # Performance settings
    max_context_size: int = Field(default=10000, gt=0)
    async_queue_size: int = Field(default=10000, gt=0)
    enable_performance_metrics: bool = False

    # Security settings
    enable_sanitization: bool = Field(
        default=True, description="Sanitize sensitive data"
    )
    sensitive_fields: list[str] = Field(
        default_factory=lambda: ["password", "token", "secret", "key", "auth"],
        description="Fields to sanitize in logs",
    )

    # Backends configuration
    backends: list[
        ConsoleBackendConfig
        | FileBackendConfig
        | RestApiBackendConfig
        | WebSocketBackendConfig
        | DatabaseBackendConfig
    ] = Field(default_factory=list)

    # Singleton settings
    enable_singleton: bool = Field(
        default=False, description="Enable singleton pattern"
    )
    singleton_name: str = Field(
        default="default", description="Singleton instance name"
    )

    model_config = ConfigDict(
        extra="ignore", use_enum_values=True, validate_assignment=True
    )

    @classmethod
    def from_env(cls, prefix: str = "LOGGER_") -> "GlobalLoggerConfig":
        """Create configuration from environment variables."""
        # Use an object-typed mapping to satisfy mypy when filling mixed types
        env_vars: dict[str, object] = {}

        # Map environment variables to config fields
        env_mapping = {
            f"{prefix}APP_NAME": "app_name",
            f"{prefix}ENVIRONMENT": "environment",
            f"{prefix}VERSION": "version",
            f"{prefix}LEVEL": "default_level",
            f"{prefix}CORRELATION_HEADER": "correlation_id_header",
            f"{prefix}ENABLE_CORRELATION": "enable_correlation_ids",
            f"{prefix}ENABLE_STRUCTURED": "enable_structured_context",
            f"{prefix}MAX_CONTEXT_SIZE": "max_context_size",
            f"{prefix}QUEUE_SIZE": "async_queue_size",
            f"{prefix}ENABLE_METRICS": "enable_performance_metrics",
            f"{prefix}ENABLE_SANITIZATION": "enable_sanitization",
            f"{prefix}ENABLE_SINGLETON": "enable_singleton",
            f"{prefix}SINGLETON_NAME": "singleton_name",
        }

        for env_var, config_field in env_mapping.items():
            value = os.getenv(env_var)
            if value is None:
                continue
            # Typed conversions
            if config_field in {
                "enable_correlation_ids",
                "enable_structured_context",
                "enable_performance_metrics",
                "enable_sanitization",
                "enable_singleton",
            }:
                env_vars[config_field] = value.lower() in {"true", "1", "yes", "on"}
            elif config_field in {"max_context_size", "async_queue_size"}:
                env_vars[config_field] = int(value)
            elif config_field == "default_level":
                env_vars[config_field] = LogLevel(value.lower())
            else:
                env_vars[config_field] = value

        # Handle sensitive fields
        sensitive_fields_env = os.getenv(f"{prefix}SENSITIVE_FIELDS")
        if sensitive_fields_env:
            env_vars["sensitive_fields"] = [
                field.strip() for field in sensitive_fields_env.split(",")
            ]

        # Construct from mapping via Pydantic for proper typing
        return cls.model_validate(env_vars)

    @model_validator(mode="after")
    def validate_config(self) -> "GlobalLoggerConfig":
        """Validate the complete configuration."""
        if not self.backends:
            # Add default console backend
            self.backends = [ConsoleBackendConfig(name="default_console")]

        # Validate backend names are unique
        backend_names = [backend.name for backend in self.backends]
        if len(backend_names) != len(set(backend_names)):
            raise JPYLoggerConfigurationError(
                message="Backend names must be unique",
                config_section="backends",
            )

        return self

Backend Configurations

BackendConfig

BackendConfig

Bases: BaseModel

Base configuration for logging backends.

Source code in src/jinpy_utils/logger/config.py
class BackendConfig(BaseModel):
    """Base configuration for logging backends."""

    backend_type: BackendType
    name: str = Field(..., description="Unique backend name")
    level: LogLevel = LogLevel.INFO
    format: LogFormat = LogFormat.JSON
    enabled: bool = True
    security: SecurityConfig = Field(default_factory=SecurityConfig)
    retry: RetryConfig = Field(default_factory=RetryConfig)

    # Performance settings
    buffer_size: int = Field(
        default=1000,
        gt=0,
        description="Buffer size for batching",
    )
    flush_interval: float = Field(
        default=5.0, gt=0, description="Flush interval in seconds"
    )
    timeout: float = Field(
        default=30.0, gt=0, description="Operation timeout in seconds"
    )

    model_config = ConfigDict(extra="allow", use_enum_values=True)

ConsoleBackendConfig

ConsoleBackendConfig

Bases: BackendConfig

Configuration for console logging backend.

Source code in src/jinpy_utils/logger/config.py
class ConsoleBackendConfig(BackendConfig):
    """Configuration for console logging backend."""

    backend_type: BackendType = BackendType.CONSOLE
    format: LogFormat = LogFormat.CONSOLE
    colors: bool = Field(default=True, description="Enable colored output")
    stream: str = Field(default="stdout", pattern="^(stdout|stderr)$")

Attributes

format class-attribute instance-attribute

format: LogFormat = CONSOLE

FileBackendConfig

FileBackendConfig

Bases: BackendConfig

Configuration for file logging backend.

Source code in src/jinpy_utils/logger/config.py
class FileBackendConfig(BackendConfig):
    """Configuration for file logging backend."""

    backend_type: BackendType = BackendType.FILE
    file_path: Path = Field(
        default=Path("logs/app.log"),
        description="Log file path",
    )
    max_size_mb: int | None = Field(
        default=100, gt=0, description="Max file size in MB"
    )
    backup_count: int = Field(
        default=5,
        ge=0,
        description="Number of backup files",
    )
    compression: CompressionType = CompressionType.GZIP
    encoding: str = Field(default="utf-8", description="File encoding")

    @field_validator("file_path")
    @classmethod
    def create_log_directory(cls, v: Path) -> Path:
        """Create log directory if it doesn't exist."""
        v.parent.mkdir(parents=True, exist_ok=True)
        return v

Attributes

file_path class-attribute instance-attribute

file_path: Path = Field(
    default=Path("logs/app.log"), description="Log file path"
)

max_size_mb class-attribute instance-attribute

max_size_mb: int | None = Field(
    default=100, gt=0, description="Max file size in MB"
)

backup_count class-attribute instance-attribute

backup_count: int = Field(default=5, ge=0, description="Number of backup files")

encoding class-attribute instance-attribute

encoding: str = Field(default='utf-8', description='File encoding')

compression class-attribute instance-attribute

compression: CompressionType = GZIP

RestApiBackendConfig

RestApiBackendConfig

Bases: BackendConfig

Configuration for REST API logging backend.

Source code in src/jinpy_utils/logger/config.py
class RestApiBackendConfig(BackendConfig):
    """Configuration for REST API logging backend."""

    backend_type: BackendType = BackendType.REST_API
    base_url: str = Field(..., description="Base URL for the logging API")
    endpoint: str = Field(default="/logs", description="Logging endpoint path")
    method: str = Field(default="POST", pattern="^(POST|PUT|PATCH)$")
    headers: dict[str, str] = Field(
        default_factory=dict, description="Additional headers"
    )
    batch_strategy: BatchStrategy = BatchStrategy.HYBRID

    @field_validator("base_url")
    @classmethod
    def validate_url(cls, v: str) -> str:
        """Validate URL format."""
        if not v.startswith(("http://", "https://")):
            raise JPYLoggerConfigurationError(
                message="Invalid URL format - must start with http:// or https://",
                config_section="base_url",
                config_value=v,
            )
        return v.rstrip("/")

Attributes

endpoint class-attribute instance-attribute

endpoint: str = Field(default='/logs', description='Logging endpoint path')

headers class-attribute instance-attribute

headers: dict[str, str] = Field(
    default_factory=dict, description="Additional headers"
)

WebSocketBackendConfig

WebSocketBackendConfig

Bases: BackendConfig

Configuration for WebSocket logging backend.

Source code in src/jinpy_utils/logger/config.py
class WebSocketBackendConfig(BackendConfig):
    """Configuration for WebSocket logging backend."""

    backend_type: BackendType = BackendType.WEBSOCKET
    ws_url: str = Field(..., description="WebSocket URL")
    reconnect_interval: float = Field(
        default=5.0, gt=0, description="Reconnection interval"
    )
    ping_interval: float = Field(
        default=30.0,
        gt=0,
        description="Ping interval",
    )
    max_message_size: int = Field(
        default=1024 * 1024, gt=0, description="Max message size"
    )

    @field_validator("ws_url")
    @classmethod
    def validate_ws_url(cls, v: str) -> str:
        """Validate WebSocket URL format."""
        if not v.startswith(("ws://", "wss://")):
            raise JPYLoggerConfigurationError(
                message="Invalid WebSocket URL format - must start with ws:// or wss://",
                config_section="ws_url",
                config_value=v,
            )
        return v

Attributes

reconnect_interval class-attribute instance-attribute

reconnect_interval: float = Field(
    default=5.0, gt=0, description="Reconnection interval"
)

ping_interval class-attribute instance-attribute

ping_interval: float = Field(default=30.0, gt=0, description='Ping interval')

DatabaseBackendConfig

DatabaseBackendConfig

Bases: BackendConfig

Configuration for database logging backend.

Source code in src/jinpy_utils/logger/config.py
class DatabaseBackendConfig(BackendConfig):
    """Configuration for database logging backend."""

    backend_type: BackendType = BackendType.DATABASE
    connection_string: str = Field(
        ...,
        description="Database connection string",
    )
    table_name: str = Field(default="logs", description="Table name for logs")
    schema_name: str | None = Field(default=None, description="Schema name")
    pool_size: int = Field(default=5, gt=0, description="Connection pool size")
    pool_timeout: float = Field(default=30.0, gt=0, description="Pool timeout")

RetryConfig

RetryConfig

Bases: BaseModel

Retry configuration for backend operations.

Source code in src/jinpy_utils/logger/config.py
class RetryConfig(BaseModel):
    """Retry configuration for backend operations."""

    strategy: RetryStrategy = RetryStrategy.EXPONENTIAL
    max_attempts: int = Field(default=3, ge=1, le=10)
    base_delay: float = Field(default=1.0, gt=0)
    max_delay: float = Field(default=60.0, gt=0)
    backoff_multiplier: float = Field(default=2.0, gt=1)
    jitter: bool = Field(
        default=True,
        description="Add random jitter to delays",
    )

SecurityConfig

SecurityConfig

Bases: BaseModel

Security configuration for logger backends.

Source code in src/jinpy_utils/logger/config.py
class SecurityConfig(BaseModel):
    """Security configuration for logger backends."""

    level: SecurityLevel = SecurityLevel.NONE
    api_key: str | None = Field(default=None, description="API key for authentication")
    tls_cert_path: Path | None = Field(default=None, description="TLS certificate path")
    tls_key_path: Path | None = Field(default=None, description="TLS private key path")
    ca_cert_path: Path | None = Field(default=None, description="CA certificate path")
    verify_ssl: bool = Field(
        default=True,
        description="Verify SSL certificates",
    )
    oauth2_token: str | None = Field(
        default=None,
        description="OAuth2 access token",
    )

    @field_validator("api_key", "oauth2_token")
    @classmethod
    def validate_secrets(cls, v: str | None) -> str | None:
        """Validate secret fields by checking environment variables."""
        if v and v.startswith("${") and v.endswith("}"):
            env_var = v[2:-1]
            return os.getenv(env_var)
        return v

Configuration Presets

create_development_config

create_development_config

create_development_config() -> GlobalLoggerConfig

Create development environment configuration.

Source code in src/jinpy_utils/logger/config.py
def create_development_config() -> GlobalLoggerConfig:
    """Create development environment configuration."""
    return GlobalLoggerConfig(
        environment="development",
        default_level=LogLevel.DEBUG,
        backends=[
            ConsoleBackendConfig(
                name="dev_console", colors=True, format=LogFormat.CONSOLE
            )
        ],
    )

create_production_config

create_production_config

create_production_config() -> GlobalLoggerConfig

Create production environment configuration.

Source code in src/jinpy_utils/logger/config.py
def create_production_config() -> GlobalLoggerConfig:
    """Create production environment configuration."""
    return GlobalLoggerConfig(
        environment="production",
        default_level=LogLevel.INFO,
        enable_performance_metrics=True,
        backends=[
            FileBackendConfig(
                name="prod_file",
                # Use a relative, writable default to avoid permission issues
                # in environments where creating system directories is not allowed.
                file_path=Path("logs/app.log"),
                format=LogFormat.JSON,
                max_size_mb=100,
                backup_count=10,
            )
        ],
    )

create_cloud_config

create_cloud_config

create_cloud_config(api_url: str, api_key: str) -> GlobalLoggerConfig

Create cloud logging configuration.

Source code in src/jinpy_utils/logger/config.py
def create_cloud_config(api_url: str, api_key: str) -> GlobalLoggerConfig:
    """Create cloud logging configuration."""
    return GlobalLoggerConfig(
        environment="cloud",
        default_level=LogLevel.INFO,
        backends=[
            RestApiBackendConfig(
                name="cloud_api",
                base_url=api_url,
                security=SecurityConfig(
                    level=SecurityLevel.API_KEY,
                    api_key=api_key,
                ),
                batch_strategy=BatchStrategy.HYBRID,
            )
        ],
    )

Enums and Constants

LogLevel

LogLevel

Bases: str, Enum

Log level enumeration with string values.

Source code in src/jinpy_utils/logger/enums.py
class LogLevel(str, Enum):
    """Log level enumeration with string values."""

    TRACE = "trace"
    DEBUG = "debug"
    INFO = "info"
    WARNING = "warning"
    ERROR = "error"
    CRITICAL = "critical"

    @property
    def numeric_value(self) -> int:
        """Get numeric value for log level comparison."""
        mapping = {
            self.TRACE: 5,
            self.DEBUG: 10,
            self.INFO: 20,
            self.WARNING: 30,
            self.ERROR: 40,
            self.CRITICAL: 50,
        }
        return mapping[self]

    def __ge__(self, other: "LogLevel") -> bool:  # type:ignore
        """Greater than or equal comparison."""
        return self.numeric_value >= other.numeric_value

    def __gt__(self, other: "LogLevel") -> bool:  # type:ignore
        """Greater than comparison."""
        return self.numeric_value > other.numeric_value

    def __le__(self, other: "LogLevel") -> bool:  # type:ignore
        """Less than or equal comparison."""
        return self.numeric_value <= other.numeric_value

    def __lt__(self, other: "LogLevel") -> bool:  # type:ignore
        """Less than comparison."""
        return self.numeric_value < other.numeric_value

LogFormat

LogFormat

Bases: str, Enum

Log output format options.

Source code in src/jinpy_utils/logger/enums.py
class LogFormat(str, Enum):
    """Log output format options."""

    JSON = "json"
    CONSOLE = "console"
    PLAIN = "plain"
    STRUCTURED = "structured"
    CEF = "cef"  # Common Event Format
    GELF = "gelf"  # Graylog Extended Log Format

BackendType

BackendType

Bases: str, Enum

Supported logging backend types.

Source code in src/jinpy_utils/logger/enums.py
class BackendType(str, Enum):
    """Supported logging backend types."""

    CONSOLE = "console"
    FILE = "file"
    ROTATING_FILE = "rotating_file"
    REST_API = "rest_api"
    DATABASE = "database"
    WEBSOCKET = "websocket"
    SYSLOG = "syslog"
    MEMORY = "memory"
    REDIS = "redis"
    KAFKA = "kafka"
    ELASTICSEARCH = "elasticsearch"

BatchStrategy

BatchStrategy

Bases: str, Enum

Batching strategies for backends.

Source code in src/jinpy_utils/logger/enums.py
class BatchStrategy(str, Enum):
    """Batching strategies for backends."""

    SIZE_BASED = "size_based"
    TIME_BASED = "time_based"
    HYBRID = "hybrid"
    IMMEDIATE = "immediate"

CompressionType

CompressionType

Bases: str, Enum

Compression types for log files.

Source code in src/jinpy_utils/logger/enums.py
class CompressionType(str, Enum):
    """Compression types for log files."""

    NONE = "none"
    GZIP = "gzip"
    BZIP2 = "bzip2"
    XZ = "xz"
    ZIP = "zip"

ConnectionState

ConnectionState

Bases: str, Enum

Connection states for backends.

Source code in src/jinpy_utils/logger/enums.py
class ConnectionState(str, Enum):
    """Connection states for backends."""

    DISCONNECTED = "disconnected"
    CONNECTING = "connecting"
    CONNECTED = "connected"
    RECONNECTING = "reconnecting"
    FAILED = "failed"
    CLOSED = "closed"

RetryStrategy

RetryStrategy

Bases: str, Enum

Retry strategies for failed operations.

Source code in src/jinpy_utils/logger/enums.py
class RetryStrategy(str, Enum):
    """Retry strategies for failed operations."""

    NONE = "none"
    LINEAR = "linear"
    EXPONENTIAL = "exponential"
    FIXED = "fixed"

SecurityLevel

SecurityLevel

Bases: str, Enum

Security levels for logging operations.

Source code in src/jinpy_utils/logger/enums.py
class SecurityLevel(str, Enum):
    """Security levels for logging operations."""

    NONE = "none"
    BASIC = "basic"
    TLS = "tls"
    MUTUAL_TLS = "mutual_tls"
    API_KEY = "api_key"
    OAUTH2 = "oauth2"

Examples

Basic Configuration

from jinpy_utils.logger import LoggerConfig, ConsoleBackendConfig, LogLevel

config = LoggerConfig(
    level=LogLevel.INFO,
    backends=[
        ConsoleBackendConfig(
            level=LogLevel.DEBUG,
            use_colors=True
        )
    ]
)

File Logging Configuration

from jinpy_utils.logger import LoggerConfig, FileBackendConfig, LogLevel, LogFormat

config = LoggerConfig(
    level=LogLevel.DEBUG,
    backends=[
        FileBackendConfig(
            level=LogLevel.INFO,
            file_path="logs/app.log",
            format=LogFormat.JSON,
            max_size_mb=50,
            backup_count=10,
            compression=True
        )
    ]
)

Multiple Backend Configuration

from jinpy_utils.logger import (
    LoggerConfig,
    ConsoleBackendConfig,
    FileBackendConfig,
    RestApiBackendConfig,
    LogLevel
)

config = LoggerConfig(
    level=LogLevel.DEBUG,
    async_enabled=True,
    backends=[
        ConsoleBackendConfig(
            level=LogLevel.DEBUG,
            use_colors=True
        ),
        FileBackendConfig(
            level=LogLevel.INFO,
            file_path="logs/app.log",
            max_size_mb=100,
            backup_count=5
        ),
        RestApiBackendConfig(
            level=LogLevel.ERROR,
            endpoint="https://logs.example.com/api/logs",
            batch_size=50
        )
    ]
)

Environment-Based Configuration

import os
from jinpy_utils.logger import LoggerConfig, create_development_config, create_production_config

def get_config() -> LoggerConfig:
    """Get configuration based on environment."""
    env = os.environ.get("ENVIRONMENT", "development")

    if env == "production":
        return create_production_config()
    elif env == "staging":
        return create_production_config(level=LogLevel.DEBUG)
    else:
        return create_development_config()

config = get_config()

Configuration Validation

from jinpy_utils.logger import LoggerConfig, ConsoleBackendConfig
from jinpy_utils.base import JPYConfigurationError

try:
    config = LoggerConfig(
        level=LogLevel.INFO,
        backends=[
            ConsoleBackendConfig(
                level=LogLevel.DEBUG
            )
        ]
    )
    config.validate()
except JPYConfigurationError as e:
    print(f"Configuration error: {e.message}")

Dynamic Configuration Updates

from jinpy_utils.logger import get_logger, LoggerConfig, FileBackendConfig

logger = get_logger("app")

# Add a new backend at runtime
file_backend = FileBackendConfig(
    level=LogLevel.WARNING,
    file_path="warnings.log"
)

logger.add_backend(file_backend)

Configuration Serialization

from jinpy_utils.logger import LoggerConfig, ConsoleBackendConfig
import json

# Create configuration
config = LoggerConfig(
    level=LogLevel.INFO,
    backends=[ConsoleBackendConfig(level=LogLevel.DEBUG)]
)

# Serialize to dictionary
config_dict = config.to_dict()

# Save to JSON file
with open("logger_config.json", "w") as f:
    json.dump(config_dict, f, indent=2)

# Load from JSON file
with open("logger_config.json", "r") as f:
    loaded_dict = json.load(f)

# Recreate configuration
loaded_config = LoggerConfig.from_dict(loaded_dict)

Advanced REST API Configuration

from jinpy_utils.logger import LoggerConfig, RestApiBackendConfig, RetryConfig, SecurityConfig

config = LoggerConfig(
    backends=[
        RestApiBackendConfig(
            level=LogLevel.INFO,
            endpoint="https://logs.example.com/api/v1/logs",
            headers={
                "Authorization": "Bearer YOUR_TOKEN",
                "Content-Type": "application/json",
                "X-Source": "jinpy-utils"
            },
            timeout_seconds=30,
            retry_config=RetryConfig(
                max_attempts=5,
                backoff_factor=2.0,
                backoff_strategy=RetryStrategy.EXPONENTIAL
            ),
            security_config=SecurityConfig(
                encrypt_payload=True,
                verify_ssl=True,
                security_level=SecurityLevel.HIGH
            ),
            batch_size=100,
            batch_timeout=10.0,
            max_queue_size=10000
        )
    ]
)

Cloud-Optimized Configuration

from jinpy_utils.logger import create_cloud_config
import os

config = create_cloud_config(
    service_name=os.environ.get("SERVICE_NAME", "my-service"),
    environment=os.environ.get("ENVIRONMENT", "production"),
    version=os.environ.get("SERVICE_VERSION", "1.0.0"),
    cloud_provider=os.environ.get("CLOUD_PROVIDER", "aws"),  # aws, gcp, azure
    region=os.environ.get("AWS_REGION", "us-east-1")
)

WebSocket Configuration with Reconnection

from jinpy_utils.logger import LoggerConfig, WebSocketBackendConfig

config = LoggerConfig(
    backends=[
        WebSocketBackendConfig(
            level=LogLevel.INFO,
            endpoint="wss://logs.example.com/ws",
            headers={
                "Authorization": "Bearer YOUR_TOKEN"
            },
            reconnect_interval=5.0,
            max_reconnect_attempts=10,
            ping_interval=30.0,
            ping_timeout=10.0,
            compression=True
        )
    ]
)

Configuration Best Practices

Environment Variables

import os
from jinpy_utils.logger import LoggerConfig, FileBackendConfig, LogLevel

def create_config_from_env() -> LoggerConfig:
    """Create configuration from environment variables."""
    return LoggerConfig(
        level=LogLevel[os.environ.get("LOG_LEVEL", "INFO")],
        async_enabled=os.environ.get("LOG_ASYNC", "true").lower() == "true",
        backends=[
            FileBackendConfig(
                file_path=os.environ.get("LOG_FILE", "app.log"),
                max_size_mb=int(os.environ.get("LOG_MAX_SIZE_MB", "100")),
                backup_count=int(os.environ.get("LOG_BACKUP_COUNT", "5"))
            )
        ]
    )

Configuration Hierarchy

from pathlib import Path
import yaml
from jinpy_utils.logger import LoggerConfig

def load_hierarchical_config() -> LoggerConfig:
    """Load configuration with hierarchy."""
    config_sources = [
        Path("/etc/myapp/logging.yaml"),        # System config
        Path.home() / ".myapp" / "logging.yaml", # User config
        Path("logging.yaml"),                    # Local config
    ]

    merged_config = {}
    for config_file in config_sources:
        if config_file.exists():
            with open(config_file) as f:
                config = yaml.safe_load(f)
                merged_config.update(config)

    return LoggerConfig.from_dict(merged_config.get("logger", {}))

Configuration Validation

from jinpy_utils.logger import LoggerConfig
from jinpy_utils.base import JPYConfigurationError

def validate_production_config(config: LoggerConfig) -> None:
    """Validate configuration for production use."""
    if config.level.value < LogLevel.INFO.value:
        raise JPYConfigurationError(
            message="Production logging level should be INFO or higher",
            config_key="level",
            suggestions=["Set level to INFO, WARNING, or ERROR"]
        )

    if not config.async_enabled:
        raise JPYConfigurationError(
            message="Async logging should be enabled in production",
            config_key="async_enabled",
            suggestions=["Set async_enabled to True for better performance"]
        )

Testing Configuration

from jinpy_utils.logger import LoggerConfig, ConsoleBackendConfig, LogLevel

def create_test_config() -> LoggerConfig:
    """Create configuration optimized for testing."""
    return LoggerConfig(
        level=LogLevel.WARNING,  # Reduce noise in tests
        async_enabled=False,     # Synchronous for predictable testing
        backends=[
            ConsoleBackendConfig(
                level=LogLevel.WARNING,
                use_colors=False,    # No colors in test output
                show_source=False    # Cleaner test output
            )
        ]
    )