diff --git a/src/NLog/Targets/FileTarget.cs b/src/NLog/Targets/FileTarget.cs index db46c5d440..bffef3a1c7 100644 --- a/src/NLog/Targets/FileTarget.cs +++ b/src/NLog/Targets/FileTarget.cs @@ -486,6 +486,13 @@ public bool ArchiveOldFileOnStartup set => _archiveOldFileOnStartup = value; } private bool? _archiveOldFileOnStartup; + + /// + /// Gets or sets whether to write the Header on initial creation of file appender. + /// Independent of file is empty or not. + /// Alternative use to ensure each application session has its own individual log-file. + /// + public bool WriteHeaderOnInitialFileOpen { get; set; } /// /// Gets or sets a value of the file size threshold to archive old log file on startup. @@ -2493,25 +2500,24 @@ private void WriteHeaderAndBom(BaseFileAppender appender) if (Header is null && !WriteBom) return; var length = appender.GetFileLength(); - // Write header and BOM only on empty files or if file info cannot be obtained. - if (length is null || length == 0) + // File is empty or file info cannot be obtained + var isNewOrEmptyFile = length is null || length == 0; + + if (isNewOrEmptyFile && WriteBom) { - if (WriteBom) - { - InternalLogger.Trace("{0}: Write byte order mark from encoding={1}", this, Encoding); - var preamble = Encoding.GetPreamble(); - if (preamble.Length > 0) - appender.Write(preamble, 0, preamble.Length); - } - - if (Header != null) + InternalLogger.Trace("{0}: Write byte order mark from encoding={1}", this, Encoding); + var preamble = Encoding.GetPreamble(); + if (preamble.Length > 0) + appender.Write(preamble, 0, preamble.Length); + } + + if (Header != null && (isNewOrEmptyFile || WriteHeaderOnInitialFileOpen)) + { + InternalLogger.Trace("{0}: Write header", this); + ArraySegment headerBytes = GetLayoutBytes(Header); + if (headerBytes.Count > 0) { - InternalLogger.Trace("{0}: Write header", this); - ArraySegment headerBytes = GetLayoutBytes(Header); - if (headerBytes.Count > 0) - { - appender.Write(headerBytes.Array, headerBytes.Offset, headerBytes.Count); - } + appender.Write(headerBytes.Array, headerBytes.Offset, headerBytes.Count); } } } diff --git a/tests/NLog.UnitTests/Targets/FileTargetTests.cs b/tests/NLog.UnitTests/Targets/FileTargetTests.cs index f90379cb84..f44a658fa4 100644 --- a/tests/NLog.UnitTests/Targets/FileTargetTests.cs +++ b/tests/NLog.UnitTests/Targets/FileTargetTests.cs @@ -2237,6 +2237,71 @@ public void RepeatingFooterTest(bool writeFooterOnArchivingOnly) Directory.Delete(tempDir, true); } } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void WriteHeaderOnStartupTest(bool writeHeaderOnInitialFileOpen) + { + var logFile = Path.GetTempFileName() + ".txt"; + try + { + const string header = "Headerline"; + + // Configure first time + var fileTarget = new FileTarget + { + FileName = SimpleLayout.Escape(logFile), + LineEnding = LineEndingMode.LF, + Layout = "${message}", + Header = header, + WriteBom = true, + WriteHeaderOnInitialFileOpen = true + }; + + LogManager.Setup().LoadConfiguration(c => c.ForLogger().WriteTo(fileTarget)); + + logger.Debug("aaa"); + logger.Info("bbb"); + logger.Warn("ccc"); + + LogManager.Configuration = null; + + string headerPart = header + LineEndingMode.LF.NewLineCharacters; + string logPart = "aaa\nbbb\nccc\n"; + AssertFileContents(logFile, headerPart + logPart, Encoding.UTF8, addBom: true); + + // Configure second time + fileTarget = new FileTarget + { + FileName = SimpleLayout.Escape(logFile), + LineEnding = LineEndingMode.LF, + Layout = "${message}", + Header = header, + WriteBom = true, + WriteHeaderOnInitialFileOpen = writeHeaderOnInitialFileOpen + }; + + LogManager.Setup().LoadConfiguration(c => c.ForLogger().WriteTo(fileTarget)); + + logger.Debug("aaa"); + logger.Info("bbb"); + logger.Warn("ccc"); + + LogManager.Configuration = null; // Flush + + if (writeHeaderOnInitialFileOpen) + AssertFileContents(logFile, headerPart + logPart + headerPart + logPart, Encoding.UTF8, addBom: true); + else + AssertFileContents(logFile, headerPart + logPart + logPart, Encoding.UTF8, addBom: true); + } + finally + { + LogManager.Configuration = null; + if (File.Exists(logFile)) + File.Delete(logFile); + } + } [Theory] [InlineData(false)]