Skip to content

Commit

Permalink
Adjusted unit-test to handle isolated TelemetryClient
Browse files Browse the repository at this point in the history
  • Loading branch information
snakefoot committed Aug 13, 2024
1 parent ea79e58 commit df34463
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 81 deletions.
49 changes: 35 additions & 14 deletions LOGGING/src/NLogTarget/ApplicationInsightsTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace Microsoft.ApplicationInsights.NLogTarget
public sealed class ApplicationInsightsTarget : TargetWithLayout
{
private TelemetryClient telemetryClient;
private DateTime lastLogEventTime;
private TelemetryConfiguration telemetryConfiguration;
private NLog.Layouts.Layout instrumentationKeyLayout = string.Empty;
private NLog.Layouts.Layout connectionStringLayout = string.Empty;

Expand Down Expand Up @@ -68,12 +68,9 @@ public string ConnectionString
public IList<TargetPropertyWithContext> ContextProperties { get; } = new List<TargetPropertyWithContext>();

/// <summary>
/// Gets the logging controller we will be using.
/// Gets or sets the factory for creating TelemetryConfiguration, so unit-tests can override in-memory-channel.
/// </summary>
internal TelemetryClient TelemetryClient
{
get { return this.telemetryClient; }
}
internal Func<TelemetryConfiguration> TelemetryConfigurationFactory { get; set; }

internal void BuildPropertyBag(LogEventInfo logEvent, ITelemetry trace)
{
Expand Down Expand Up @@ -119,9 +116,9 @@ internal void BuildPropertyBag(LogEventInfo logEvent, ITelemetry trace)
}

/// <summary>
/// Initializes the Target and perform instrumentationKey validation.
/// Initializes the Target and configures TelemetryClient.
/// </summary>
/// <exception cref="NLogConfigurationException">Will throw when <see cref="InstrumentationKey"/> is not set.</exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "ApplicationInsightsTarget class handles ownership of TelemetryConfiguration with Dispose.")]
protected override void InitializeTarget()
{
base.InitializeTarget();
Expand All @@ -132,9 +129,9 @@ protected override void InitializeTarget()
// configure new telemetryclient with the connectionstring otherwise using legacy instrumentationkey.
if (!string.IsNullOrWhiteSpace(connectionString))
{
var telemetryConfiguration = TelemetryConfiguration.CreateDefault();
telemetryConfiguration.ConnectionString = connectionString;
this.telemetryClient = new TelemetryClient(telemetryConfiguration);
this.telemetryConfiguration = this.TelemetryConfigurationFactory?.Invoke() ?? TelemetryConfiguration.CreateDefault();
this.telemetryConfiguration.ConnectionString = connectionString;
this.telemetryClient = new TelemetryClient(this.telemetryConfiguration);
}
else
{
Expand All @@ -151,6 +148,17 @@ protected override void InitializeTarget()
this.telemetryClient.Context.GetInternalContext().SdkVersion = SdkVersionUtils.GetSdkVersion("nlog:");
}

/// <summary>
/// Closes the target and releases resources used by the current instance of the <see cref="ApplicationInsightsTarget"/> class.
/// </summary>
protected override void CloseTarget()
{
this.telemetryConfiguration?.Dispose();
this.telemetryConfiguration = null;

base.CloseTarget();
}

/// <summary>
/// Send the log message to Application Insights.
/// </summary>
Expand All @@ -162,8 +170,6 @@ protected override void Write(LogEventInfo logEvent)
throw new ArgumentNullException(nameof(logEvent));
}

this.lastLogEventTime = DateTime.UtcNow;

if (logEvent.Exception != null)
{
this.SendException(logEvent);
Expand All @@ -187,14 +193,29 @@ protected override void FlushAsync(AsyncContinuation asyncContinuation)

try
{
this.TelemetryClient.FlushAsync(System.Threading.CancellationToken.None).ContinueWith(t => asyncContinuation(t.Exception));
this.telemetryClient.FlushAsync(System.Threading.CancellationToken.None).ContinueWith(t => asyncContinuation(t.Exception));
}
catch (Exception ex)
{
asyncContinuation(ex);
}
}

/// <summary>
/// Releases resources used by the current instance of the <see cref="ApplicationInsightsTarget"/> class.
/// </summary>
/// <param name="disposing">Dispose managed state (managed objects).</param>
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);

if (disposing)
{
this.telemetryConfiguration?.Dispose();
this.telemetryConfiguration = null;
}
}

private static void LoadLogEventProperties(LogEventInfo logEvent, IDictionary<string, string> propertyBag)
{
if (logEvent.Properties?.Count > 0)
Expand Down
67 changes: 7 additions & 60 deletions LOGGING/test/NLogTarget.Tests/NLogTargetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -455,64 +455,14 @@ public void NLogTargetFlushesTelemetryClient()
NLog.Common.AsyncContinuation asyncContinuation = (ex) => { flushException = ex; flushEvent.Set(); };
aiLogger.Factory.Flush(asyncContinuation, 5000);
Assert.IsTrue(flushEvent.WaitOne(5000));
Assert.IsNotNull(flushException);
Assert.AreEqual("Flush called", flushException.Message);
}

[TestMethod]
[TestCategory("NLogTarget")]
public void NLogInfoIsSentAsInformationTraceItemWithAIConnectionString()
public void NLogTargetWithConnectionString()
{
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("InstrumentationKey=b91a8f48-c77c-4f12-80e2-f96bc1abb126;IngestionEndpoint=https://centralus-2.in.applicationinsights.azure.com/;LiveEndpoint=https://centralus.livediagnostics.monitor.azure.com/");
aiLogger.Error("Error Message");

var telemetry = (TraceTelemetry)this.adapterHelper.Channel.SentItems.FirstOrDefault();
Assert.AreEqual("Error Message", telemetry.Message);
var aiLogger = this.CreateTargetWithGivenConnectionString("TestAI");
VerifyMessagesInMockChannel(aiLogger, "TestAI");
}

private void VerifyMessagesInMockChannel(Logger aiLogger, string instrumentationKey)
Expand Down Expand Up @@ -562,19 +512,16 @@ private Logger CreateTargetWithGivenInstrumentationKey(
}

private Logger CreateTargetWithGivenConnectionString(
string connectionString = "Your_ApplicationInsights_ConnectionString",
string instrumentationKey = "TEST",
Action<Logger> 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
ConnectionString = $"InstrumentationKey={instrumentationKey};IngestionEndpoint=https://localhost/;LiveEndpoint=https://localhost/"
};

target.TelemetryConfigurationFactory = () => new TelemetryConfiguration() { TelemetryChannel = this.adapterHelper.Channel };

LoggingRule rule = new LoggingRule("*", LogLevel.Trace, target);
LoggingConfiguration config = new LoggingConfiguration();
config.AddTarget("AITarget", target);
Expand Down
9 changes: 2 additions & 7 deletions LOGGING/test/Shared/AdapterHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ 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");
Expand All @@ -29,19 +27,16 @@ 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"
, string connectionString = "Your_ApplicationInsights_ConnectionString")
public AdapterHelper(string instrumentationKey = "F8474271-D231-45B6-8DD4-D344C309AE69")
{
this.InstrumentationKey = instrumentationKey;
this.ConnectionString = connectionString;

string configuration = string.Format(InvariantCulture,
@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<ApplicationInsights xmlns=""http://schemas.microsoft.com/ApplicationInsights/2013/Settings"">
<InstrumentationKey>{0}</InstrumentationKey>
</ApplicationInsights>",
instrumentationKey,
connectionString);
instrumentationKey);

File.WriteAllText(ApplicationInsightsConfigFilePath, configuration);
this.Channel = new CustomTelemetryChannel();
Expand Down

0 comments on commit df34463

Please sign in to comment.