Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add etw log for missing instrumentation key #1331

Merged
merged 8 commits into from
Dec 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace Microsoft.ApplicationInsights.Common
{
using System;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class InterlockedThrottleTests
{
[TestMethod]
public void VerifyInterlockedWorksAsExpected()
{
int testInterval = 10;
var counter = 0;

var its = new InterlockedThrottle(TimeSpan.FromSeconds(testInterval));

its.PerformThrottledAction(() => counter++);
its.PerformThrottledAction(() => counter++);
its.PerformThrottledAction(() => counter++);
its.PerformThrottledAction(() => counter++);

Assert.AreEqual(1, counter);

Thread.Sleep(TimeSpan.FromSeconds(testInterval +1));

its.PerformThrottledAction(() => counter++);
its.PerformThrottledAction(() => counter++);
its.PerformThrottledAction(() => counter++);
its.PerformThrottledAction(() => counter++);

Assert.AreEqual(2, counter);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)ActivityExtensionsTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\InterlockedThrottleTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataContracts\PageViewPerformanceTelemetryTest.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensibility\Implementation\DictionarySerializationWriterTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensibility\Implementation\Endpoints\EndpointContainerTests.cs" />
Expand Down
1 change: 1 addition & 0 deletions BASE/src/Common/Common/Common.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Extensions\ExceptionExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)InterlockedThrottle.cs" />
</ItemGroup>
</Project>
34 changes: 34 additions & 0 deletions BASE/src/Common/Common/InterlockedThrottle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace Microsoft.ApplicationInsights.Common
{
using System;
using System.Threading;

/// <summary>
/// This class will hold a timestamp and will perform a given action only if the current time has exceeded an interval.
/// </summary>
internal class InterlockedThrottle
{
private readonly TimeSpan interval;
private long timeStamp = DateTimeOffset.MinValue.Ticks;

/// <summary>
/// Initializes a new instance of the <see cref="InterlockedThrottle"/> class.
/// </summary>
/// <param name="interval">Defines the time period to perform some action.</param>
public InterlockedThrottle(TimeSpan interval) => this.interval = interval;

/// <summary>
/// Will execute the action only if the time period has elapsed.
/// </summary>
/// <param name="action">Action to be executed.</param>
public void PerformThrottledAction(Action action)
{
var now = DateTimeOffset.UtcNow;
if (now.Ticks > Interlocked.Read(ref this.timeStamp))
{
Interlocked.Exchange(ref this.timeStamp, now.Add(this.interval).Ticks);
action();
}
}
}
}
12 changes: 12 additions & 0 deletions BASE/src/Microsoft.ApplicationInsights/Channel/InMemoryChannel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace Microsoft.ApplicationInsights.Channel
{
using System;
using System.Diagnostics;
using Microsoft.ApplicationInsights.Common;
using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing;

/// <summary>
Expand All @@ -11,6 +13,9 @@ public class InMemoryChannel : ITelemetryChannel
{
private readonly TelemetryBuffer buffer;
private readonly InMemoryTransmitter transmitter;

private readonly InterlockedThrottle throttleEmptyIkeyLog = new InterlockedThrottle(interval: TimeSpan.FromSeconds(30));

private bool? developerMode = false;
private int bufferSize;

Expand Down Expand Up @@ -139,6 +144,13 @@ public void Send(ITelemetry item)
{
CoreEventSource.Log.ItemRejectedNoInstrumentationKey(item.ToString());
}
else
{
if (!Debugger.IsAttached)
{
this.throttleEmptyIkeyLog.PerformThrottledAction(() => CoreEventSource.Log.TelemetryChannelNoInstrumentationKey());
}
}

return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -581,9 +581,12 @@ public void InitializationIsSkippedForSampledItem(string appDomainName = "Incorr
[Event(55, Message = "TelemetryConfigurationFactory overwrote the InstrumentationKey with a value from an Environment Variable: {0}", Level = EventLevel.Informational)]
public void TelemetryConfigurationFactoryFoundInstrumentationKeyEnvironmentVariable(string variableName, string appDomainName = "Incorrect") => this.WriteEvent(55, variableName, this.nameProvider.Name);

[Event(56, Message = "TelemetryConfigurationFactory could not find an InstrumentationKey. This needs to be manually set.", Level = EventLevel.Warning, Keywords = Keywords.UserActionable)]
[Event(56, Message = "TelemetryConfigurationFactory did not find an InstrumentationKey in your config file. This needs to be set in either your config file or at application startup.", Level = EventLevel.Warning, Keywords = Keywords.UserActionable)]
public void TelemetryConfigurationFactoryNoInstrumentationKey(string appDomainName = "Incorrect") => this.WriteEvent(56, this.nameProvider.Name);

[Event(57, Message = "TelemetryChannel found a telemetry item without an InstrumentationKey. This is a required field and must be set in either your config file or at application startup.", Level = EventLevel.Error, Keywords = Keywords.UserActionable)]
public void TelemetryChannelNoInstrumentationKey(string appDomainName = "Incorrect") => this.WriteEvent(57, this.nameProvider.Name);

/// <summary>
/// Keywords for the PlatformEventSource.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,12 @@ public void SamplingConfigErrorBothTypes(string appDomainName = "Incorrect")
this.WriteEvent(73, this.ApplicationName);
}

[Event(74, Message = "TelemetryChannel found a telemetry item without an InstrumentationKey. This is a required field and must be set in either your config file or at application startup.", Level = EventLevel.Error, Keywords = Keywords.UserActionable)]
public void TelemetryChannelNoInstrumentationKey(string appDomainName = "Incorrect")
{
this.WriteEvent(74, this.ApplicationName);
}

private static string GetApplicationName()
{
//// We want to add application name to all events BUT
Expand Down
11 changes: 11 additions & 0 deletions BASE/src/ServerTelemetryChannel/ServerTelemetryChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
{
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Common;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.Implementation;

Expand All @@ -17,6 +19,8 @@ public sealed class ServerTelemetryChannel : ITelemetryChannel, ITelemetryModule
internal TelemetryBuffer TelemetryBuffer;
internal Transmitter Transmitter;

private readonly InterlockedThrottle throttleEmptyIkeyLog = new InterlockedThrottle(interval: TimeSpan.FromSeconds(30));

private bool? developerMode;
private int telemetryBufferCapacity;
private ITelemetryProcessor telemetryProcessor;
Expand Down Expand Up @@ -269,6 +273,13 @@ public void Send(ITelemetry item)
{
TelemetryChannelEventSource.Log.ItemRejectedNoInstrumentationKey(item.ToString());
}
else
{
if (!Debugger.IsAttached)
{
this.throttleEmptyIkeyLog.PerformThrottledAction(() => TelemetryChannelEventSource.Log.TelemetryChannelNoInstrumentationKey());
}
}

return;
}
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## VNext
- [Fix IndexOutOfRangeException in W3CUtilities.TryGetTraceId](https://github.com/microsoft/ApplicationInsights-dotnet/pull/1327)
- [Fix UpdateRequestTelemetryFromRequest throwing UriFormatException](https://github.com/microsoft/ApplicationInsights-dotnet/issues/1328)
- [Add ETW log for missing Instrumentation Key](https://github.com/microsoft/ApplicationInsights-dotnet/pull/1331)

## Version 2.12.0-beta4
- [Add support for collecting convention-based Azure SDK activities.](https://github.com/microsoft/ApplicationInsights-dotnet/pull/1300)
Expand Down