# ldastoolsal - LDAS Tools System Abstraction Layer

## Overview
The LDAS Tools System Abstraction Layer provides cross-platform C++ abstractions for system operations, threading, logging, and I/O utilities. Serves as the foundational layer enabling consistent behavior across different operating systems for gravitational wave data analysis applications.

## Enhanced Hierarchical Logging System

### New Features (2025)
The logging system has been significantly enhanced with hierarchical channel-based logging, lazy evaluation, and advanced message routing capabilities.

#### Key Components
- **LoggerRegistry**: Manages hierarchical loggers with dot-separated namespaces
- **PatternMatcher**: Flexible pattern matching for group configuration  
- **ScopedChannelVerbosity**: RAII temporary debug level changes
- **Multi-sink routing**: Debug messages to stderr, others to stdout/files
- **Lazy evaluation**: No string construction for filtered messages

## Architecture

### Core Design Patterns
- **RAII**: Resource management with automatic cleanup
- **Singleton**: ThreadPool and SignalHandler for single instances  
- **Template Programming**: Type-safe, flexible interfaces
- **Exception Safety**: Strong exception safety guarantees
- **Cross-Platform**: Consistent interfaces hiding platform specifics

### Library Structure
```
ldastoolsal/src/
├── Threading/            # Thread and concurrency management
│   ├── Thread.hh/.cc     # Thread abstraction with cancellation
│   ├── ThreadPool.hh/.cc # Singleton thread pool
│   ├── Task.hh/.cc       # Abstract task framework
│   ├── TaskTimer.hh/.cc  # Time-limited task execution
│   └── mutexlock.hh/.cc  # RAII mutex locking
├── System/               # System utilities and abstractions
│   ├── System.hh/.cc     # System-level utilities
│   ├── SystemCall.hh/.cc # OS operation wrapper
│   ├── Fork.hh/.cc       # Process forking abstraction
│   └── SignalHandler.hh/.cc # Centralized signal management
├── Logging/              # Logging and error handling
│   ├── SimpleLogger.hh/.cc # Modern Boost.Log-based logging
│   ├── Logger.hh         # Template logging interface
│   └── ErrorLog.hh/.cc   # Legacy error reporting
├── Memory/               # Memory management and debugging
│   ├── MemChecker.hh/.cc # Garbage collection system
│   └── Profile.hh        # Performance profiling
├── IO/                   # File system and I/O utilities
│   ├── fstream.hh/.cc    # Enhanced file streams
│   ├── Directory.hh/.cc  # Directory operations
│   └── MkDir.hh/.cc      # Directory creation
└── Time/                 # GPS time handling
    └── gpstime.hh/.cc    # GPS time system
```

## Threading and Concurrency

### Thread Management
```cpp
// Thread class with comprehensive cancellation support
class Thread {
public:
    enum CancellationType {
        ABANDON,       // No cleanup, immediate termination
        IGNORE,        // Ignore cancellation requests
        ASYNCHRONOUS,  // Cancel immediately at any point
        DEFERRED,      // Cancel at next cancellation point
        EXCEPTION,     // Cancel via exception
        BY_SIGNAL      // Cancel via signal
    };
    
    // Thread state management
    bool alive() const;
    bool cancelled() const;
    bool detached() const;
};
```

### Thread Pool Pattern
```cpp
// Singleton-based thread pool
class ThreadPool {
public:
    static Thread* Acquire();              // Get thread from pool
    static void Relinquish(Thread* thread); // Return thread to pool
    
    // Usage pattern
    auto* thread = ThreadPool::Acquire();
    // Use thread for work
    ThreadPool::Relinquish(thread);
};
```

### Task Framework
```cpp
// Abstract base class for units of work
class Task {
public:
    virtual void operator()() = 0;  // Work implementation
    
    // Task configuration
    void SetName(const std::string& name);
    void SetCancellationMethod(CancellationType type);
    void SetCancellationSignal(int signal);
};

// Time-limited task execution
class TaskTimer {
public:
    TaskTimer(Task& task, double timeout);
    void Execute();  // Run with timeout protection
};
```

### Synchronization Primitives
```cpp
// RAII-based mutex locking
class MutexLock {
public:
    MutexLock();
    ~MutexLock();  // Automatic unlock
    
    void Lock();
    void Unlock();
    bool TryLock();
};

// Template-based variable protection
template<typename T>
class MutexLockVariable {
    T data;
    mutable MutexLock lock;
public:
    void Set(const T& value);
    T Get() const;
};
```

## Logging Framework

### Hierarchical Channel-Based Logging
```cpp
// Get loggers for specific channels/modules
auto* framecpp_logger = get_channel_logger("framecpp");
auto* frtoc_logger = get_channel_logger("framecpp.frtoc");
auto* frvect_logger = get_channel_logger("framecpp.frvect");

// Declare static channel loggers (recommended)
DECLARE_CHANNEL_LOGGER(framecpp_frtoc, "framecpp.frtoc")
DECLARE_CHANNEL_LOGGER(framecpp_frvect, "framecpp.frvect")

// Usage
logger_log_debug(get_framecpp_frtoc_logger(), 5, "FrTOC processing ", data);
logger_log_warning(get_framecpp_frvect_logger(), "Vector operation failed");
```

### Group Configuration and Pattern Matching
```cpp
// Configure entire groups with patterns
auto& registry = LoggerRegistry::getInstance();

// Set debug level for all framecpp modules
registry.set_group_debug_level("framecpp.*", 8);

// Override for specific module  
registry.set_group_debug_level("framecpp.frtoc", 10);

// Disable specific groups
registry.disable_group("test.*");

// Pattern examples:
// "framecpp.*" matches "framecpp.frtoc", "framecpp.frvect", etc.
// "*.processor" matches any module ending in "processor"
// "framecpp.fr*" matches "framecpp.frtoc", "framecpp.frvect", etc.
```

### Debug Level Behavior (Intuitive)
```cpp
// Debug level N shows messages 1 through N
logger->set_debug_level(10);  // Shows debug levels 1-10
logger_log_debug(logger, 5, "This shows");    // 5 <= 10 ✓
logger_log_debug(logger, 15, "This filters"); // 15 > 10 ✗

logger->set_debug_level(3);   // Shows debug levels 1-3 only  
logger_log_debug(logger, 2, "This shows");    // 2 <= 3 ✓
logger_log_debug(logger, 5, "This filters");  // 5 > 3 ✗
```

### Lazy Evaluation and Performance
```cpp
// Early exits prevent unnecessary work
logger->set_debug_level(3);

auto expensive_operation = []() -> std::string {
    // This won't execute if message is filtered
    process_large_dataset();
    return "result"; 
};

// No performance cost - early exit before string construction
logger_log_debug(logger, 10, "Data: ", expensive_operation()); // Filtered
```

### Severity-Based Routing
```cpp
// Setup optimized routing
logger->setup_optimized_routing();
// - Debug messages → stderr (immediate flush)
// - Info/warnings → stdout (buffered) 
// - Errors → both stderr AND rotating log files

// Custom routing
auto cerr_sink = logger->create_cerr_sink();
auto cout_sink = logger->create_cout_sink();
auto file_sink = logger->create_rotating_file_sink("logs");

logger->add_filtered_sink(cerr_sink, debug_min, debug_max);
logger->add_filtered_sink(file_sink, error_min, error_max);
```

### Temporary Verbosity Control
```cpp
{
    // Temporarily increase verbosity for debugging
    ScopedChannelVerbosity verbose("framecpp.frtoc", 10);
    
    // All debug messages 1-10 show during this scope
    logger_log_debug(frtoc_logger, 8, "Verbose debugging");
    
    // Complex debugging operations
    debug_complex_operation();
    
} // Automatically restores previous debug level
```

### Modern Logging API (SimpleLogger)
```cpp
// Boost.Log-based system with multiple severity levels
enum severity_level {
    debug,           // Debug information (levels 1-N)
    ok,             // Success messages
    note,           // Informational notes
    warning,        // Warning conditions
    error_non_fatal, // Recoverable errors
    error,          // Fatal errors
    email,          // Email notifications
    phone           // Critical alerts
};

// Channel-aware logging with variadic templates
logger_log_debug(logger, 5, "Processing ", count, " items");
logger_log_warning(logger, "Disk space low: ", percentage, "%");
logger_log_error(logger, "Connection failed to ", hostname);
```

### Configuration Examples
```cpp
// Production configuration
registry.set_group_debug_level("*", 0);          // No debug by default
registry.set_group_debug_level("critical.*", 3); // Minimal debug for critical
registry.set_group_debug_level("network.*", 5);  // Network debugging
default_logger()->setup_optimized_routing();      // Route to appropriate sinks

// Development configuration  
registry.set_group_debug_level("*", 8);          // Verbose everywhere
registry.set_group_debug_level("performance.*", 10); // Max verbosity for perf
```

### Legacy Error Logging (Still Supported)
```cpp
// Traditional error reporting system
class ErrorLog {
public:
    enum State {
        ASSERT_FAILURE, FATAL, DEBUG, WARNING, INFO
    };
    
    static void StdErrLog(State state, const char* file, 
                         int line, const std::string& message);
};
```

## System Utilities

### Process Management
```cpp
// Process forking abstraction
class Fork {
public:
    Fork();
    
    bool IsParent() const;
    bool IsChild() const;
    pid_t GetChildPid() const;
    
    // Pipe-based communication
    void SetupPipes();
    void RedirectStdIO();
};
```

### Signal Handling
```cpp
// Centralized signal management
class SignalHandler {
public:
    enum Signal {
        ABORT, ALARM, HANGUP, TERMINATE, USER_1, USER_2
    };
    
    static void RegisterCallback(Signal sig, 
                               std::function<void()> callback);
    static void Block(Signal sig);
    static void Unblock(Signal sig);
};
```

### System Call Wrapper
```cpp
// Base class for OS operations
class SystemCall {
protected:
    int return_code;
    int errno_value;
    
public:
    bool Success() const;
    int GetReturnCode() const;
    int GetErrno() const;
    std::string GetErrorMessage() const;
};
```

## Memory Management

### Garbage Collection System
```cpp
// Memory cleanup registration
class MemChecker {
public:
    static void Append(std::function<void()> cleanup_func,
                      const std::string& description,
                      int priority_ring = 0);
    
    static void Trigger(bool final_cleanup = false);
    
    // RAII trigger for automatic cleanup
    class Trigger {
    public:
        Trigger(bool final = false);
        ~Trigger();
    };
};
```

### Performance Profiling
```cpp
// GPS time-based measurements
class Profile {
public:
    Profile(const std::string& name);
    ~Profile();  // Automatic timing calculation
    
    static void Report();  // Display timing statistics
    static void Reset();   // Clear accumulated data
};
```

## File System and I/O

### Enhanced File Streams
```cpp
// Memory-mapped I/O and extended buffering
class fstream : public std::fstream {
public:
    // Memory-mapped file access
    void* MapMemory(size_t length, off_t offset = 0);
    void UnmapMemory(void* addr, size_t length);
    
    // Extended buffering controls
    void SetBufferSize(size_t size);
    void FlushBuffers();
};
```

### Directory Operations
```cpp
// Cross-platform directory traversal
class Directory {
public:
    Directory(const std::string& path);
    
    // Blocking and non-blocking modes
    std::string Read();
    std::string Read(double timeout);  // Timeout-based
    
    bool EndOfDirectory() const;
    void Rewind();
};
```

### Directory Creation
```cpp
// Recursive directory creation
class MkDir {
public:
    static bool Create(const std::string& path, 
                      mode_t mode = 0755);
    static bool CreateRecursive(const std::string& path);
};
```

## GPS Time System

### Precise Time Representation
```cpp
// GPS time with nanosecond precision
class GPSTime {
public:
    GPSTime(int32_t seconds, int32_t nanoseconds = 0);
    
    // Time conversion
    double ToDouble() const;
    std::string ToString() const;
    
    // Leap second handling
    static bool IsLeapSecond(int32_t gps_seconds);
    static int32_t GPS2UTC(int32_t gps_seconds);
    static int32_t UTC2GPS(int32_t utc_seconds);
    
    // Arithmetic operations
    GPSTime operator+(const GPSTime& other) const;
    GPSTime operator-(const GPSTime& other) const;
    bool operator<(const GPSTime& other) const;
};
```

## Build System

### CMake Configuration
```cmake
# Modern CMake requirements
cmake_minimum_required(VERSION 3.12)
set(CMAKE_CXX_STANDARD 17)

# Key dependencies
find_package(Boost 1.67 REQUIRED COMPONENTS
    log thread system filesystem date_time program_options)
find_package(Threads REQUIRED)
```

### Sanitizer Support
- **ASAN**: Address Sanitizer for memory errors
- **LSAN**: Leak Sanitizer for memory leaks
- **MSAN**: Memory Sanitizer for uninitialized memory
- **TSAN**: Thread Sanitizer for race conditions
- **UBSAN**: Undefined Behavior Sanitizer

## Development Guidelines

### Code Formatting
All C/C++ source code must be formatted using clang-format. The configuration file (`.clang-format`) is located in the parent directory. Additionally, trailing whitespace must be removed from all files. Ensure all code changes are properly formatted before committing:

```bash
# Format a single file
clang-format -i src/MyFile.cc

# Format all C/C++ files recursively
find . -name "*.cc" -o -name "*.hh" | xargs clang-format -i

# Remove trailing whitespace from all files
find . -type f \( -name "*.cc" -o -name "*.hh" -o -name "*.cmake" -o -name "*.txt" \) -exec sed -i 's/[[:space:]]*$//' {} +
```

### Threading Best Practices
```cpp
// RAII locking pattern
{
    MutexLock lock;
    // Critical section automatically protected
    // Automatic unlock on scope exit
}

// Task-based concurrency
class MyWork : public Task {
    void operator()() override {
        // Thread-safe work implementation
    }
};
```

### Logging Best Practices
```cpp
// Use appropriate severity levels
logger_log_debug(logger, 3, "Detailed debug info");
logger_log_note(logger, "Normal operation");
logger_log_warning(logger, "Potential issue");
logger_log_error(logger, "Fatal error");

// Include context in messages
logger_log_warning(logger, "File operation failed: ", 
                  filename, " error: ", error_code);
```

### Memory Management
```cpp
// Register cleanup for resources
MemChecker::Append([](){ cleanup_resource(); }, 
                  "Resource cleanup", 
                  priority_ring);

// Use RAII triggers for automatic cleanup
{
    MemChecker::Trigger trigger(false);
    // Work with automatic cleanup on exit
}
```

## Integration Points

### LDAS Tools Dependencies
- **Base layer**: Used by all other LDAS Tools libraries
- **Thread safety**: Provides threading primitives for concurrent libraries
- **Logging**: Centralized logging for entire ecosystem
- **System abstraction**: Cross-platform compatibility layer

### External Dependencies
- **Boost** (>=1.67): Core functionality (log, thread, system, filesystem)
- **POSIX Threads**: Threading primitives
- **Standard Library**: C++17 features

## Debug Level Management System

### DebugLevelManager - Centralized Debug Control

The `DebugLevelManager` provides centralized debug level management with environment variable support, channel-specific configuration, and pattern matching for LDAS Tools applications.

```cpp
// Include the debug level manager
#include "ldastoolsal/DebugLevelManager.hh"

// Initialize in main() of any LDAS Tools utility
if (!LDASTools::AL::DebugLevelManager::initialize(argc, argv, "my_utility", "MYAPP_DEBUG")) {
    return 0; // Help was requested and shown
}

// Library code remains unchanged - works with existing logger infrastructure
logger_log_debug(logger(), 25, "Debug message");
```

#### Key Features
- **Environment Variable Support**: Configure debug levels via `{PREFIX}_LEVEL` and `{PREFIX}_CHANNELS`
- **Pattern Matching**: Use wildcards like `framecpp.frtoc.*` to configure entire module trees
- **Command-Line Integration**: Automatic boost::program_options integration with `--debug-level` and `--debug-channels`
- **Channel Hierarchy**: Support for dot-separated channel names with inheritance
- **Configuration Files**: Load debug configuration from files
- **Help Integration**: Built-in help text with example channel patterns

#### Configuration Methods

```cpp
// Set global debug level (affects all channels without specific configuration)
DebugLevelManager::set_global_level(10);

// Set specific channel debug levels
DebugLevelManager::set_channel_level("framecpp.frtoc", 25);
DebugLevelManager::set_channel_level("framecpp.*", 15);  // Pattern matching

// Parse channel specification strings
DebugLevelManager::parse_channel_spec("framecpp.frtoc:25,framecpp.*:15");

// Check if message should be logged
if (DebugLevelManager::should_log("framecpp.frtoc.data", 20)) {
    logger_log_debug(logger, 20, "Expensive debug operation");
}
```

#### Environment Variable Configuration

```bash
# Set global debug level
export FRAMECPP_DEBUG_LEVEL=15

# Configure specific channels
export FRAMECPP_DEBUG_CHANNELS="framecpp.frtoc.*:25,framecpp.frendoffile:30"

# Run application with debug output
./framecpp_dump_toc --debug-level=20 --debug-channels="framecpp.*:25" input.gwf
```

#### Application Integration Pattern

```cpp
// Application-specific wrapper (recommended pattern)
class MyAppDebugManager {
public:
    static bool initialize(int argc, char* argv[], 
                          const std::string& program_name = "myapp_utility") {
        // Configure app-specific settings
        DebugLevelManager::set_env_prefix("MYAPP_DEBUG");
        DebugLevelManager::set_example_channels({
            "myapp.processing.*",
            "myapp.io",
            "myapp.*"
        });
        
        // Initialize with app-specific environment prefix
        return DebugLevelManager::initialize(argc, argv, program_name, "MYAPP_DEBUG");
    }
};
```

#### Configuration File Format

```ini
# debug.conf - Debug configuration file
global_level = 10

[channels]
framecpp.frtoc.* = 25
framecpp.frendoffile = 30
network.* = 5
test.* = 0
```

```cpp
// Load configuration from file
DebugLevelManager::load_from_file("debug.conf");
```

## Common Usage Patterns

### Application Initialization with DebugLevelManager
```cpp
// Modern approach using DebugLevelManager
#include "ldastoolsal/DebugLevelManager.hh"

int main(int argc, char* argv[]) {
    // Initialize debug level manager early
    if (!LDASTools::AL::DebugLevelManager::initialize(argc, argv, "my_utility", "MYUTIL_DEBUG")) {
        return 0; // Help was requested
    }
    
    // Application startup logging
    auto* app_logger = get_channel_logger("app.startup");
    logger_log_note(app_logger, "Application starting with PID ", getpid());
    
    // Debug levels automatically configured from command line or environment
    logger_log_debug(get_channel_logger("app.processing"), 15, "Processing started");
    
    return 0;
}
```

### Legacy Application Initialization with Hierarchical Logging
```cpp
// Legacy approach using LoggerRegistry directly
auto& registry = LoggerRegistry::getInstance();

// Configure logging for different subsystems
registry.set_group_debug_level("network.*", 5);      // Network debugging
registry.set_group_debug_level("framecpp.*", 8);     // Frame processing verbose
registry.set_group_debug_level("framecpp.frtoc", 10);// Extra verbose for FrTOC
registry.set_group_debug_level("test.*", 0);         // Disable test logging

// Setup optimized routing
default_logger()->setup_optimized_routing();

// Application startup logging
auto* app_logger = get_channel_logger("app.startup");
logger_log_note(app_logger, "Application starting with PID ", getpid());

// Setup cleanup with logging
MemChecker::Append([]() { 
    auto* cleanup_logger = get_channel_logger("app.shutdown");
    logger_log_note(cleanup_logger, "Application cleanup completed");
}, "App cleanup");
```

### Module-Specific Logging
```cpp
// In framecpp module files
DECLARE_CHANNEL_LOGGER(framecpp_reader, "framecpp.reader")
DECLARE_CHANNEL_LOGGER(framecpp_writer, "framecpp.writer")

void read_frame_data() {
    auto* logger = get_framecpp_reader_logger();
    
    logger_log_debug(logger, 3, "Starting frame read operation");
    
    // Temporary high verbosity for complex operation
    {
        ScopedChannelVerbosity verbose("framecpp.reader", 10);
        logger_log_debug(logger, 8, "Detailed frame parsing...");
        // Complex parsing with verbose debug output
    }
    
    logger_log_note(logger, "Frame data read successfully");
}
```

### Concurrent Processing with Channel Logging
```cpp
// Thread pool usage with per-thread logging
auto* thread = ThreadPool::Acquire();

// Create channel logger for this processing task
auto task_logger = get_channel_logger("processing.task." + std::to_string(task_id));

MyTask task;
task.SetLogger(task_logger);  // Pass logger to task
thread->Execute(task);
ThreadPool::Relinquish(thread);
```

### GPS Time Operations with Logging
```cpp
// GPS time with integrated logging
auto* time_logger = get_channel_logger("gps.time");

GPSTime now = GPSTime::Now();
logger_log_debug(time_logger, 5, "Current GPS time: ", now.ToString());

// Time arithmetic with validation logging
GPSTime later = now + GPSTime(3600, 0);  // Add 1 hour
logger_log_debug(time_logger, 3, "Calculated time offset: ", later.ToString());

if (GPSTime::IsLeapSecond(now.GetSeconds())) {
    logger_log_warning(time_logger, "Leap second detected at ", now.ToString());
}
```

## Performance Benefits

### Lazy Evaluation Impact
- **Zero overhead** for filtered debug messages
- **No string construction** when messages won't be output  
- **Early exit optimization** prevents unnecessary work
- **Minimal CPU impact** for disabled log levels

### Memory Efficiency  
- **Static logger instances** - no repeated allocations
- **Efficient pattern matching** with compiled regex caching
- **RAII cleanup** ensures no memory leaks

### Scalability
- **Thread-safe operations** throughout
- **Lock-free early exits** for performance-critical paths
- **Bulk configuration updates** with single lock acquisition
- **Hierarchical inheritance** reduces configuration overhead

## Integration with LDAS Tools Ecosystem

The enhanced logging system integrates seamlessly with existing LDAS Tools:

- **frameCPP**: Use `framecpp.*` channels for frame processing modules
- **ldasgen**: Use `ldasgen.*` channels for general utilities  
- **diskcache**: Use `diskcache.*` channels for caching operations
- **filters**: Use `filters.*` channels for signal processing
- **frameutils**: Use `frameutils.*` channels for frame utilities

### Backward Compatibility
- **Existing code unchanged** - `default_logger()` still works
- **Legacy ErrorLog supported** - no breaking changes
- **Gradual migration** - can adopt hierarchical logging incrementally
- **Configuration coexistence** - old and new logging can be mixed

## Recent Enhancements (2025)

### DebugLevelManager Implementation
Added comprehensive debug level management system with the following capabilities:

- **Centralized Configuration**: Single point of control for all debug output across applications
- **Environment Variable Support**: Configure debug levels via `{PREFIX}_LEVEL` and `{PREFIX}_CHANNELS`
- **Pattern Matching**: Wildcard support for channel hierarchies (`framecpp.*`, `*.processor`)
- **Command-Line Integration**: Automatic boost::program_options integration
- **Application Wrappers**: Framework for app-specific debug managers (e.g., `FrameCPPDebugManager`)
- **Configuration Files**: Support for .conf file-based configuration
- **Help System**: Built-in help with example channel patterns

### Integration with LDAS Tools Projects
The DebugLevelManager is now used by:
- **frameCPP**: `FrameCPPDebugManager` with `FRAMECPP_DEBUG_*` environment variables
- **Other Projects**: Ready for integration with project-specific wrappers

### Performance Optimizations
- **Lazy Evaluation**: Debug messages only processed when channels are enabled
- **Pattern Caching**: Compiled regex patterns cached for efficient matching
- **Early Exit**: Zero overhead for disabled debug channels
- **Thread Safety**: All operations are thread-safe with minimal locking

The ldastoolsal library now provides enterprise-grade logging capabilities with centralized debug management alongside the essential foundation for robust, cross-platform scientific computing applications in the gravitational wave data analysis domain.