Release notes
3.4.0
- Release date
-
2026-08-21
Added
-
Add a MailKit based
SmtpAppenderin the newlog4net.Ext.Mailassembly and marklog4net.Appender.SmtpAppenderas obsolete, because Microsoft no longer recommendsSystem.Net.Mail.SmtpClientfor new development (requested by @DietzeC, implemented by @FreeAndNil in #302) (300, 302) -
pin the Maven wrapper and the Maven distribution it downloads with
wrapperSha256SumanddistributionSha256Sum.mvnwandMavenWrapperDownloaderalready refuse to run when a download does not match, but neither property was set, so whatever the URLs returned was executed (CWE-494). Both values were taken from artifacts whose PGP signature verifies against the Apache Maven KEYS (audit 1231d72-f023) (310) -
add a
TransportSecurityoption to thelog4net.Ext.MailSmtpAppenderand makeEnableSsla shorthand for it.EnableSslrequires transport security, selecting implicit TLS on port 465 and mandatorySTARTTLSelsewhere, so connecting fails when the server offers no TLS instead of silently continuing in plaintext, asSystem.Net.Mail.SmtpClient.EnableSsldoes. OpportunisticSTARTTLSremains available, but only by asking for it withTransportSecurity=StartTlsWhenAvailable(audit 1231d72-f007) (310) -
add
ListenAddresstoTelnetAppender. The listening socket was bound toIPAddress.Anywith no way to scope it, so an operator who only wanted to watch the log from the machine itself still got a listener on every interface. The default is unchanged, and the listening socket now follows the address family, so an IPv6 address works too (audit 1231d72-f002) (310) -
log an error when
AdoNetAppenderis activated withoutCommandText. In that legacy mode the renderedLayoutoutput is executed as the SQL statement, and because layouts perform no SQL quoting, logged content becomes part of the statement (CWE-89). ConfigureCommandTextwithAdoNetAppenderParameterbindings instead (audit 1231d72-f003) (310)
Changed
-
Mono is no longer required to build the
net462andnet472targets on Linux and macOS.MonoForFramework.targetsand itsFrameworkPathOverridehandling were removed in favour of theMicrosoft.NETFramework.ReferenceAssembliespackages that the .NET SDK already references implicitly. Mono is still needed to run .NET Framework assemblies: CI moved toubuntu-latest(Ubuntu 24.04) andmacos-latest(macOS 26), which no longer ship Mono, so thenet462tests now run only on the Windows job and the Mono guards in the test suite were dropped. Support for running log4net under Mono is unaffected - the runtime check inlog4net.Util.SystemInfois unchanged (305) -
build the container image from
mcr.microsoft.com/dotnet/sdk:10.0-nobleinstead of installing a SDK intoubuntu:20.04withdotnet-install.sh. This moves off an Ubuntu release that left standard support in April 2025 and drops the download step, the Mono packages and theDOTNET_ROOTandPATHhandling (305) -
build and test with .NET 10: the test and integration-test projects now target
net10.0instead ofnet8.0, and a .NET 10 SDK is required because the sources use C# 14 language features. The publishedlog4netassembly still targetsnet462andnetstandard2.0, so nothing changes for consumers (305) -
bound the waits for the named mutexes used by
FileAppender.InterProcessLockand byRollingFileAppenderwhen it decides whether to roll. Both waited without a timeout while the appender lock was held, so a mutex nobody released suspended every thread logging through the appender. The wait now stops afterLockTimeoutMillis, 10000 by default, reporting through the error handler and dropping the event or skipping the roll check;Timeout.Infiniterestores the previous behaviour.AbandonedMutexExceptionis handled as the successful acquisition it is, rather than leaving the mutex held, and the rolling lock is no longer released when it was never taken (audit 1231d72-f015) (310) -
give
RegexToMatchmatching a deadline inStringMatchFilterand the filters deriving from it,PropertyFilter,MdcFilterandNdcFilter. The pattern was matched withRegex.InfiniteMatchTimeoutwhile the appender lock was held, so a pattern that backtracks could stall everything logging through the appender on some inputs. Matching now stops afterMatchTimeoutMillis, 1000 by default, and an abandoned match is reported once and leaves the event to the rest of the filter chain; 0 restores unbounded matching. The pattern comes from configuration and is trusted, so this is hardening rather than a vulnerability fix (audit 1231d72-f013) (310) -
report the first error of an appender even when
log4net.Internal.Debugis off, which is the default.OnlyOnceErrorHandleris the default error handler of every appender, so an appender that stopped delivering events previously did so without leaving any trace (CWE-778).log4net.Internal.QuietandLogLog.EmitInternalMessagesremain the ways to silence internal messages (audit 1231d72-f019) (310)
Fixed
-
fix
LoggingEvent.UserNameresolving the Windows identity for every event, because the cache added in 2.0.15 was held in an instance field and so never applied. The process identity is now resolved once, and impersonated identities once per user, cutting a bufferedFixFlags.Allevent from about 193 us to 17.5 us on the machine measured (304) -
fix the
log4net.Ext.Mailpackage failing to pack withNU5039(The readme file 'README.md' does not exist in the package), because theREADME.mditem was packed without aPackagePath(305) -
fix the release scripts continuing after a failed step:
$ErrorActionPreferencedoes not apply to native commands, so a failingdotnet,git,zip,gpgormvnwwent unnoticed and the artifacts were packaged, signed and tagged anyway. Bothscripts/build-preview.ps1andscripts/build-release.ps1now set$PSNativeCommandUseErrorActionPreference. Also fixscripts/build-preview.ps1outside Windows, where the artifact paths handed togpgwere built with backslashes, which are not path separators on Linux or macOS (305) -
Make log4net usable from a
PublishAotbuild, whereLogManager.GetLogger()used to throwPlatformNotSupportedExceptionfromAssembly.GetCallingAssembly(), and where repositories and pattern converters were left without a constructor by the trimmer. Configuration has to be done in code - see the new Native AOT and trimming page (reported by @vpenades, implemented by @FreeAndNil in #306) (233, 306) -
stop a single logging event that the database rejects from discarding the whole buffer in
AdoNetAppender. The events have already been removed from the buffer when they are sent, so a rolled back transaction lost up toBufferSizeunrelated events, which an attacker could trigger repeatedly with content the provider refuses, such asU+0000on npgsql (CWE-778). Delivery becomes at-least-once: events already applied by a batch that then failed may be written again (audit 1231d72-f004) (310) -
stop a NUL character in logged content from truncating
LocalSyslogAppenderrecords. The message is marshaled to libc as a null-terminated string, so everything the layout rendered after the NUL was silently dropped, including trailing fields and exception text (CWE-158). NUL is now escaped as\0; other control characters are still passed through, becausesyslog(3)encodes them and newlines are needed for multi-line exception output (audit 1231d72-f008) (310) -
make
TextWriterAppenderand the appenders deriving from it, includingFileAppenderandRollingFileAppender, flush under the appender lock.Flushsynchronized on a private object whileAppendruns under the lock taken byDoAppend, so a flush could run concurrently with a write to the sameQuietTextWriter, which is not thread safe, and interleave or lose output.Flushalso returnedtruewhatever happened and let a failure from the underlying writer escape to its caller; it now reports through theErrorHandlerand returnsfalse(audit 1231d72-f020) (310) -
stop
AdoNetAppenderfrom repeating the password when it reports a connection it could not open. The message named the resolved connection string in full, and the documented examples embedPassword=…(CWE-532). Password-bearing keywords are now replaced with*, while the rest of the connection string is kept so the message stays useful (audit 1231d72-f018) (310) -
report a
RemoteSyslogAppenderIdentitythat renders control characters, and remove them, so that it cannot split the record. The identity becomes the TAG of the syslog record and was appended verbatim, while the message part is filtered, so a line feed in it let the text that followed be read as a record of its own with an attacker chosen facility and severity. The TAG is a structural identifier and expected to be a constant, so this is reported as the configuration error it is rather than being repaired quietly (audit 1231d72-f016) (310) -
fix the lifetime of the
LocalSyslogAppenderidentity.openlogkeeps the pointer it is given rather than a copy of the string, and registers it for the process rather than for an appender. EachActivateOptionsallocated a new buffer and forgot the previous one, leaking it (CWE-401), whileOnClosefreed a buffer that another instance may still have been logging through. The handle is now shared, replaced under a lock onceopenlogpoints at the new string, and left allocated when an appender closes (audit 1231d72-f017) (310) -
stop a Telnet client that connects and then stops reading from suspending all logging.
TelnetAppenderwrites to its clients while the appender lock is held and set noSocket.SendTimeout, so once TCP flow control filled the client’s receive window the next write blocked forever and every thread logging through the appender queued behind it (CWE-833). Writes now time out afterSendTimeoutMillis(5000 by default) and the client is disconnected; 0 restores the previous unbounded behavior (audit 1231d72-f001) (310) -
stop
LoggingEvent.UserNamereporting the wrong user for an event logged while impersonating. The property resolved the identity of whichever thread read it, so with a buffering appender the buffered events were attributed to the thread flushing the buffer rather than the one that logged them (CWE-282). An event logged while impersonating now takes its user name with it when it is fixed, and an event read on an impersonating thread reports the not available text instead of that thread’s user. Without impersonation the name is the process identity, which is the same on every thread, so it is still resolved lazily and nothing changes (audit 1231d72-f014) (310) -
make the release verification scripts fail closed.
verify-release.ps1reported a SHA-512 mismatch with-ErrorAction Continueand never checked the exit code ofgpg, so it extracted the archive and exited 0 for a tampered artifact or a broken signature. Both scripts looped over whichever.ascfiles were present, so deleting them left nothing to verify and the scripts succeeded. The checks are now driven from the artifacts, each of which must have a.sha512and a.asc, and the keys are imported into a key ring of their own so that a signature from any other key this machine trusts is no longer accepted (audit 1231d72-f009, 1231d72-f010) (310)
Removed
-
remove the
git-broadcastworkflow. Its push and pull request triggers had been commented out, leaving it dispatched by hand only, while it still rannpx git-broadcast@beta, a dist-tag that can be repointed at any published version, in a job that checks out with a token able to push to this repository, using mutable action tags and nopermissionsblock (CWE-1357) (audit 1231d72-f011) (310)
3.3.2
- Release date
-
2026-06-25
Fixed
-
fix dropped log messages during concurrent
GetLoggercalls (reported by @omtslug, fixed by @gdziadkiewicz in #294) (292, 294) -
fix race condition in
AppenderSkeleton.AddFilterandClearFiltersunder concurrent logging (CWE-362) (f57d7b3-001, 298) -
fix unhandled exception in
AppenderSkeletonfinalizer that could terminate the process whenOnClose()throws (CWE-755) (f57d7b3-003, 298) -
fix mutex leak in
InterProcessLock.AcquireLockwhen the underlying file stream is null (CWE-772) (f57d7b3-002, 298)
3.3.1
- Release date
-
2026-04-20
Fixed
-
reduce silent log event loss during XmlConfigurator reconfiguration (by @N0TRE3L in #287) (287)
-
fix silent corruption of supplementary Unicode characters (U+10000–U+10FFFF) in
MaskXmlInvalidCharacters: valid UTF-16 surrogate pairs are now preserved instead of being replaced with the mask string (reported by @N0tre3l, fixed by @freeandnil in #291) (290, 291)
3.2.0
- Release date
-
2025-08-22
Added
-
Asynchronous Sending for RemoteSyslogAppender
-
requested by @yogitasingh001 #255
-
implemented by @yogitasingh001 (in #253) and @FreeAndNil (in #258)
-
Refactored the RemoteSyslogAppender to use an asynchronous, non-blocking logging model. Introduced a background worker pattern using
BlockingCollection<byte[]>to decouple UDP log transmission from the calling thread. This eliminates thread blocking caused by.Wait()onSendAsync()and significantly improves performance under high-load conditions. A graceful shutdown ensures any buffered logs are flushed on appender closure. No changes to external behavior - maintains backward compatibility.
-
Fixed
-
Fix InvalidCastException in NDC.Inherit(System.Collections.Stack) (reported by @jberg7, fixed by @FreeAndNil in #246) (245, 246)
-
Fix caching of time strings in AbsoluteTimeDateFormatter (reported by @LeadAssimilator, fixed by @FreeAndNil in #248) (247, 248)
-
The rolling of logfiles was fixed (reported by @maedula and @mordio, fixed by @gdziadkiewicz) (250, 260, 257, 262)
-
Shutdown: Unsubscribe from AppDomain event handlers (by @Flohack74) (256)
-
change dockerfile from mono:latest to ubuntu:20.04 and install mono manually (by @FreeAndNil) (c3f92ba)
3.0.4
- Release date
-
2025-02-21
Fixed
-
Keep old, working ubuntu image version (by @gdziadkiewicz) (215)
-
fixed SetQWForFiles method name in FileAppender from #196 by @sketchturner in #217 (fixes #216 reported by @sketchturner) (216, 217, 196)
-
XmlLayoutSchemaLog4J: Changed XML start element for exceptions since v3.0.0 (reported by @sita-martin, fixed in #226 by @FreeAndNil) (225, 226)
3.0.3
- Release date
-
2024-11-07
Added
-
Enable Microsoft.CodeAnalysis.NetAnalyzers (by @FreeAndNil) (201)
3.0.2
- Release date
-
2024-10-21
Known issues
-
MDC was accidentally renamed into Mdc - this will be reverted in 3.0.3
-
NDC was accidentally renamed into Ndc - this will be reverted in 3.0.3
Added
-
separate review instructions for log4net (by @FreeAndNil) (189)
Changed
-
more modern coding style (by @FreeAndNil) (196)
3.0.0
- Release date
-
2024-09-15
Breaking changes
|
Starting with 3.0.0 we only support the following target frameworks
The reasoning for this change can be found in #111 - Dropping support for older runtimes |
Removed obsolete classes and members
since 1.2.14 (2015)
-
log4net.Appender.BufferingAppenderSkeleton.OnlyFixPartialEventData
-
log4net.Appender.ColoredConsoleAppender.ctor(ILayout)
-
log4net.Appender.ColoredConsoleAppender.ctor(ILayout, bool)
-
log4net.Appender.ConsoleAppender.ctor(ILayout)
-
log4net.Appender.ConsoleAppender.ctor(ILayout, bool)
-
log4net.Appender.DebugAppender.ctor(ILayout)
-
log4net.Appender.EventLogAppender.ctor(ILayout)
-
log4net.Appender.FileAppender.ctor(ILayout, string)
-
log4net.Appender.FileAppender.ctor(ILayout, string, bool)
-
log4net.Appender.MemoryAppender.OnlyFixPartialEventData
-
log4net.Appender.SmtpAppender.LocationInfo
-
log4net.Appender.TextWriterAppender.ctor(ILayout, Stream)
-
log4net.Appender.TextWriterAppender.ctor(ILayout, TextWriter)
-
log4net.Appender.TraceAppender.ctor(ILayout)
-
log4net.Config.DOMConfigurator
-
log4net.Config.AliasDomainAttribute
-
log4net.Config.DomainAttribute
-
log4net.Config.DOMConfiguratorAttribute
-
log4net.Core.LoggerManager.GetLoggerRepository
-
log4net.Core.LoggerManager.CreateDomain
-
log4net.Core.LoggingEventData.TimeStamp
-
log4net.Core.LoggingEvent.GetExceptionStrRep
-
log4net.Core.LoggingEvent.FixVolatileData
-
log4net.LogManager.GetLoggerRepository
-
log4net.LogManager.CreateDomain
Changed
-
log4net.Appender.MemoryAppender.m_eventsList (protected field) is now List<LoggingEvent> (instead of System.Collections.ArrayList) (124)
-
log4net.Util.ReadOnlyPropertiesDictionary.InnerHashtable is now Dictionary<string, object?> (instead of System.Collections.Hashtable) (124)
-
log4net.Repository.Hierarchy.Hierarchy.EmittedNoAppenderWarning is now internal (157)
Fixed
-
Fix dotnet (ie not netfx) test run (by @mobilebilly) (109)
-
Regression: Creating nested loggers in reverse order fails in 3.0.0-preview.1 (by @FreeAndNil) (156)
-
ColoredConsoleAppender writes UTF-8 preamble to the console on initialization (reported by @RoboBurned, fixed by @FreeAndNil) (168)
-
System.NullReferenceException when comparing with a null Level (by @FreeAndNil) (169)
-
Culture-Specific String Comparisons Cause RollingFileAppender Failure in log4net on NET 5+ (reported by @stianeklund) (179)
2.x
Changed
-
release notes for older releases can be found here (2.x-and-older)