Commit Graph

7 Commits

Author SHA1 Message Date
3178c50936 Remove autoconfigured (didn't work as implemented). 2025-07-11 17:38:04 -05:00
49755fa2af Add more unit tests. 2025-07-07 17:02:45 -05:00
c22e7edd5d Move autoconfiguration implementation into the main module.
Autoconfiguration implementation really needs access to internal fields
and data structures to work properly.

Additionally introduces the concept of GlobalLogService takeover
internally, which allows existing LogService instances to become aware
of a new GlobalLogService. This is needed for
`useForAutoconfiguredLogging` to work as one would naturally expect,
where Loggers that may have already been created (explicitly or
implicitly) by library or third-party code are kept up to date when the
application explicitly configures logging.
2025-07-07 16:29:58 -05:00
269cc81c82 Rewrite the log procs for better performance.
Previously, log message parsing and construction were performed before
we checked if we were actually going to log anything (based on our
thresholds). This change moves the logic for both the LogMessage
construction, as well as any logic in the calling context (string
concatenation etc.) after the threshold check.

This is to enable use-cases like this:

    logger.debug("Something interesting happened\p    context: " &
        expensiveCallToConstructFullContext())

and not have to pay the performance penalty of the string concatenation
in production settings when debug logging is turned off.
2025-07-07 16:21:59 -05:00
f80e5807db refactor: Complete rewrite of logging system with thread-safe architecture
This commit represents a complete architectural overhaul of the namespaced
logging library, transitioning from a shared-memory approach to a robust
thread-safe design with proper synchronization primitives.

- **NEW**: internal `GlobalLogService` with atomic configuration versioning
- **NEW**: Thread-local configuration caching with freshness checking
- **NEW**: Separate `LogService` (copyable) and `ThreadLocalLogService` (ref)
- **REMOVED**: Manual thread state reloading in favor of automatic freshness

- All shared state protected by locks and atomics
- Configuration changes use atomic version numbers for efficient sync
- Proper cleanup with `=destroy` implementing graceful shutdown
- Thread-safe appender cloning via `clone()` method pattern

- **NEW**: Dedicated writer threads for console and file output
- **NEW**: Channel-based message passing to writer threads
- **NEW**: Batched file I/O with optimized write patterns
- **NEW**: Graceful thread shutdown on service destruction

- **NEW**: Configurable error handling with `ErrorHandlerFunc`
- **NEW**: `defaultErrorHandlerFunc` with stderr fallback
- **NEW**: Thread-safe error reporting with separate lock
- **NEW**: Robust error recovery in all I/O operations

- **NEW**: `autoconfigured` module for zero-config usage
- **NEW**: `formatSimpleTextLog` as default formatter
- **NEW**: Optional logger support for ergonomic usage
- **NEW**: Generic `CustomLogAppender[T]` with state parameter
- **NEW**: `FileLogAppender` with proper multithreaded file I/O
- **BREAKING**: Logger `name` field renamed to `scope`
- **BREAKING**: Configuration methods renamed (e.g., `setRootLevel` → `setRootThreshold`)

- **NEW**: Comprehensive test suite with 20+ test cases
- **NEW**: `testutil` module with thread-safe test infrastructure
- **NEW**: Cross-thread synchronization testing
- **NEW**: File I/O testing with temporary files
- **REMOVED**: Old test suite replaced with more comprehensive version

- Atomic version checking prevents unnecessary config copies
- Writer threads use efficient polling with 100ms idle sleep
- File writer batches messages and optimizes file operations
- Thread-local caching reduces lock contention

1. **API Changes**:
   - `LogService` returned by `iniLogService` is fundamentally different
   - `threadLocalRef()` required for thread-local operations
   - `reloadThreadState()` removed (automatic freshness)
   - Logger field `name` → `scope`

2. **Configuration**:
   - `setRootLevel()` → `setRootThreshold()`
   - `setThreshold()` API simplified
   - `clearAppenders()` removed

3. **Appenders**:
   - `initThreadCopy()` → `clone()`
   - `appendLogMessage()` signature changed
   - Custom appenders now generic with state parameter

```nim
let ls = initLogService()
ls.addAppender(initConsoleLogAppender())
reloadThreadState(ls)
let logger = ls.getLogger("app")
logger.info("Hello world")
```

```nim
let ls = initLogService()
let tlls = threadLocalRef(ls)
tlls.addAppender(initConsoleLogAppender())
let logger = tlls.getLogger("app")
logger.info("Hello world")
```
```nim
import namespaced_logging/autoconfigured
addLogAppender(initConsoleLogAppender())
info("Hello world")
```
2025-07-06 01:03:35 -05:00
5f21b2f263 Initial implementation. 2022-01-13 14:12:10 -06:00
3222260baa Initial commit following nimble init. 2022-01-13 13:22:13 -06:00