From 59b35e984835ffa3dda9281aae725644c9a9b211 Mon Sep 17 00:00:00 2001 From: saidi-adot Date: Fri, 10 Mar 2023 14:52:35 -0700 Subject: [PATCH 1/5] #2714 Add support for connection string to Microsoft.ApplicationInsights.NLogTarget #2714 --- .../NLogTarget/ApplicationInsightsTarget.cs | 31 +++++- .../test/NLogTarget.Tests/NLogTargetTests.cs | 105 ++++++++++++++++-- LOGGING/test/Shared/AdapterHelper.cs | 9 +- 3 files changed, 132 insertions(+), 13 deletions(-) diff --git a/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs b/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs index 7d5e65d079..706173441e 100644 --- a/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs +++ b/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs @@ -13,6 +13,7 @@ namespace Microsoft.ApplicationInsights.NLogTarget using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.DataContracts; + using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; using Microsoft.ApplicationInsights.Implementation; @@ -31,6 +32,7 @@ public sealed class ApplicationInsightsTarget : TargetWithLayout private TelemetryClient telemetryClient; private DateTime lastLogEventTime; private NLog.Layouts.Layout instrumentationKeyLayout = string.Empty; + private NLog.Layouts.Layout connectionStringLayout = string.Empty; /// /// Initializers a new instance of ApplicationInsightsTarget type. @@ -50,6 +52,15 @@ public string InstrumentationKey set => this.instrumentationKeyLayout = value ?? string.Empty; } + /// + /// Gets or sets the Application Insights connectionstring for your application + /// + public string ConnectionString + { + get => (this.connectionStringLayout as NLog.Layouts.SimpleLayout)?.Text ?? null; + set => this.connectionStringLayout = value ?? string.Empty; + } + /// /// Gets the array of custom attributes to be passed into the logevent context. /// @@ -118,10 +129,24 @@ protected override void InitializeTarget() this.telemetryClient = new TelemetryClient(); #pragma warning restore CS0618 // Type or member is obsolete - string instrumentationKey = this.instrumentationKeyLayout.Render(LogEventInfo.CreateNullEvent()); - if (!string.IsNullOrWhiteSpace(instrumentationKey)) + string connectionString = this.connectionStringLayout.Render(LogEventInfo.CreateNullEvent()); + + // Check if nlog application insights target has connectionstring in config file then + // configure telemetryclient with the connectionstring otherwise using instrumentationkey. + if (!string.IsNullOrWhiteSpace(connectionString)) { - this.telemetryClient.Context.InstrumentationKey = instrumentationKey; + var configuration = TelemetryConfiguration.CreateDefault(); + configuration.ConnectionString = connectionString; + + this.telemetryClient.TelemetryConfiguration.ConnectionString = connectionString; + } + else + { + string instrumentationKey = this.instrumentationKeyLayout.Render(LogEventInfo.CreateNullEvent()); + if (!string.IsNullOrWhiteSpace(instrumentationKey)) + { + this.telemetryClient.Context.InstrumentationKey = instrumentationKey; + } } this.telemetryClient.Context.GetInternalContext().SdkVersion = SdkVersionUtils.GetSdkVersion("nlog:"); diff --git a/LOGGING/test/NLogTarget.Tests/NLogTargetTests.cs b/LOGGING/test/NLogTarget.Tests/NLogTargetTests.cs index 92a6604fd7..55c6be0651 100644 --- a/LOGGING/test/NLogTarget.Tests/NLogTargetTests.cs +++ b/LOGGING/test/NLogTarget.Tests/NLogTargetTests.cs @@ -226,11 +226,11 @@ public void TraceHasCustomProperties() var telemetry = (TraceTelemetry)this.adapterHelper.Channel.SentItems.FirstOrDefault(); Assert.IsNotNull(telemetry, "Didn't get the log event from the channel"); - Assert.AreEqual("Value", telemetry.Properties["Name"]); + Assert.AreEqual("Value", telemetry.Properties["Name"]); } - [TestMethod] + [TestMethod] [TestCategory("NLogTarget")] public void GlobalDiagnosticContextPropertiesAreAddedToProperties() { @@ -260,8 +260,8 @@ public void GlobalDiagnosticContextPropertiesSupplementEventProperties() aiLogger.Log(eventInfo); var telemetry = (TraceTelemetry)this.adapterHelper.Channel.SentItems.FirstOrDefault(); - Assert.AreEqual("global_value", telemetry.Properties["global_prop"]); - Assert.AreEqual("Value", telemetry.Properties["Name"]); + Assert.AreEqual("global_value", telemetry.Properties["global_prop"]); + Assert.AreEqual("Value", telemetry.Properties["Name"]); } [TestMethod] @@ -280,10 +280,10 @@ public void EventPropertyKeyNameIsAppendedWith_1_IfSameAsGlobalDiagnosticContext aiLogger.Log(eventInfo); var telemetry = (TraceTelemetry)this.adapterHelper.Channel.SentItems.FirstOrDefault(); - Assert.IsTrue(telemetry.Properties.ContainsKey("Name")); - Assert.AreEqual("Global Value", telemetry.Properties["Name"]); - Assert.IsTrue(telemetry.Properties.ContainsKey("Name_1"), "Key name altered"); - Assert.AreEqual("Value", telemetry.Properties["Name_1"]); + Assert.IsTrue(telemetry.Properties.ContainsKey("Name")); + Assert.AreEqual("Global Value", telemetry.Properties["Name"]); + Assert.IsTrue(telemetry.Properties.ContainsKey("Name_1"), "Key name altered"); + Assert.AreEqual("Value", telemetry.Properties["Name_1"]); } [TestMethod] @@ -459,6 +459,62 @@ public void NLogTargetFlushesTelemetryClient() Assert.AreEqual("Flush called", flushException.Message); } + [TestMethod] + [TestCategory("NLogTarget")] + public void NLogInfoIsSentAsInformationTraceItemWithAIConnectionString() + { + var aiLogger = this.CreateTargetWithGivenConnectionString("Your_ApplicationInsights_ConnectionString"); + aiLogger.Info("Info message"); + + var telemetry = (TraceTelemetry)this.adapterHelper.Channel.SentItems.First(); + Assert.AreEqual($"Info message", telemetry.Message); + } + + [TestMethod] + [TestCategory("NLogTarget")] + public void NLogTraceIsSentAsVerboseTraceItemWithAIConnectionString() + { + var aiLogger = this.CreateTargetWithGivenConnectionString("Your_ApplicationInsights_ConnectionString"); + aiLogger.Trace("Trace message"); + + var telemetry = (TraceTelemetry)this.adapterHelper.Channel.SentItems.FirstOrDefault(); + Assert.AreEqual("Trace message", telemetry.Message); + } + + [TestMethod] + [TestCategory("NLogTarget")] + public void NLogDebugIsSentAsVerboseTraceItemWithAIConnectionString() + { + var aiLogger = this.CreateTargetWithGivenConnectionString("Your_ApplicationInsights_ConnectionString"); + aiLogger.Debug("Debug Message"); + + var telemetry = (TraceTelemetry)this.adapterHelper.Channel.SentItems.FirstOrDefault(); + Assert.AreEqual("Debug Message", telemetry.Message); + } + + [TestMethod] + [TestCategory("NLogTarget")] + public void NLogWarnIsSentAsWarningTraceItemWithAIConnectionString() + { + var aiLogger = this.CreateTargetWithGivenConnectionString("Your_ApplicationInsights_ConnectionString"); + + aiLogger.Warn("Warn message"); + + var telemetry = (TraceTelemetry)this.adapterHelper.Channel.SentItems.FirstOrDefault(); + Assert.AreEqual("Warn message", telemetry.Message); + } + + [TestMethod] + [TestCategory("NLogTarget")] + public void NLogErrorIsSentAsVerboseTraceItemWithAIConnectionString() + { + var aiLogger = this.CreateTargetWithGivenConnectionString("Your_ApplicationInsights_ConnectionString"); + aiLogger.Error("Error Message"); + + var telemetry = (TraceTelemetry)this.adapterHelper.Channel.SentItems.FirstOrDefault(); + Assert.AreEqual("Error Message", telemetry.Message); + } + private void VerifyMessagesInMockChannel(Logger aiLogger, string instrumentationKey) { aiLogger.Trace("Sample trace message"); @@ -504,5 +560,38 @@ private Logger CreateTargetWithGivenInstrumentationKey( return aiLogger; } + + private Logger CreateTargetWithGivenConnectionString( + string connectionString = "Your_ApplicationInsights_ConnectionString", + Action loggerAction = null) + { + // Mock channel to validate that our appender is trying to send logs +#pragma warning disable CS0618 // Type or member is obsolete + TelemetryConfiguration.Active.TelemetryChannel = this.adapterHelper.Channel; +#pragma warning restore CS0618 // Type or member is obsolete + + ApplicationInsightsTarget target = new ApplicationInsightsTarget + { + ConnectionString = connectionString + }; + + LoggingRule rule = new LoggingRule("*", LogLevel.Trace, target); + LoggingConfiguration config = new LoggingConfiguration(); + config.AddTarget("AITarget", target); + config.LoggingRules.Add(rule); + + LogManager.Configuration = config; + Logger aiLogger = LogManager.GetLogger("AITarget"); + + if (loggerAction != null) + { + loggerAction(aiLogger); + target.Dispose(); + return null; + } + + return aiLogger; + } + } } diff --git a/LOGGING/test/Shared/AdapterHelper.cs b/LOGGING/test/Shared/AdapterHelper.cs index 9b926f8599..a59dcac7bf 100644 --- a/LOGGING/test/Shared/AdapterHelper.cs +++ b/LOGGING/test/Shared/AdapterHelper.cs @@ -19,6 +19,8 @@ public class AdapterHelper : IDisposable { public string InstrumentationKey { get; } + public string ConnectionString { get; } + #if NET452 || NET46 private static readonly string ApplicationInsightsConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ApplicationInsights.config"); @@ -27,16 +29,19 @@ public class AdapterHelper : IDisposable Path.Combine(Path.GetDirectoryName(typeof(AdapterHelper).GetTypeInfo().Assembly.Location), "ApplicationInsights.config"); #endif - public AdapterHelper(string instrumentationKey = "F8474271-D231-45B6-8DD4-D344C309AE69") + public AdapterHelper(string instrumentationKey = "F8474271-D231-45B6-8DD4-D344C309AE69", + string connectionString= "Your_ApplicationInsights_ConnectionString") { this.InstrumentationKey = instrumentationKey; + this.ConnectionString = connectionString; string configuration = string.Format(InvariantCulture, @" {0} + {1} ", - instrumentationKey); + instrumentationKey, connectionString); File.WriteAllText(ApplicationInsightsConfigFilePath, configuration); this.Channel = new CustomTelemetryChannel(); From d6f5598fed159ee5d1ba1f7bf283b1da9b119d2e Mon Sep 17 00:00:00 2001 From: saidi-adot Date: Tue, 17 Oct 2023 11:15:50 -0700 Subject: [PATCH 2/5] Fixing build issues for Application Insights NLogTarget --- .../net452/PublicAPI.Shipped.txt | 2 ++ LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.publicApi/Microsoft.ApplicationInsights.NLogTarget.dll/net452/PublicAPI.Shipped.txt b/.publicApi/Microsoft.ApplicationInsights.NLogTarget.dll/net452/PublicAPI.Shipped.txt index 1fa6d1888c..8471af83e6 100644 --- a/.publicApi/Microsoft.ApplicationInsights.NLogTarget.dll/net452/PublicAPI.Shipped.txt +++ b/.publicApi/Microsoft.ApplicationInsights.NLogTarget.dll/net452/PublicAPI.Shipped.txt @@ -3,6 +3,8 @@ Microsoft.ApplicationInsights.NLogTarget.ApplicationInsightsTarget.ApplicationIn Microsoft.ApplicationInsights.NLogTarget.ApplicationInsightsTarget.ContextProperties.get -> System.Collections.Generic.IList Microsoft.ApplicationInsights.NLogTarget.ApplicationInsightsTarget.InstrumentationKey.get -> string Microsoft.ApplicationInsights.NLogTarget.ApplicationInsightsTarget.InstrumentationKey.set -> void +Microsoft.ApplicationInsights.NLogTarget.ApplicationInsightsTarget.ConnectionString.get -> string +Microsoft.ApplicationInsights.NLogTarget.ApplicationInsightsTarget.ConnectionString.set -> void Microsoft.ApplicationInsights.NLogTarget.TargetPropertyWithContext Microsoft.ApplicationInsights.NLogTarget.TargetPropertyWithContext.Layout.get -> NLog.Layouts.Layout Microsoft.ApplicationInsights.NLogTarget.TargetPropertyWithContext.Layout.set -> void diff --git a/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs b/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs index 706173441e..68d464b00a 100644 --- a/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs +++ b/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs @@ -53,7 +53,7 @@ public string InstrumentationKey } /// - /// Gets or sets the Application Insights connectionstring for your application + /// Gets or sets the Application Insights connectionstring for your application. /// public string ConnectionString { From dca83104454f22c5a6a971d4393cf822785be555 Mon Sep 17 00:00:00 2001 From: saidi-adot Date: Thu, 19 Oct 2023 13:43:19 -0700 Subject: [PATCH 3/5] Updating documentation for Applictaion Insights ConnectionString NLog Target --- LOGGING/README.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/LOGGING/README.md b/LOGGING/README.md index c022877113..10c4837e26 100644 --- a/LOGGING/README.md +++ b/LOGGING/README.md @@ -37,7 +37,27 @@ Application Insights NLog Target nuget package adds ApplicationInsights target i If your application does not have web.config then it can also be configured manually. - * **Configure ApplicationInsightsTarget using NLog.config** : + * **Configure ApplicationInsightsTarget with ConnectionString using NLog.config** : +ConnectionString is the preferred approach to write logs into application insights. If nlog application insights target has connectionString in the config file then telemetryclient will configure with it otherwise it will configure with instrumentationkey. + +```xml + + + + + + + Your_ApplicationInsights_ConnectionString + + + + + + + +``` + + * **Configure ApplicationInsightsTarget with InstrumentationKey using NLog.config** : ```xml @@ -70,6 +90,11 @@ For more information see: ```csharp +// You need this only if you did not define ConnectionString or InstrumentationKey in ApplicationInsights.config (Or in the NLog.config) +TelemetryConfiguration.Active.ConnectionString = "Your_ApplicationInsights_ConnectionString"; + +or + // You need this only if you did not define InstrumentationKey in ApplicationInsights.config (Or in the NLog.config) TelemetryConfiguration.Active.InstrumentationKey = "Your_Resource_Key"; @@ -85,6 +110,9 @@ If you configure NLog programmatically with the [NLog Config API](https://github var config = new LoggingConfiguration(); ApplicationInsightsTarget target = new ApplicationInsightsTarget(); +// You need this only if you did not define AI ConnectionString in ApplicationInsights.config or want to use different connectionstring +target.ConnectionString = "Your_ApplicationInsights_ConnectionString"; +or // You need this only if you did not define InstrumentationKey in ApplicationInsights.config or want to use different instrumentation key target.InstrumentationKey = "Your_Resource_Key"; From 199655ad2a00bf27ce5b26f1df579b4d95762665 Mon Sep 17 00:00:00 2001 From: saidi-adot Date: Wed, 25 Oct 2023 14:34:09 -0700 Subject: [PATCH 4/5] Update README.md Adding Documentation for Application Insights ConnectionString NLog Target --- LOGGING/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LOGGING/README.md b/LOGGING/README.md index 10c4837e26..205bd238f1 100644 --- a/LOGGING/README.md +++ b/LOGGING/README.md @@ -38,7 +38,7 @@ Application Insights NLog Target nuget package adds ApplicationInsights target i If your application does not have web.config then it can also be configured manually. * **Configure ApplicationInsightsTarget with ConnectionString using NLog.config** : -ConnectionString is the preferred approach to write logs into application insights. If nlog application insights target has connectionString in the config file then telemetryclient will configure with it otherwise it will configure with instrumentationkey. +ConnectionString is the preferred approach to write logs into Application Insights. If the NLog Application Insights target has connectionString in the config file then TelemetryClient will use it, otherwise it will use the instrumentationKey. ```xml @@ -110,7 +110,7 @@ If you configure NLog programmatically with the [NLog Config API](https://github var config = new LoggingConfiguration(); ApplicationInsightsTarget target = new ApplicationInsightsTarget(); -// You need this only if you did not define AI ConnectionString in ApplicationInsights.config or want to use different connectionstring +// You need this only if you did not define Application Insights ConnectionString in ApplicationInsights.config or want to use different connectionstring target.ConnectionString = "Your_ApplicationInsights_ConnectionString"; or // You need this only if you did not define InstrumentationKey in ApplicationInsights.config or want to use different instrumentation key From fbff48952a4613303eb537a03a18506980dc2328 Mon Sep 17 00:00:00 2001 From: saidi-adot Date: Thu, 9 Nov 2023 17:13:58 -0700 Subject: [PATCH 5/5] Update ApplicationInsightsTarget.cs Resolving review comments --- LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs b/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs index 68d464b00a..2cf63dc456 100644 --- a/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs +++ b/LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs @@ -135,9 +135,6 @@ protected override void InitializeTarget() // configure telemetryclient with the connectionstring otherwise using instrumentationkey. if (!string.IsNullOrWhiteSpace(connectionString)) { - var configuration = TelemetryConfiguration.CreateDefault(); - configuration.ConnectionString = connectionString; - this.telemetryClient.TelemetryConfiguration.ConnectionString = connectionString; } else