Skip to content

Add LogManager shutdown, sink ownership, and drain timeout#12

Merged
DJGosnell merged 1 commit intomasterfrom
issue-8/logmanager-shutdown-sink-ownership
Mar 3, 2026
Merged

Add LogManager shutdown, sink ownership, and drain timeout#12
DJGosnell merged 1 commit intomasterfrom
issue-8/logmanager-shutdown-sink-ownership

Conversation

@DJGosnell
Copy link
Member

Summary

  • Closes LogManager shutdown, sink ownership, and drain timeout #8
  • Adds ShutdownAsync()/Shutdown() for coordinated sink disposal with optional timeout
  • Adds ReconfigureAsync() that awaits old sink disposal; sync Reconfigure() fires-and-forgets
  • Adds configurable drain timeout to BufferedLogSink (default 30s) to prevent indefinite hangs
  • Auto-registers ProcessExit hook on Initialize() as a safety net (5s timeout)
  • SinkSet now tracks all sinks for disposal; LogConfig.DisposeAllAsync() disposes monitors + sinks
  • Reset() (test helper) now fully disposes sinks, not just monitors

Reason for Change

LogManager had no public shutdown path. Buffered sinks (FileSink, StreamSink) silently lost queued entries on process exit. Reconfigure() disposed monitors but leaked old sinks (file handles, drain tasks). BufferedLogSink.DisposeAsync() awaited the drain task with no timeout, risking indefinite hangs on stuck network streams.

Impact

  • All existing Initialize() calls now auto-register a ProcessExit safety-net hook
  • Reconfigure() now disposes old sinks (previously leaked) via fire-and-forget
  • BufferedLogSink now defaults to 30s drain timeout (previously infinite)

Migration Steps

  • No breaking API changes — all new parameters have defaults matching safe behavior
  • Callers should add await LogManager.ShutdownAsync() (or LogManager.Shutdown()) at app exit for explicit control
  • Custom BufferedLogSink subclasses gain a drainTimeout constructor parameter (optional, defaults to 30s)

Performance Considerations

  • No hot-path changes — Dispatch() is untouched
  • ProcessExit hook is a one-time static event registration
  • Drain timeout uses Task.WaitAsync + CancellationTokenSource only during disposal

Security Considerations

None.

Breaking Changes

Consumer-facing

  • None — all new APIs are additive, all existing signatures preserved with default parameters

Internal

  • SinkSet constructor now requires an allSinks array parameter
  • LogConfig.Reset() now disposes sinks (previously only disposed monitors)
  • BufferedLogSink default drain behavior changed from infinite wait to 30s timeout

- Add ShutdownAsync/Shutdown with optional timeout for coordinated sink disposal
- Auto-register ProcessExit hook on Initialize for safety-net flush (5s timeout)
- Add ReconfigureAsync that awaits old sink disposal; sync Reconfigure fires-and-forgets
- Add drain timeout to BufferedLogSink (default 30s) to prevent hang on stuck writes
- Surface drainTimeout parameter on FileSink, StreamSink, and LogConfigBuilder
- Track all sinks in SinkSet for disposal; add DisposeSinksAsync and DisposeAllAsync
- Update Reset() to fully dispose sinks (not just monitors)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@DJGosnell DJGosnell merged commit cae9116 into master Mar 3, 2026
1 check passed
@DJGosnell DJGosnell deleted the issue-8/logmanager-shutdown-sink-ownership branch March 3, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LogManager shutdown, sink ownership, and drain timeout

1 participant