CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cement

Advanced Application Framework for Python with a focus on Command Line Interfaces

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

logging.mddocs/

Logging System

The logging system provides comprehensive logging functionality with console and file output support, multiple log levels, colorized output options, and integration with Python's standard logging module.

Capabilities

Log Handler Interface

Base interface for logging functionality that defines the contract for logging operations.

class LogHandler:
    """
    Logging handler interface for application logging functionality.
    
    Provides methods for logging at different levels and controlling
    log output configuration and formatting.
    """
    
    def set_level(self, level: str) -> None:
        """
        Set the logging level.
        
        Args:
            level: Logging level ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
        """
    
    def get_level(self) -> str:
        """
        Get the current logging level.
        
        Returns:
            Current logging level string
        """
    
    def debug(self, msg: str, **kwargs: Any) -> None:
        """
        Log a debug message.
        
        Args:
            msg: Message to log
            **kwargs: Additional keyword arguments for formatting
        """
    
    def info(self, msg: str, **kwargs: Any) -> None:
        """
        Log an info message.
        
        Args:
            msg: Message to log
            **kwargs: Additional keyword arguments for formatting
        """
    
    def warning(self, msg: str, **kwargs: Any) -> None:
        """
        Log a warning message.
        
        Args:
            msg: Message to log
            **kwargs: Additional keyword arguments for formatting
        """
    
    def error(self, msg: str, **kwargs: Any) -> None:
        """
        Log an error message.
        
        Args:
            msg: Message to log
            **kwargs: Additional keyword arguments for formatting
        """
    
    def fatal(self, msg: str, **kwargs: Any) -> None:
        """
        Log a fatal/critical message.
        
        Args:
            msg: Message to log
            **kwargs: Additional keyword arguments for formatting
        """

Usage Examples

Basic Logging

from cement import App, Controller, ex

class BaseController(Controller):
    class Meta:
        label = 'base'
    
    @ex(help='demonstrate logging')
    def demo(self):
        """Demonstrate different logging levels."""
        self.app.log.debug('This is a debug message')
        self.app.log.info('Application started successfully')
        self.app.log.warning('This is a warning message')
        self.app.log.error('An error occurred')
        
        try:
            # Simulate an operation that might fail
            result = 10 / 0
        except ZeroDivisionError:
            self.app.log.error('Division by zero error occurred')

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        handlers = [BaseController]

with MyApp() as app:
    app.setup()
    
    # Set logging level
    app.log.set_level('DEBUG')
    
    app.run()

File Logging Configuration

from cement import App, init_defaults

CONFIG = init_defaults('myapp')
CONFIG['log.logging'] = {
    'file': '/var/log/myapp.log',
    'level': 'INFO',
    'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    'rotate': True,
    'max_bytes': 1024000,  # 1MB
    'max_files': 5
}

class MyApp(App):
    class Meta:
        label = 'myapp'
        config_defaults = CONFIG
        log_handler = 'logging'

with MyApp() as app:
    app.setup()
    
    app.log.info('Application started')
    app.log.debug('Debug information')
    app.log.warning('Warning message')
    
    app.run()

Colorized Logging

from cement import App, init_defaults

CONFIG = init_defaults('myapp')
CONFIG['log.colorlog'] = {
    'level': 'DEBUG',
    'format': '%(log_color)s%(levelname)s%(reset)s - %(message)s',
    'colors': {
        'DEBUG': 'cyan',
        'INFO': 'green', 
        'WARNING': 'yellow',
        'ERROR': 'red',
        'CRITICAL': 'bold_red'
    }
}

class MyApp(App):
    class Meta:
        label = 'myapp'
        extensions = ['colorlog']
        log_handler = 'colorlog'
        config_defaults = CONFIG

with MyApp() as app:
    app.setup()
    
    app.log.debug('Debug message in cyan')
    app.log.info('Info message in green')
    app.log.warning('Warning message in yellow')
    app.log.error('Error message in red')
    
    app.run()

Custom Logging Configuration

from cement import App, Controller, ex
import logging

class LoggingController(Controller):
    class Meta:
        label = 'logging'
        stacked_on = 'base'
        stacked_type = 'nested'
    
    @ex(
        help='set logging level',
        arguments=[
            (['level'], {
                'choices': ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
                'help': 'logging level to set'
            })
        ]
    )  
    def set_level(self):
        """Set the logging level."""
        level = self.app.pargs.level
        self.app.log.set_level(level)
        self.app.log.info(f'Logging level set to {level}')
    
    @ex(help='show current logging level')
    def get_level(self):
        """Show current logging level."""
        level = self.app.log.get_level()
        print(f'Current logging level: {level}')
    
    @ex(help='test all logging levels')
    def test(self):
        """Test all logging levels."""
        self.app.log.debug('Debug level message')
        self.app.log.info('Info level message')
        self.app.log.warning('Warning level message')
        self.app.log.error('Error level message')
        self.app.log.fatal('Fatal level message')

class BaseController(Controller):
    class Meta:
        label = 'base'

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        handlers = [
            BaseController,
            LoggingController
        ]

with MyApp() as app:
    app.run()

# Usage:
# myapp logging set-level DEBUG
# myapp logging get-level
# myapp logging test

Structured Logging

from cement import App, Controller, ex
import json
import logging

class StructuredLogHandler(logging.Handler):
    """Custom handler for structured JSON logging."""
    
    def emit(self, record):
        log_entry = {
            'timestamp': self.format_time(record),
            'level': record.levelname,
            'message': record.getMessage(),
            'module': record.module,
            'function': record.funcName,
            'line': record.lineno
        }
        
        # Add extra fields if present
        if hasattr(record, 'user_id'):
            log_entry['user_id'] = record.user_id
        if hasattr(record, 'request_id'):
            log_entry['request_id'] = record.request_id
            
        print(json.dumps(log_entry))
    
    def format_time(self, record):
        import datetime
        return datetime.datetime.fromtimestamp(record.created).isoformat()

class BaseController(Controller):
    class Meta:
        label = 'base'
    
    @ex(help='demonstrate structured logging')
    def structured_demo(self):
        """Demonstrate structured logging with extra fields."""
        # Log with extra context
        extra = {
            'user_id': 'user_123',
            'request_id': 'req_456'
        }
        
        self.app.log.info('User login attempt', extra=extra)
        self.app.log.warning('Invalid login credentials', extra=extra)
        self.app.log.error('Database connection failed', extra=extra)

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        handlers = [BaseController]
    
    def setup(self):
        super().setup()
        
        # Add structured logging handler
        structured_handler = StructuredLogHandler()
        self.log.logger.addHandler(structured_handler)

with MyApp() as app:
    app.run()

Logging with Context Managers

from cement import App, Controller, ex
import contextlib
import time

@contextlib.contextmanager
def log_execution_time(logger, operation_name):
    """Context manager to log operation execution time."""
    start_time = time.time()
    logger.info(f'Starting {operation_name}')
    
    try:
        yield
        execution_time = time.time() - start_time
        logger.info(f'Completed {operation_name} in {execution_time:.2f} seconds')
    except Exception as e:
        execution_time = time.time() - start_time
        logger.error(f'Failed {operation_name} after {execution_time:.2f} seconds: {e}')
        raise

class BaseController(Controller):
    class Meta:
        label = 'base'
    
    @ex(help='demonstrate logging with context manager')
    def timed_operation(self):
        """Demonstrate timed operation logging."""
        with log_execution_time(self.app.log, 'data processing'):
            # Simulate some work
            time.sleep(2)
            self.app.log.info('Processing data...')
            time.sleep(1)
            self.app.log.info('Data processing completed')

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        handlers = [BaseController]

with MyApp() as app:
    app.run()

Multiple Log Destinations

from cement import App, init_defaults
import logging
import sys

CONFIG = init_defaults('myapp')
CONFIG['log.logging'] = {
    'level': 'INFO',
    'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
}

class MyApp(App):
    class Meta:
        label = 'myapp'
        config_defaults = CONFIG
        log_handler = 'logging'
    
    def setup(self):
        super().setup()
        
        # Add file handler
        file_handler = logging.FileHandler('/var/log/myapp.log')
        file_formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        )
        file_handler.setFormatter(file_formatter)
        file_handler.setLevel(logging.INFO)
        
        # Add console handler for errors only
        error_handler = logging.StreamHandler(sys.stderr)
        error_formatter = logging.Formatter(
            'ERROR: %(message)s'
        )
        error_handler.setFormatter(error_formatter)
        error_handler.setLevel(logging.ERROR)
        
        # Add handlers to logger
        self.log.logger.addHandler(file_handler)
        self.log.logger.addHandler(error_handler)

with MyApp() as app:
    app.setup()
    
    app.log.info('This goes to file and console')
    app.log.warning('This goes to file and console')
    app.log.error('This goes to file, console, and stderr')
    
    app.run()

Install with Tessl CLI

npx tessl i tessl/pypi-cement

docs

arguments.md

caching.md

configuration.md

controllers.md

extensions.md

foundation.md

hooks.md

index.md

interface-handler.md

logging.md

mail.md

output.md

plugins.md

templates.md

utilities.md

tile.json