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 fa12d6b1e5..3af6d6629a 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 @@ -1,10 +1,14 @@ namespace Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnostics { + using System; using System.Diagnostics; using System.IO; + using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using Microsoft.VisualStudio.TestTools.UnitTesting; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; [TestClass] public class SelfDiagnosticsConfigRefresherTest @@ -36,7 +40,8 @@ public void SelfDiagnosticsConfigRefresher_OmitAsConfigured() // The event was omitted Assert.AreEqual('\0', (char)actualBytes[MessageOnNewFile.Length]); - }} + } + } finally { CleanupConfigFile(); @@ -74,6 +79,42 @@ public void SelfDiagnosticsConfigRefresher_CaptureAsConfigured() } } + [TestMethod] + public void SelfDiagnosticsConfigRefresher_ReadFromEnviornmentVar() + { + var key = "APPLICATIONINSIGHTS_LOG_DIAGNOSTICS"; + var val = @"C:\home\LogFiles\SelfDiagnostics"; + Environment.SetEnvironmentVariable(key, val); + + try + { + CreateConfigFile(false, val); + using (var configRefresher = new SelfDiagnosticsConfigRefresher()) + { + // Emitting event of EventLevel.Error + CoreEventSource.Log.InvalidOperationToStopError(); + var filePath = configRefresher.CurrentFilePath; + + int bufferSize = 512; + byte[] actualBytes = ReadFile(filePath, bufferSize); + string logText = Encoding.UTF8.GetString(actualBytes); + Assert.IsTrue(logText.StartsWith(MessageOnNewFileString)); + + // The event was captured + string logLine = logText.Substring(MessageOnNewFileString.Length); + string logMessage = ParseLogMessage(logLine); + string expectedMessage = "Operation to stop does not match the current operation. Telemetry is not tracked."; + Assert.IsTrue(logMessage.StartsWith(expectedMessage)); + } + } + finally + { + Environment.SetEnvironmentVariable(key, null); + Platform.PlatformSingleton.Current = null; // Force reinitialization in future tests so that new environment variables will be loaded. + CleanupConfigFile(); + } + } + private static string ParseLogMessage(string logLine) { int timestampPrefixLength = "2020-08-14T20:33:24.4788109Z:".Length; @@ -91,13 +132,24 @@ private static byte[] ReadFile(string filePath, int byteCount) } } - private static void CreateConfigFile() + private void CreateConfigFile(bool userDefinedLogDirectory = true, string envVarVal = "") { - string configJson = @"{ - ""LogDirectory"": ""."", - ""FileSize"": 1024, - ""LogLevel"": ""Error"" - }"; + ConfigFileObj configFileObj = new() + { + FileSize = 1024, + LogLevel = "Error" + }; + + if (userDefinedLogDirectory) + { + configFileObj.LogDirectory = "."; + } + else + { + configFileObj.LogDirectory = envVarVal; + } + + string configJson = JsonConvert.SerializeObject(configFileObj); using (FileStream file = File.Open(ConfigFilePath, FileMode.Create, FileAccess.Write)) { byte[] configBytes = Encoding.UTF8.GetBytes(configJson); @@ -105,6 +157,13 @@ private static void CreateConfigFile() } } + private class ConfigFileObj + { + public int FileSize { get; set; } + public string LogLevel { get; set; } + public string LogDirectory { get; set; } + }; + private static void CleanupConfigFile() { try @@ -116,4 +175,4 @@ private static void CleanupConfigFile() } } } -} +} \ No newline at end of file diff --git a/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigParser.cs b/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigParser.cs index 480e0085fe..b58299c5ee 100644 --- a/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigParser.cs +++ b/BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsConfigParser.cs @@ -5,6 +5,7 @@ using System.IO; using System.Text; using System.Text.RegularExpressions; + using Microsoft.ApplicationInsights.Extensibility.Implementation.Platform; internal class SelfDiagnosticsConfigParser { @@ -12,6 +13,8 @@ internal class SelfDiagnosticsConfigParser private const int FileSizeLowerLimit = 1024; // Lower limit for log file size in KB: 1MB private const int FileSizeUpperLimit = 128 * 1024; // Upper limit for log file size in KB: 128MB + private const string LogDiagnosticsEnvironmentVariable = "APPLICATIONINSIGHTS_LOG_DIAGNOSTICS"; + /// /// ConfigBufferSize is the maximum bytes of config file that will be read. /// @@ -40,8 +43,15 @@ public bool TryGetConfiguration(out string logDirectory, out int fileSizeInKB, o { var configFilePath = ConfigFileName; - // First check using current working directory - if (!File.Exists(configFilePath)) + // First, check whether the enviornment variable was set. + if (PlatformSingleton.Current.TryGetEnvironmentVariable(LogDiagnosticsEnvironmentVariable, out string logDiagnosticsPath)) + { + configFilePath = Path.Combine(logDiagnosticsPath, ConfigFileName); + logDirectory = logDiagnosticsPath; + } + + // Second, check using current working directory. + else if (!File.Exists(configFilePath)) { #if NET452 configFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigFileName); @@ -49,7 +59,7 @@ public bool TryGetConfiguration(out string logDirectory, out int fileSizeInKB, o configFilePath = Path.Combine(AppContext.BaseDirectory, ConfigFileName); #endif - // Second check using application base directory + // Third, check using application base directory. if (!File.Exists(configFilePath)) { return false; @@ -67,7 +77,8 @@ public bool TryGetConfiguration(out string logDirectory, out int fileSizeInKB, o file.Read(buffer, 0, buffer.Length); string configJson = Encoding.UTF8.GetString(buffer); - if (!TryParseLogDirectory(configJson, out logDirectory)) + + if (logDirectory == null && !TryParseLogDirectory(configJson, out logDirectory)) { return false; } diff --git a/CHANGELOG.md b/CHANGELOG.md index cc8302df20..824e4b8811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## VNext +- [Added support to read diagnostics config from the path defined in environment variable.](https://github.com/microsoft/ApplicationInsights-dotnet/pull/2769) ## Version 2.22.0-beta3 - [Do not report CosmosDB transport-level calls](https://github.com/microsoft/ApplicationInsights-dotnet/pull/2789)