From 317786702ee9c356f7e452b6739fcdcceb59f455 Mon Sep 17 00:00:00 2001 From: Timothy Mothra Date: Fri, 9 Jul 2021 17:47:38 -0700 Subject: [PATCH] Self-Diagnostics: include datetimestamp in filename (#2325) * include datetimestamp in self-diagnostics filename * come review comments * update readme * update readme * Update Readme.md --- .../MemoryMappedFileHandlerTest.cs | 19 +++++++++++-------- .../SelfDiagnosticsConfigRefresherTest.cs | 15 ++++++++------- .../MemoryMappedFileHandler.cs | 17 +++++++++++++++-- .../SelfDiagnosticsConfigRefresher.cs | 2 ++ troubleshooting/ETW/Readme.md | 7 +++++-- 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/BASE/Test/Microsoft.ApplicationInsights.Test/Microsoft.ApplicationInsights.Tests/Extensibility/Implementation/Tracing/SelfDiagnostics/MemoryMappedFileHandlerTest.cs b/BASE/Test/Microsoft.ApplicationInsights.Test/Microsoft.ApplicationInsights.Tests/Extensibility/Implementation/Tracing/SelfDiagnostics/MemoryMappedFileHandlerTest.cs index 702d10f85..6e5d230a4 100644 --- a/BASE/Test/Microsoft.ApplicationInsights.Test/Microsoft.ApplicationInsights.Tests/Extensibility/Implementation/Tracing/SelfDiagnostics/MemoryMappedFileHandlerTest.cs +++ b/BASE/Test/Microsoft.ApplicationInsights.Test/Microsoft.ApplicationInsights.Tests/Extensibility/Implementation/Tracing/SelfDiagnostics/MemoryMappedFileHandlerTest.cs @@ -15,15 +15,16 @@ [TestMethod] public void MemoryMappedFileHandler_Success() { - var fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName) + "." - + Process.GetCurrentProcess().Id + ".log"; + string filePath; var fileSize = 1024; using (var handler = new MemoryMappedFileHandler()) { handler.CreateLogFile(".", fileSize); + + filePath = handler.CurrentFilePath; } - var actualBytes = ReadFile(fileName, MessageOnNewFile.Length); + var actualBytes = ReadFile(filePath, MessageOnNewFile.Length); CollectionAssert.AreEqual(MessageOnNewFile, actualBytes); } @@ -36,6 +37,8 @@ var messageToOverflow = Encoding.UTF8.GetBytes("1234567"); var expectedBytesAtEnd = Encoding.UTF8.GetBytes("1234"); var expectedBytesAtStart = Encoding.UTF8.GetBytes("567cessfully opened file.\n"); + string filePath; + using (var handler = new MemoryMappedFileHandler()) { handler.CreateLogFile(".", fileSize); @@ -43,20 +46,20 @@ handler.Write(buffer, fileSize - MessageOnNewFile.Length - expectedBytesAtEnd.Length); handler.Write(messageToOverflow, messageToOverflow.Length); + + filePath = handler.CurrentFilePath; } - var fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName) + "." - + Process.GetCurrentProcess().Id + ".log"; - var actualBytes = ReadFile(fileName, buffer.Length); + var actualBytes = ReadFile(filePath, buffer.Length); CollectionAssert.AreEqual(expectedBytesAtStart, SubArray(actualBytes, 0, expectedBytesAtStart.Length)); CollectionAssert.AreEqual(expectedBytesAtEnd, SubArray(actualBytes, actualBytes.Length - expectedBytesAtEnd.Length, expectedBytesAtEnd.Length)); } - private static byte[] ReadFile(string fileName, int byteCount) + private static byte[] ReadFile(string filePath, int byteCount) { byte[] actualBytes = new byte[byteCount]; - using (var file = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var file = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { file.Read(actualBytes, 0, byteCount); } diff --git a/BASE/Test/Microsoft.ApplicationInsights.Test/Microsoft.ApplicationInsights.Tests/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigRefresherTest.cs b/BASE/Test/Microsoft.ApplicationInsights.Test/Microsoft.ApplicationInsights.Tests/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigRefresherTest.cs index 5bd6318e0..fa12d6b1e 100644 --- a/BASE/Test/Microsoft.ApplicationInsights.Test/Microsoft.ApplicationInsights.Tests/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigRefresherTest.cs +++ b/BASE/Test/Microsoft.ApplicationInsights.Test/Microsoft.ApplicationInsights.Tests/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigRefresherTest.cs @@ -27,8 +27,10 @@ // Emitting event of EventLevel.Warning CoreEventSource.Log.OperationIsNullWarning(); + var filePath = configRefresher.CurrentFilePath; + int bufferSize = 512; - byte[] actualBytes = ReadFile(bufferSize); + byte[] actualBytes = ReadFile(filePath, bufferSize); string logText = Encoding.UTF8.GetString(actualBytes); Assert.IsTrue(logText.StartsWith(MessageOnNewFileString)); @@ -52,8 +54,10 @@ // Emitting event of EventLevel.Error CoreEventSource.Log.InvalidOperationToStopError(); + var filePath = configRefresher.CurrentFilePath; + int bufferSize = 512; - byte[] actualBytes = ReadFile(bufferSize); + byte[] actualBytes = ReadFile(filePath, bufferSize); string logText = Encoding.UTF8.GetString(actualBytes); Assert.IsTrue(logText.StartsWith(MessageOnNewFileString)); @@ -77,12 +81,9 @@ return logLine.Substring(timestampPrefixLength); } - private static byte[] ReadFile(int byteCount) + private static byte[] ReadFile(string filePath, int byteCount) { - var outputFileName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName) + "." - + Process.GetCurrentProcess().Id + ".log"; - var outputFilePath = Path.Combine(".", outputFileName); - using (var file = File.Open(outputFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var file = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { byte[] actualBytes = new byte[byteCount]; file.Read(actualBytes, 0, byteCount); diff --git a/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/MemoryMappedFileHandler.cs b/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/MemoryMappedFileHandler.cs index 2647ccf43..a319f43f8 100644 --- a/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/MemoryMappedFileHandler.cs +++ b/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/MemoryMappedFileHandler.cs @@ -2,6 +2,7 @@ namespace Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.Sel { using System; using System.Diagnostics; + using System.Globalization; using System.IO; using System.IO.MemoryMappedFiles; using System.Text; @@ -38,6 +39,8 @@ namespace Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.Sel public int LogFileSize { get => this.logFileSize; private set => this.logFileSize = value; } + public string CurrentFilePath => this.underlyingFileStreamForMemoryMappedFile?.Name; + /// /// Create a log file. If the file already exists, it will be overwritten. /// @@ -48,8 +51,7 @@ namespace Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.Sel try { Directory.CreateDirectory(logDirectory); - var fileName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName) + "." - + Process.GetCurrentProcess().Id + ".log"; + var fileName = GenerateFileName(); var filePath = Path.Combine(logDirectory, fileName); // Because the API [MemoryMappedFile.CreateFromFile][1](the string version) behaves differently on @@ -162,6 +164,17 @@ namespace Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.Sel } } + private static string GenerateFileName() + { + var dateTimeStamp = DateTime.UtcNow.ToString("yyyyMMdd-HHmmss", CultureInfo.InvariantCulture); + + var currentProcess = Process.GetCurrentProcess(); + var processFileName = Path.GetFileName(currentProcess.MainModule.FileName); + var processId = currentProcess.Id; + + return $"{dateTimeStamp}.{processFileName}.{processId}.log"; + } + /// /// Try to get the log stream which is seeked to the position where the next line of log should be written. /// diff --git a/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigRefresher.cs b/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigRefresher.cs index 5ec4aa95b..78b86d9fd 100644 --- a/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigRefresher.cs +++ b/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigRefresher.cs @@ -37,6 +37,8 @@ this.worker = Task.Run(() => this.Worker(this.cancellationTokenSource.Token), this.cancellationTokenSource.Token); } + public string CurrentFilePath => this.memoryMappedFileHandler.CurrentFilePath; + /// public void Dispose() { diff --git a/troubleshooting/ETW/Readme.md b/troubleshooting/ETW/Readme.md index 3662dc15f..0ccf3670a 100644 --- a/troubleshooting/ETW/Readme.md +++ b/troubleshooting/ETW/Readme.md @@ -122,7 +122,8 @@ As of version 2.18.0, this SDK ships a "self-diagnostics feature" which captures The self-diagnostics feature can be enabled/changed/disabled while the process is running. The SDK will attempt to read the configuration file every 10 seconds, using a non-exclusive read-only mode. -The SDK will create or overwrite a file with new logs according to the configuration. +The SDK will create or overwrite a file with new logs according to the configuration. +This file will not exceed the configured max size and will be circularly overwritten. #### Configuration @@ -150,13 +151,15 @@ Example: #### Configuration Parameters -A `FileSize`-KiB log file named as `ExecutableName.ProcessId.log` (e.g. `foobar.exe.12345.log`) will be generated at the specified directory `LogDirectory`. +A `FileSize`-KiB log file named as `YearMonthDay-HourMinuteSecond.ExecutableName.ProcessId.log` (e.g. `20010101-120000.foobar.exe.12345.log`) will be generated at the specified directory `LogDirectory`. +The file name starts with the `DateTime.UtcNow` timestamp of when the file was created. 1. `LogDirectory` is the directory where the output log file will be stored. It can be an absolute path or a relative path to the current directory. 2. `FileSize` is a positive integer, which specifies the log file size in [KiB](https://en.wikipedia.org/wiki/Kibibyte). This value must be between 1 MiB and 128 MiB (inclusive), or it will be rounded to the closest upper or lower limit. +The log file will never exceed this configured size, and will be circularly rewriten. 3. `LogLevel` is the lowest level of the events to be captured. This value must match one of the [fields](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventlevel#fields) of the `EventLevel` enum.