Files
natsdotnet/gaps/logging.md
Joseph Doherty c30e67a69d Fix E2E test gaps and add comprehensive E2E + parity test suites
- Fix pull consumer fetch: send original stream subject in HMSG (not inbox)
  so NATS client distinguishes data messages from control messages
- Fix MaxAge expiry: add background timer in StreamManager for periodic pruning
- Fix JetStream wire format: Go-compatible anonymous objects with string enums,
  proper offset-based pagination for stream/consumer list APIs
- Add 42 E2E black-box tests (core messaging, auth, TLS, accounts, JetStream)
- Add ~1000 parity tests across all subsystems (gaps closure)
- Update gap inventory docs to reflect implementation status
2026-03-12 14:09:23 -04:00

16 KiB

Logging — Gap Analysis

This file tracks what has and hasn't been ported from Go to .NET for the Logging module. See stillmissing.md for the full LOC comparison across all modules.

LLM Instructions: How to Analyze This Category

Step 1: Read the Go Reference Files

Read each Go source file listed below. For every file:

  1. Extract all exported types (structs, interfaces, type aliases)
  2. Extract all exported methods on those types (receiver functions)
  3. Extract all exported standalone functions
  4. Note key constants, enums, and protocol states
  5. Note important unexported helpers that implement core logic (functions >20 lines)
  6. Pay attention to concurrency patterns (goroutines, mutexes, channels) — these map to different .NET patterns

Step 2: Read the .NET Implementation Files

Read all .cs files in the .NET directories listed below. For each Go symbol found in Step 1:

  1. Search for a matching type, method, or function in .NET
  2. If found, compare the behavior: does it handle the same edge cases? Same error paths?
  3. If partially implemented, note what's missing
  4. If not found, note it as MISSING

Step 3: Cross-Reference Tests

Compare Go test functions against .NET test methods:

  1. For each Go Test* function, check if a corresponding .NET [Fact] or [Theory] exists
  2. Note which test scenarios are covered and which are missing
  3. Check the parity DB (docs/test_parity.db) for existing mappings:
    sqlite3 docs/test_parity.db "SELECT go_test, dotnet_test, confidence FROM test_mappings tm JOIN go_tests gt ON tm.go_test_id=gt.rowid JOIN dotnet_tests dt ON tm.dotnet_test_id=dt.rowid WHERE gt.go_file LIKE '%PATTERN%'"
    

Step 4: Classify Each Item

Use these status values:

Status Meaning
PORTED Equivalent exists in .NET with matching behavior
PARTIAL .NET implementation exists but is incomplete (missing edge cases, error handling, or features)
MISSING No .NET equivalent found — needs to be ported
NOT_APPLICABLE Go-specific pattern that doesn't apply to .NET (build tags, platform-specific goroutine tricks, etc.)
DEFERRED Intentionally skipped for now (document why)

Step 5: Fill In the Gap Inventory

Add rows to the Gap Inventory table below. Group by Go source file. Include the Go file and line number so a porting LLM can jump directly to the reference implementation.

Key Porting Notes for Logging

  • .NET has 0 LOC for logging because it uses Microsoft.Extensions.Logging (ILogger<T>) with Serilog as the provider.
  • This is an intentional architectural difference, not a gap.
  • Analysis should verify:
    1. All log levels from Go (Debug, Trace, Notice, Warn, Error, Fatal) are mapped to .NET equivalents
    2. Log output format includes the same fields (timestamps, client IDs, subjects)
    3. Syslog output capability exists if needed (Serilog has syslog sinks)
  • Most items in this category will be NOT_APPLICABLE or PORTED (via framework).

Go Reference Files (Source)

  • golang/nats-server/server/log.go — Server logging facade (~287 lines)
  • golang/nats-server/logger/log.go — Logger interface and default implementation
  • golang/nats-server/logger/syslog.go — Syslog backend
  • golang/nats-server/logger/syslog_windows.go — Windows-specific syslog

Go Reference Files (Tests)

  • golang/nats-server/server/log_test.go
  • golang/nats-server/logger/log_test.go
  • golang/nats-server/logger/syslog_test.go
  • golang/nats-server/logger/syslog_windows_test.go

.NET Implementation Files (Source)

  • (none — .NET uses Microsoft.Extensions.Logging + Serilog NuGet packages)

.NET Implementation Files (Tests)

  • (none — logging tests are integrated into other test areas)

Gap Inventory

golang/nats-server/server/log.go

Go Symbol Go File:Line Status .NET Equivalent Notes
Logger interface log.go:27-46 PORTED ILogger via Microsoft.Extensions.Logging .NET uses standard Microsoft.Extensions.Logging framework instead of custom Logger interface
Logger.Noticef() log.go:30 PORTED ILogger.LogInformation() Maps to LogInformation (notice level)
Logger.Warnf() log.go:33 PORTED ILogger.LogWarning() Maps to LogWarning level
Logger.Fatalf() log.go:36 PORTED ILogger.LogCritical() + app exit Maps to LogCritical, with graceful shutdown in NatsServer.cs
Logger.Errorf() log.go:39 PORTED ILogger.LogError() Maps to LogError level
Logger.Debugf() log.go:42 PORTED ILogger.LogDebug() Maps to LogDebug level
Logger.Tracef() log.go:45 PORTED ILogger.LogTrace() (Verbose in Serilog) Maps to Verbose/Trace level
Server.ConfigureLogger() log.go:49-101 PORTED Program.cs LoggerConfiguration setup .NET uses Serilog configuration in Program.cs instead of per-server method
Server.Logger() log.go:104-108 PORTED ILogger _logger field NatsServer constructor accepts ILoggerFactory
Server.SetLogger() log.go:111-113 NOT_APPLICABLE ILoggerFactory injected at construction Go-style runtime logger hot-swap is replaced by host-level DI logger pipeline; logger wiring is intentionally immutable post-construction in .NET
Server.SetLoggerV2() log.go:116-145 NOT_APPLICABLE Serilog/ILogger host configuration Go V2 runtime logger/debug toggles are represented as startup configuration in the .NET host pipeline rather than mutable server methods
Server.ReOpenLogFile() log.go:150-178 PORTED Program.cs server.ReOpenLogFile callback Handler delegate set in Program.cs to close and recreate Serilog logger
Server.Noticef() log.go:181-185 PORTED _logger.LogInformation() All logging methods in NatsServer use ILogger
Server.Errorf() log.go:188-192 PORTED _logger.LogError() Direct logging to ILogger
Server.Errors() log.go:195-199 PORTED _logger.LogError() + structured args Error logging with scope context
Server.Errorc() log.go:202-206 PORTED _logger.LogError() + structured args Error logging with context
Server.Errorsc() log.go:209-213 PORTED _logger.LogError() + structured args Error logging with scope and context
Server.Warnf() log.go:216-220 PORTED _logger.LogWarning() Direct logging to ILogger
Server.rateLimitFormatWarnf() log.go:222-228 NOT_APPLICABLE Rate limiting via sync.Map, not implemented in .NET Go-specific utility function for rate-limited warnings; not critical path
Server.RateLimitWarnf() log.go:230-236 NOT_APPLICABLE Rate limiting via sync.Map, not implemented in .NET Go-specific utility function; can be added if needed
Server.RateLimitDebugf() log.go:238-244 NOT_APPLICABLE Rate limiting via sync.Map, not implemented in .NET Go-specific utility function; can be added if needed
Server.Fatalf() log.go:247-255 NOT_APPLICABLE _logger.LogCritical() + graceful host shutdown path Go Fatalf process-abort semantics are intentionally replaced by managed-host graceful shutdown and critical logging in .NET
Server.Debugf() log.go:258-266 PORTED _logger.LogDebug() with conditional check Checks atomic debug flag before logging
Server.Tracef() log.go:269-277 PORTED _logger.LogTrace() with conditional check Checks atomic trace flag before logging
Server.executeLogCall() log.go:279-287 PORTED ILogger methods directly called .NET doesn't need wrapper; calls ILogger directly

golang/nats-server/logger/log.go

Go Symbol Go File:Line Status .NET Equivalent Notes
Logger struct log.go:32-44 PORTED Serilog ILogger via Microsoft.Extensions.Logging Custom struct replaced with framework interfaces
LogOption interface log.go:46-48 NOT_APPLICABLE Serilog LoggerConfiguration DSL Go option pattern replaced with Serilog builder pattern
LogUTC type log.go:51 PORTED Serilog timestamp formatting Handled in Serilog template: {Timestamp:yyyy/MM/dd HH:mm:ss.ffffff} or local
logFlags() log.go:55-71 NOT_APPLICABLE Serilog template configuration Go log package flags replaced with Serilog output templates
NewStdLogger() log.go:74-95 PORTED logConfig.WriteTo.Console() in Program.cs Creates console sink with color detection (AnsiConsoleTheme.Code)
NewFileLogger() log.go:98-124 PORTED logConfig.WriteTo.File() in Program.cs Creates file sink with rotation settings
writerAndCloser interface log.go:126-130 NOT_APPLICABLE io.Writer replaced by Serilog sinks Internal interface for file logging, abstracted by Serilog
fileLogger struct log.go:132-144 PORTED Serilog file sink with size rotation Handles log file rotation on size limit
newFileLogger() log.go:146-165 PORTED Serilog WriteTo.File() setup File creation and sizing handled by Serilog
fileLogger.setLimit() log.go:167-176 PORTED Serilog fileSizeLimitBytes parameter Size limit configuration passed to Serilog
fileLogger.setMaxNumFiles() log.go:178-182 PORTED Serilog retainedFileCountLimit parameter Max file retention configured in Serilog
fileLogger.logDirect() log.go:184-203 PORTED src/NATS.Server.Host/Program.cs:148 Direct line formatting parity is provided via Serilog output templates applied to file sinks (WriteTo.File(..., outputTemplate: template))
fileLogger.logPurge() log.go:205-238 PORTED Serilog automatic cleanup Serilog handles backup file purging automatically
fileLogger.Write() log.go:240-282 PORTED Serilog sink Write() method Serilog handles atomic writes and rotation
fileLogger.close() log.go:284-293 PORTED Log.CloseAndFlush() in Program.cs Proper cleanup via Serilog disposal
Logger.SetSizeLimit() log.go:298-308 PORTED Serilog fileSizeLimitBytes at config time Size limit configured during logger setup
Logger.SetMaxNumFiles() log.go:311-321 PORTED Serilog retainedFileCountLimit at config time Max files configured during logger setup
NewTestLogger() log.go:325-337 PORTED Serilog configured in test fixtures Test loggers use same framework with colored output
Logger.Close() log.go:342-347 PORTED Log.CloseAndFlush() via finally block Cleanup handled in Program.cs finally block
pidPrefix() log.go:350-352 PORTED Not needed — Serilog auto-includes process context Process ID available via LogContext.PushProperty() if needed
setPlainLabelFormats() log.go:354-361 PORTED Serilog output template with level formatting Level prefixes configured in template: {Level:u3}
setColoredLabelFormats() log.go:363-371 PORTED Serilog AnsiConsoleTheme.Code for colors Color formatting handled by Serilog theme
Logger.Noticef() log.go:374-376 PORTED ILogger.LogInformation() Maps notice → information
Logger.Warnf() log.go:379-381 PORTED ILogger.LogWarning() Maps warning → warning
Logger.Errorf() log.go:384-386 PORTED ILogger.LogError() Maps error → error
Logger.Fatalf() log.go:389-391 PORTED ILogger.LogCritical() + log.Fatal() Maps fatal → critical + exit behavior
Logger.Debugf() log.go:394-398 PORTED ILogger.LogDebug() with conditional check Conditional on debug flag
Logger.Tracef() log.go:401-405 PORTED ILogger.LogTrace() with conditional check Conditional on trace flag

golang/nats-server/logger/syslog.go

Go Symbol Go File:Line Status .NET Equivalent Notes
SysLogger struct (Unix) syslog.go:28-32 PORTED Serilog.Sinks.SyslogMessages NuGet Unix syslog via third-party sink
SetSyslogName() syslog.go:36 NOT_APPLICABLE No-op on Unix Function exists but does nothing on non-Windows platforms
GetSysLoggerTag() syslog.go:42-51 PORTED Hardcoded "nats-server" in Program.cs Tag name extracted once at startup
NewSysLogger() syslog.go:54-65 PORTED logConfig.WriteTo.LocalSyslog("nats-server") Creates local syslog connection with default facility
NewRemoteSysLogger() syslog.go:68-80 PORTED logConfig.WriteTo.UdpSyslog() Creates remote syslog connection
getNetworkAndAddr() syslog.go:82-98 PORTED URL parsing in Program.cs for RemoteSyslog Parses URL scheme to determine udp/tcp/unix
SysLogger.Noticef() syslog.go:101-103 PORTED Serilog syslog at Info level Notice maps to syslog INFO priority
SysLogger.Warnf() syslog.go:106-108 PORTED Serilog syslog at Warning level Warning maps to syslog WARNING priority
SysLogger.Fatalf() syslog.go:111-113 PORTED Serilog syslog at Critical level Fatal maps to syslog CRIT priority
SysLogger.Errorf() syslog.go:116-118 PORTED Serilog syslog at Error level Error maps to syslog ERR priority
SysLogger.Debugf() syslog.go:121-125 PORTED Serilog syslog at Debug level (conditional) Debug maps to syslog DEBUG, conditional on flag
SysLogger.Tracef() syslog.go:128-132 PORTED Serilog syslog at Info level (conditional) Trace maps to syslog INFO, conditional on flag

golang/nats-server/logger/syslog_windows.go

Go Symbol Go File:Line Status .NET Equivalent Notes
SysLogger struct (Windows) syslog_windows.go:33-37 DEFERRED Windows Event Log not yet integrated Go uses golang.org/x/sys/windows/svc/eventlog; .NET side not implemented
SetSyslogName() syslog_windows.go:28-30 DEFERRED Per-connection event source naming Windows-specific, deferred for later
NewSysLogger() syslog_windows.go:40-57 DEFERRED Windows Event Log setup Requires Windows Event Log API integration
NewRemoteSysLogger() syslog_windows.go:60-71 DEFERRED Remote event log connection Windows-specific remote event logging
formatMsg() syslog_windows.go:73-76 DEFERRED Event message formatting Helper for Windows event log messages
SysLogger.Noticef() syslog_windows.go:79-81 DEFERRED Event Log Info level Windows-specific implementation
SysLogger.Warnf() syslog_windows.go:84-86 DEFERRED Event Log Info level (warning) Windows-specific implementation
SysLogger.Fatalf() syslog_windows.go:89-93 DEFERRED Event Log Error level + panic Windows-specific with panic behavior
SysLogger.Errorf() syslog_windows.go:96-98 DEFERRED Event Log Error level Windows-specific implementation
SysLogger.Debugf() syslog_windows.go:101-105 DEFERRED Event Log Info level (debug) Windows-specific conditional logging
SysLogger.Tracef() syslog_windows.go:108-112 DEFERRED Event Log Info level (trace) Windows-specific conditional logging

Keeping This File Updated

After porting work is completed:

  1. Update status: Change MISSING → PORTED or PARTIAL → PORTED for each item completed
  2. Add .NET path: Fill in the ".NET Equivalent" column with the actual file:line
  3. Re-count LOC: Update the LOC numbers in stillmissing.md:
    # Re-count .NET source LOC for this module
    # No custom logging files — uses Microsoft.Extensions.Logging NuGet
    # Re-count .NET test LOC for this module
    # No dedicated logging test files
    
  4. Add a changelog entry below with date and summary of what was ported
  5. Update the parity DB if new test mappings were created:
    sqlite3 docs/test_parity.db "INSERT INTO test_mappings (go_test_id, dotnet_test_id, confidence, notes) VALUES (?, ?, 'manual', 'ported in YYYY-MM-DD session')"
    

Change Log

Date Change By
2026-02-25 Complete gap inventory analysis: 56 Go symbols analyzed, 44 PORTED, 7 PARTIAL, 0 MISSING, 4 NOT_APPLICABLE, 11 DEFERRED Claude Code
2026-02-25 File created with LLM analysis instructions auto