Back to Index

Logger

Inherits from Task

Contents

The Logger class provides a centralized logging facility for the task framework. It extends the base Task class to integrate with the signal-slot system, handling log messages from various components and formatting them for output. The Logger supports different message levels (log, warning, error) and can be connected to multiple tasks for comprehensive application-wide logging.

Features

Class Interface

class Logger : public Task {
public:
    // Constructor with optional prefix
    explicit Logger(const std::string &prefix = ">>");
    virtual ~Logger() = default;

    // Logging methods
    void log(const ArgumentPack &args);
    void warn(const ArgumentPack &args);
    void error(const ArgumentPack &args);

    // Static helper to create logging signals for a task
    static void createSignalsFor(Task *task);

    // Connect to all signals of a task
    void connectAllSignalsTo(Task *task);
    void connectAllSignalsTo(const std::vector<Task *> &tasks);

private:
    std::string m_prefix;
};

Logging Methods

Method Description Format Use Case
log() Regular informational messages Standard console output General information, status updates
warn() Warning messages Yellow colored text Potential issues, non-critical problems
error() Error messages Red colored text Critical errors, failure conditions

Usage Examples

Basic Logging

Direct Use of Logger
// Create a logger with a custom prefix
auto logger = std::make_shared<Logger>("MyApp");

// Log different types of messages
ArgumentPack infoArgs;
infoArgs.add<std::string>("Application started successfully");
logger->log(infoArgs);

ArgumentPack warnArgs;
warnArgs.add<std::string>("Configuration file not found, using defaults");
logger->warn(warnArgs);

ArgumentPack errorArgs;
errorArgs.add<std::string>("Failed to connect to database: Connection refused");
logger->error(errorArgs);

// Output:
// MyApp Application started successfully
// MyApp WARNING: Configuration file not found, using defaults
// MyApp ERROR: Failed to connect to database: Connection refused

Connecting Logger to Tasks

Centralized Logging for Multiple Components
// Create a logger
auto logger = std::make_shared<Logger>("System");

// Create various components
auto algorithm = std::make_shared<MyAlgorithm>();
auto counter = std::make_shared<Counter>(0, 0, 100);
auto threadPool = std::make_shared<ThreadPool>();

// Connect logger to all components
logger->connectAllSignalsTo(algorithm.get());
logger->connectAllSignalsTo(counter.get());
logger->connectAllSignalsTo(threadPool.get());

// Add tasks to thread pool
threadPool->createAndAdd<MyTask>("Task1", 100);
threadPool->createAndAdd<MyTask>("Task2", 200);

// Execute thread pool - all logging goes through the logger
threadPool->exec();

// Output example:
// System Thread pool executing 2 tasks
// System Task1 started
// System Task2 started
// System Task1 completed successfully
// System Task2 completed successfully
// System Thread pool execution finished in 201ms

Custom Logging Setup

Configuring Logger for Specific Components
// Create specialized loggers for different subsystems
auto systemLogger = std::make_shared<Logger>("SYSTEM");
auto networkLogger = std::make_shared<Logger>("NETWORK");
auto dataLogger = std::make_shared<Logger>("DATA");

// Create components
auto networkComponent = std::make_shared<NetworkHandler>();
auto dataProcessor = std::make_shared<DataProcessor>();
auto systemMonitor = std::make_shared<SystemMonitor>();

// Connect specialized loggers to appropriate components
networkLogger->connectAllSignalsTo(networkComponent.get());
dataLogger->connectAllSignalsTo(dataProcessor.get());
systemLogger->connectAllSignalsTo(systemMonitor.get());

// Example output:
// NETWORK Connection established with server at 192.168.1.100
// DATA Processing 1024 records from dataset
// SYSTEM CPU usage: 45%, Memory: 512MB
// NETWORK WARNING: High latency detected (150ms)
// DATA ERROR: Invalid record format at position 512

Integration with Other Components

The Logger class is designed to integrate with all components in the task framework. Here are some common integration patterns:

With Algorithm

Logging Algorithm Execution
// Create logger and algorithm
auto logger = std::make_shared<Logger>("Processor");
auto algorithm = std::make_shared<DataProcessor>();

// Connect logger to algorithm
logger->connectAllSignalsTo(algorithm.get());

// Execute algorithm with logging
algorithm->exec();

// Typical log output:
// Processor Starting data processing...
// Processor Processing file data.csv
// Processor 25% complete
// Processor 50% complete
// Processor 75% complete
// Processor 100% complete
// Processor Data processing completed successfully

With ThreadPool

Logging Parallel Task Execution
// Create logger and thread pool
auto logger = std::make_shared<Logger>("ThreadPool");
auto pool = std::make_shared<ThreadPool>();

// Connect logger to the thread pool
logger->connectAllSignalsTo(pool.get());

// Add tasks to the pool
for (int i = 0; i < 5; i++) {
    auto task = pool->createAndAdd<MyTask>("Task" + std::to_string(i), i * 100);
    // Connect logger to each task as well
    logger->connectAllSignalsTo(task);
}

// Execute all tasks
pool->exec();

// Output includes both pool and task logs:
// ThreadPool Starting execution of 5 tasks
// ThreadPool Task0 started
// ThreadPool Task1 started
// ThreadPool Task2 started
// ThreadPool Task0 completed
// ThreadPool Task3 started
// ThreadPool Task1 completed
// ThreadPool Task4 started
// ThreadPool Task2 completed
// ThreadPool Task3 completed
// ThreadPool Task4 completed
// ThreadPool All tasks completed in 450ms

Configuration Options

The Logger class provides several configuration options:

Custom Prefix

Setting a Custom Logger Prefix
// Different prefix options
auto logger1 = std::make_shared<Logger>(">>"); // Default
auto logger2 = std::make_shared<Logger>("MyApp");
auto logger3 = std::make_shared<Logger>("[Server]");
auto logger4 = std::make_shared<Logger>("GUI::");

// Output examples:
// >> Application message
// MyApp Application message
// [Server] Application message
// GUI:: Application message

Signal Creation for Tasks

The Logger provides a static helper method to create standard logging signals for Task objects:

Creating Logging Signals
// Creating a custom task with logging capabilities
class MyCustomTask : public Task {
public:
    MyCustomTask() {
        // Create standard logging signals
        Logger::createSignalsFor(this);
        
        // Now the task has log, warn, and error signals
    }
    
    void doSomething() {
        // Use logging signals
        emitString("log", "Operation started");
        
        try {
            // Work...
            
            emitString("log", "Operation completed");
        } catch (const std::exception& e) {
            emitString("error", std::string("Operation failed: ") + e.what());
        }
    }
};

The createSignalsFor() method creates the following signals for the task:

Message Formatting

The Logger formats messages differently based on their type:

Message Formatting Implementation
// Regular log messages
void Logger::log(const ArgumentPack &args) {
    if (!args.empty()) {
        try {
            std::cout << m_prefix << " " << args.get<std::string>(0)
                      << std::endl;
        } catch (const std::bad_cast &) {
            std::cout << m_prefix << " [invalid format]" << std::endl;
        }
    }
}

// Warning messages (yellow text)
void Logger::warn(const ArgumentPack &args) {
    if (!args.empty()) {
        try {
            std::cerr << "\033[33m" << m_prefix
                      << " WARNING: " << args.get<std::string>(0) << "\033[0m"
                      << std::endl;
        } catch (const std::bad_cast &) {
            std::cerr << "\033[33m" << m_prefix
                      << " WARNING: [invalid format]\033[0m" << std::endl;
        }
    }
}

// Error messages (red text)
void Logger::error(const ArgumentPack &args) {
    if (!args.empty()) {
        try {
            std::cerr << "\033[31m" << m_prefix
                      << " ERROR: " << args.get<std::string>(0) << "\033[0m"
                      << std::endl;
        } catch (const std::bad_cast &) {
            std::cerr << "\033[31m" << m_prefix
                      << " ERROR: [invalid format]\033[0m" << std::endl;
        }
    }
}
Note: The color formatting using ANSI escape codes works in most terminal environments but may not be displayed correctly in all console windows. The Logger will still function correctly, but visual formatting may vary.

Thread Safety

The Logger class is designed to be thread-safe for concurrent access:

This allows safe logging from multiple threads in parallel applications:

Thread-Safe Logging Example
// Create a shared logger
auto logger = std::make_shared<Logger>("ThreadSafe");

// Create a thread pool with multiple worker threads
auto pool = std::make_shared<ThreadPool>();

// Add tasks that will log concurrently
for (int i = 0; i < 10; i++) {
    auto task = pool->createAndAdd<LoggingTask>(i);
    
    // Connect logger to each task
    logger->connectAllSignalsTo(task);
}

// Execute all tasks in parallel
pool->exec();

// All log messages will be properly formatted and synchronized,
// even though they're coming from multiple threads simultaneously

Best Practices

Implementation Details