public static void OnOpenedLifecycleHookCanWriteFileHeader() { using (var tmp = TempFolder.ForCaller()) { var headerWriter = new FileHeaderWriter("This is the file header"); var path = tmp.AllocateFilename("txt"); using (new FileSink(path, new JsonFormatter(), null, new UTF8Encoding(false), false, headerWriter)) { // Open and write header } using (var sink = new FileSink(path, new JsonFormatter(), null, new UTF8Encoding(false), false, headerWriter)) { // Length check should prevent duplicate header here sink.Emit(Some.LogEvent()); } var lines = System.IO.File.ReadAllLines(path); Assert.Equal(2, lines.Length); Assert.Equal(headerWriter.Header, lines[0]); Assert.Equal('{', lines[1][0]); } }
public void Should_write_header_at_start_of_log_file() { var headerWriter = new HeaderWriter(W3C_HEADER); var logEvents = Some.LogEvents(3); using (var temp = TempFolder.ForCaller()) { var path = temp.AllocateFilename("txt"); using (var log = new LoggerConfiguration() .WriteTo.File(Path.Combine(path), hooks: headerWriter) .CreateLogger()) { log.WriteAll(logEvents); } // Read the contents of the file that was written var lines = path.ReadAllLines(); // File should contain our header line plus 3 log events lines.Count.ShouldBe(1 + logEvents.Length); // Ensure the file starts with the header lines[0].ShouldBe(W3C_HEADER); // Ensure all the log events were written as normal for (var i = 0; i < logEvents.Length; i++) { lines[i + 1].ShouldEndWith(logEvents[i].MessageTemplate.Text); } } }
public void Should_compress_deleting_log_files_in_place() { var archiveWrapper = new ArchiveHooks(); using (var temp = TempFolder.ForCaller()) { var path = temp.AllocateFilename("log"); // Write events, such that we end up with 2 deleted files and 1 retained file WriteLogEvents(path, archiveWrapper, LogEvents); // Get all the files in the test directory var files = Directory.GetFiles(temp.Path) .OrderBy(p => p, StringComparer.OrdinalIgnoreCase) .ToArray(); // We should have a single log file, and 2 gz files files.Count(x => x.EndsWith("log")).ShouldBe(1); files.Count(x => x.EndsWith("gz")).ShouldBe(2); // Ensure the data was GZip compressed, by decompressing and comparing against what we wrote int i = 0; foreach (var gzipFile in files.Where(x => x.EndsWith("gz"))) { var lines = Utils.DecompressLines(gzipFile); lines.Count.ShouldBe(1); lines[0].ShouldEndWith(LogEvents[i].MessageTemplate.Text); i++; } } }
static void WriteTwoEventsAndCheckOutputFileLength(long?maxBytes, Encoding encoding) { using (var tmp = TempFolder.ForCaller()) { var path = tmp.AllocateFilename("txt"); var evt = Some.LogEvent("Irrelevant as it will be replaced by the formatter"); var actualEventOutput = "x"; var formatter = new FixedOutputFormatter(actualEventOutput); var eventOuputLength = encoding.GetByteCount(actualEventOutput); using (var sink = new FileSink(path, formatter, maxBytes, encoding: encoding)) { sink.Emit(evt); } var size = new FileInfo(path).Length; Assert.Equal(encoding.GetPreamble().Length + eventOuputLength, size); //write a second event to the same file using (var sink = new FileSink(path, formatter, maxBytes, encoding: encoding)) { sink.Emit(evt); } size = new FileInfo(path).Length; Assert.Equal(encoding.GetPreamble().Length + eventOuputLength * 2, size); } }
public void OnOpenedLifecycleHookCanWrapUnderlyingStream() { var gzipWrapper = new GZipHooks(); using (var tmp = TempFolder.ForCaller()) { var path = tmp.AllocateFilename("txt"); var evt = Some.LogEvent("Hello, world!"); using (var sink = new FileSink(path, new JsonFormatter(), null, null, false, gzipWrapper)) { sink.Emit(evt); sink.Emit(evt); } // Ensure the data was written through the wrapping GZipStream, by decompressing and comparing against // what we wrote List <string> lines; using (var textStream = new MemoryStream()) { using (var fs = System.IO.File.OpenRead(path)) using (var decompressStream = new GZipStream(fs, CompressionMode.Decompress)) { decompressStream.CopyTo(textStream); } textStream.Position = 0; lines = textStream.ReadAllLines(); } Assert.Equal(2, lines.Count); Assert.Contains("Hello, world!", lines[0]); } }
public void ANewLogBufferIsEmpty() { using (var temp = TempFolder.ForCaller()) using (var buffer = new LogBuffer(temp.AllocateFilename("mdb"), DefaultBufferSize)) { var contents = buffer.Peek((int)DefaultBufferSize); Assert.Equal(0, contents.Length); } }
public void WhenWritingLoggingExceptionsAreSuppressed() { using (var tmp = TempFolder.ForCaller()) using (var log = new LoggerConfiguration() .WriteTo.File(new ThrowingLogEventFormatter(), tmp.AllocateFilename()) .CreateLogger()) { log.Information("Hello"); } }
public void WhenAuditingLoggingExceptionsPropagate() { using (var tmp = TempFolder.ForCaller()) using (var log = new LoggerConfiguration() .AuditTo.File(new ThrowingLogEventFormatter(), tmp.AllocateFilename()) .CreateLogger()) { var ex = Assert.Throws <AggregateException>(() => log.Information("Hello")); Assert.IsType <NotImplementedException>(ex.GetBaseException()); } }
public void WhenFlushingToDiskReportedSharedFileSinkCanBeCreatedAndDisposed() { using (var tmp = TempFolder.ForCaller()) using (var log = new LoggerConfiguration() .WriteTo.File(tmp.AllocateFilename(), shared: true, flushToDiskInterval: TimeSpan.FromMilliseconds(500)) .CreateLogger()) { log.Information("Hello"); Thread.Sleep(TimeSpan.FromSeconds(1)); } }
public void SinkCanBeConfiguredAndDisposedWhenFlushIntervalSpecified() { using (var temp = TempFolder.ForCaller()) using (var logger = new LoggerConfiguration() .WriteTo.RollingFile(temp.AllocateFilename(), flushToDiskInterval: TimeSpan.FromMilliseconds(500)) .CreateLogger()) { logger.Information("Hello, rolling file."); Thread.Sleep(TimeSpan.FromSeconds(1)); } }
public void AtLeastOneEventIsAlwaysDequeued() { using (var temp = TempFolder.ForCaller()) using (var buffer = new LogBuffer(temp.AllocateFilename("mdb"), DefaultBufferSize)) { byte[] a1 = Some.Bytes(140), a2 = Some.Bytes(140), a3 = Some.Bytes(140); buffer.Enqueue(new[] { a1, a2, a3 }); var contents = buffer.Peek(30); Assert.Equal(1, contents.Length); Assert.Equal(a1, contents[0].Value); } }
public void PeekingDoesNotChangeState() { using (var temp = TempFolder.ForCaller()) using (var buffer = new LogBuffer(temp.AllocateFilename("mdb"), DefaultBufferSize)) { buffer.Enqueue(new[] { Some.Bytes(140) }); var contents = buffer.Peek((int)DefaultBufferSize); Assert.Equal(1, contents.Length); var remainder = buffer.Peek((int)DefaultBufferSize); Assert.Equal(1, remainder.Length); } }
public void SizeHintLimitsDequeuedEventCount() { using (var temp = TempFolder.ForCaller()) using (var buffer = new LogBuffer(temp.AllocateFilename("mdb"), DefaultBufferSize)) { byte[] a1 = Some.Bytes(140), a2 = Some.Bytes(140), a3 = Some.Bytes(140); buffer.Enqueue(new[] { a1, a2, a3 }); var contents = buffer.Peek(300); Assert.Equal(2, contents.Length); Assert.Equal(a1, contents[0].Value); Assert.Equal(a2, contents[1].Value); } }
public void EntriesOverLimitArePurgedFifo() { using (var temp = TempFolder.ForCaller()) using (var buffer = new LogBuffer(temp.AllocateFilename("mdb"), 4096)) { byte[] a1 = Some.Bytes(140), a2 = Some.Bytes(140), a3 = Some.Bytes(140); buffer.Enqueue(new[] { a1, a2, a3 }); var contents = buffer.Peek((int)DefaultBufferSize); Assert.Equal(2, contents.Length); Assert.Equal(a2, contents[0].Value); Assert.Equal(a3, contents[1].Value); } }
public void FileIsWrittenIfNonexistent() { using (var tmp = TempFolder.ForCaller()) { var nonexistent = tmp.AllocateFilename("txt"); var evt = Some.LogEvent("Hello, world!"); using (var sink = new FileSink(nonexistent, new JsonFormatter(), null)) { sink.Emit(evt); } var lines = System.IO.File.ReadAllLines(nonexistent); Assert.Contains("Hello, world!", lines[0]); } }
public void SpecifiedEncodingIsPropagated(bool shared) { using (var tmp = TempFolder.ForCaller()) { var filename = tmp.AllocateFilename("txt"); using (var log = new LoggerConfiguration() .WriteTo.File(filename, outputTemplate: "{Message}", encoding: Encoding.Unicode, shared: shared) .CreateLogger()) { log.Information("ten chars."); } // Don't forget the two-byte BOM :-) Assert.Equal(22, System.IO.File.ReadAllBytes(filename).Length); } }
public void GivingTheLastSeenEventKeyRemovesPrecedingEvents() { using (var temp = TempFolder.ForCaller()) using (var buffer = new LogBuffer(temp.AllocateFilename("mdb"), DefaultBufferSize)) { byte[] a1 = Some.Bytes(140), a2 = Some.Bytes(140), a3 = Some.Bytes(140); buffer.Enqueue(new[] { a1, a2, a3 }); var contents = buffer.Peek(420); Assert.Equal(3, contents.Length); buffer.Dequeue(contents[2].Key); var remaining = buffer.Peek(420); Assert.Equal(0, remaining.Length); } }
public void Should_compress_rolling_log_files() { var gzipWrapper = new GZipHooks(); var logEvents = new[] { Some.LogEvent(), Some.LogEvent(), Some.LogEvent() }; using (var temp = TempFolder.ForCaller()) { var path = temp.AllocateFilename("gz"); // Use a rolling log file configuration with a 1-byte size limit, so we roll after each log event using (var log = new LoggerConfiguration() .WriteTo.File(path, rollOnFileSizeLimit: true, fileSizeLimitBytes: 1, hooks: gzipWrapper) .CreateLogger()) { foreach (var logEvent in logEvents) { log.Write(logEvent); } } // Get all the files the rolling file sink wrote var files = Directory.GetFiles(temp.Path) .OrderBy(p => p, StringComparer.OrdinalIgnoreCase) .ToArray(); // We should have a file for each entry in logEvents files.Length.ShouldBe(logEvents.Length); // Ensure the data was written through the wrapping GZipStream, by decompressing and comparing against // what we wrote for (var i = 0; i < files.Length; i++) { var lines = Utils.DecompressLines(files[i]); lines.Count.ShouldBe(1); lines[0].ShouldEndWith(logEvents[i].MessageTemplate.Text); } } }
public void EnumerationIsInOrder() { using (var temp = TempFolder.ForCaller()) using (var buffer = new LogBuffer(temp.AllocateFilename("mdb"), DefaultBufferSize)) { byte[] a1 = Some.Bytes(140), a2 = Some.Bytes(140), a3 = Some.Bytes(140); buffer.Enqueue(new[] { a1, a2, a3 }); var contents = new List <byte[]>(); buffer.Enumerate((k, v) => { contents.Add(v); }); Assert.Equal(3, contents.Count); Assert.Equal(new[] { a1, a2, a3 }, contents); } }
public void Should_write_header_at_start_of_rolling_log_files() { var headerWriter = new HeaderWriter(W3C_HEADER); var logEvents = Some.LogEvents(3); using (var temp = TempFolder.ForCaller()) { var path = temp.AllocateFilename("txt"); // Use a rolling log file configuration with a 50-byte size limit, so we roll after writing the header and a single log event using (var log = new LoggerConfiguration() .WriteTo.File(path, rollOnFileSizeLimit: true, fileSizeLimitBytes: 50, hooks: headerWriter) .CreateLogger()) { log.WriteAll(logEvents); } // Get all the files the rolling file sink wrote var files = Directory.GetFiles(temp.Path) .OrderBy(p => p, StringComparer.OrdinalIgnoreCase) .ToArray(); // We should have found a file for each entry in logEvents files.Length.ShouldBe(logEvents.Length); // Check each file to ensure it contains our header plus 1 log event for (var i = 0; i < files.Length; i++) { var lines = files[i].ReadAllLines(); // File should contain our header line plus 1 log event lines.Count.ShouldBe(2); // Ensure the file starts with the header lines[0].ShouldBe(W3C_HEADER); // Ensure the log event was written as normal lines[1].ShouldEndWith(logEvents[i].MessageTemplate.Text); } } }
public void Should_expand_tokens_in_target_path() { using (var temp = TempFolder.ForCaller()) { var subfolder = temp.AllocateFolderName(); var targetDirPath = Path.Combine(subfolder, "{Date:yyyy}"); var path = temp.AllocateFilename("log"); var archiveWrapper = new ArchiveHooks(CompressionLevel.NoCompression, targetDirPath); // Write events, such that we end up with 2 deleted files and 1 retained file WriteLogEvents(path, archiveWrapper, LogEvents); // Get the final, expanded target directory var targetDirs = Directory.GetDirectories(subfolder); targetDirs.Length.ShouldBe(1); // Ensure the directory name contains the expanded date token targetDirs[0].ShouldEndWith(DateTime.Now.ToString("yyyy")); } }
public void WhenLimitIsNotSpecifiedFileSizeIsNotRestricted() { const int maxBytes = 5000; const int eventsToLimit = 10; using (var tmp = TempFolder.ForCaller()) { var path = tmp.AllocateFilename("txt"); var evt = Some.LogEvent(new string('n', maxBytes / eventsToLimit)); using (var sink = new FileSink(path, new JsonFormatter(), null)) { for (var i = 0; i < eventsToLimit * 2; i++) { sink.Emit(evt); } } var size = new FileInfo(path).Length; Assert.True(size > maxBytes * 2); } }
public void FileIsAppendedToWhenAlreadyCreated() { using (var tmp = TempFolder.ForCaller()) { var path = tmp.AllocateFilename("txt"); var evt = Some.LogEvent("Hello, world!"); using (var sink = new FileSink(path, new JsonFormatter(), null)) { sink.Emit(evt); } using (var sink = new FileSink(path, new JsonFormatter(), null)) { sink.Emit(evt); } var lines = System.IO.File.ReadAllLines(path); Assert.Contains("Hello, world!", lines[0]); Assert.Contains("Hello, world!", lines[1]); } }
public void Should_copy_deleting_log_files() { using (var temp = TempFolder.ForCaller()) { var targetDirPath = temp.AllocateFolderName(); var path = temp.AllocateFilename("log"); var archiveWrapper = new ArchiveHooks(CompressionLevel.NoCompression, targetDirPath); // Write events, such that we end up with 2 deleted files and 1 retained file WriteLogEvents(path, archiveWrapper, LogEvents); // Get all the files in the test directory var files = Directory.GetFiles(temp.Path) .OrderBy(p => p, StringComparer.OrdinalIgnoreCase) .ToArray(); // We should only have a single log file files.Length.ShouldBe(1); // Get all the files in the target directory var targetFiles = Directory.GetFiles(targetDirPath) .OrderBy(p => p, StringComparer.OrdinalIgnoreCase) .ToArray(); // We should have 2 log files in the target directory targetFiles.Length.ShouldBe(2); targetFiles.ShouldAllBe(x => x.EndsWith(".log")); // Ensure the content matches what we wrote for (var i = 0; i < targetFiles.Length; i++) { var lines = System.IO.File.ReadAllLines(targetFiles[i]); lines.Length.ShouldBe(1); lines[0].ShouldEndWith(LogEvents[i].MessageTemplate.Text); } } }
public void Should_compress_log_file() { var gzipWrapper = new GZipHooks(); var logEvents = new[] { Some.LogEvent(), Some.LogEvent(), Some.LogEvent() }; using (var temp = TempFolder.ForCaller()) { var path = temp.AllocateFilename("gz"); using (var log = new LoggerConfiguration() .WriteTo.File(Path.Combine(path), hooks: gzipWrapper) .CreateLogger()) { foreach (var logEvent in logEvents) { log.Write(logEvent); } } // Ensure the data was written through the wrapping GZipStream, by decompressing and comparing against // what we wrote var lines = Utils.DecompressLines(path); lines.Count.ShouldBe(logEvents.Length); for (var i = 0; i < logEvents.Length; i++) { lines[i].ShouldEndWith(logEvents[i].MessageTemplate.Text); } } }
public void Should_write_header_to_non_empty_stream_is_required() { var headerWriter = new HeaderWriter(W3C_HEADER, true); var logEvents = Some.LogEvents(3); using (var temp = TempFolder.ForCaller()) { var path = temp.AllocateFilename("txt"); // Write something to the start of the log file System.IO.File.WriteAllText(path, "Myergen\n"); using (var log = new LoggerConfiguration() .WriteTo.File(Path.Combine(path), hooks: headerWriter) .CreateLogger()) { log.WriteAll(logEvents); } // Read the contents of the file that was written var lines = path.ReadAllLines(); // File should contain the content line, our header line, and the 3 log events, lines.Count.ShouldBe(1 + 1 + logEvents.Length); // Ensure the file contains the header lines[1].ShouldBe(W3C_HEADER); // Ensure all the log events were written as normal for (var i = 0; i < logEvents.Length; i++) { lines[i + 2].ShouldEndWith(logEvents[i].MessageTemplate.Text); } } }