Skip to content

Commit

Permalink
Control Document Quotas for QuickPulse (#2425)
Browse files Browse the repository at this point in the history
* save initial work

* add tests

* save work

* save ongoing work

* end fix

* fix tests

* fix test errors

* fix tests

* remove debug comments

* save PR comment fixes

* add PR comment fix

* tiny fix

* add testcase

* fix PR comments

* fix PR commit

* add PR fix

* fix compile

* add PR comment fix

* Pr comment fix

* save Pr comment fix

* save Pr comment

* fix PR

* tentative changes for tests

* fix tests

* fix tests

* save tests targeting

* fix Pr comments

* PR comments fixed

* save PR fix

* add changelog edit

Co-authored-by: Timothy Mothra <tilee@microsoft.com>
  • Loading branch information
rambhatt-msft and TimothyMothra authored Oct 27, 2021
1 parent 9a431e2 commit 2c9b722
Show file tree
Hide file tree
Showing 12 changed files with 535 additions and 34 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## VNext
- [Allow Control of Documents sampling for QuickPulse telemetry](https://github.com/microsoft/ApplicationInsights-dotnet/pull/2425)

## Version 2.19.0-beta1
- [The `{OriginalFormat}` field in ILogger Scope will be emitted as `OriginalFormat` with the braces removed](https://github.com/microsoft/ApplicationInsights-dotnet/pull/2362)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Microsoft.ApplicationInsights.Tests
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.Extensibility.Filtering;
using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.Implementation.QuickPulse;
using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.Implementation.ServiceContract;
using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse;
using Microsoft.ApplicationInsights.Web.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
Expand Down Expand Up @@ -653,6 +654,222 @@ public void CollectionConfigurationCarriesOverQuotaWhenCreatingDocumentStreams()
Assert.AreEqual(3, documentStreams[3].EventQuotaTracker.CurrentQuota);
}

[TestMethod]
public void CollectionConfigurationWithMaxAndInitialQuotas()
{
// ARRANGE
var timeProvider = new ClockMock();

CollectionConfigurationError[] errors;
var oldDocumentStreamInfos = new[]
{
new DocumentStreamInfo()
{
Id = "Stream1",
DocumentFilterGroups =
new[]
{
new DocumentFilterConjunctionGroupInfo()
{
TelemetryType = TelemetryType.Request,
Filters = new FilterConjunctionGroupInfo() { Filters = new FilterInfo[0] }
}
}
},
new DocumentStreamInfo()
{
Id = "Stream2",
DocumentFilterGroups =
new[]
{
new DocumentFilterConjunctionGroupInfo()
{
TelemetryType = TelemetryType.Dependency,
Filters = new FilterConjunctionGroupInfo() { Filters = new FilterInfo[0] }
}
}
},
new DocumentStreamInfo()
{
Id = "Stream3",
DocumentFilterGroups =
new[]
{
new DocumentFilterConjunctionGroupInfo()
{
TelemetryType = TelemetryType.Exception,
Filters = new FilterConjunctionGroupInfo() { Filters = new FilterInfo[0] }
}
}
}
};

var newDocumentStreamInfos = new[]
{
new DocumentStreamInfo()
{
Id = "Stream1",
DocumentFilterGroups =
new[]
{
new DocumentFilterConjunctionGroupInfo()
{
TelemetryType = TelemetryType.Request,
Filters = new FilterConjunctionGroupInfo() { Filters = new FilterInfo[0] }
}
}
},
new DocumentStreamInfo()
{
Id = "Stream2",
DocumentFilterGroups =
new[]
{
new DocumentFilterConjunctionGroupInfo()
{
TelemetryType = TelemetryType.Dependency,
Filters = new FilterConjunctionGroupInfo() { Filters = new FilterInfo[0] }
}
}
},
new DocumentStreamInfo()
{
Id = "Stream3",
DocumentFilterGroups =
new[]
{
new DocumentFilterConjunctionGroupInfo()
{
TelemetryType = TelemetryType.Exception,
Filters = new FilterConjunctionGroupInfo() { Filters = new FilterInfo[0] }
}
}
},
new DocumentStreamInfo()
{
Id = "Stream4",
DocumentFilterGroups =
new[]
{
new DocumentFilterConjunctionGroupInfo()
{
TelemetryType = TelemetryType.Event,
Filters = new FilterConjunctionGroupInfo() { Filters = new FilterInfo[0] }
}
}
},
new DocumentStreamInfo()
{
Id = "Stream5",
DocumentFilterGroups =
new[]
{
new DocumentFilterConjunctionGroupInfo()
{
TelemetryType = TelemetryType.Trace,
Filters = new FilterConjunctionGroupInfo() { Filters = new FilterInfo[0] }
}
}
}
};

var oldCollectionConfigurationInfo = new CollectionConfigurationInfo()
{
DocumentStreams = oldDocumentStreamInfos,
ETag = "ETag1",
QuotaInfo = new QuotaConfigurationInfo()
{
InitialQuota = 10,
MaxQuota = 30
}
};
var oldCollectionConfiguration = new CollectionConfiguration(oldCollectionConfigurationInfo, out errors, timeProvider);

// spend some quota on the old configuration
var accumulatorManager = new QuickPulseDataAccumulatorManager(oldCollectionConfiguration);
var telemetryProcessor = new QuickPulseTelemetryProcessor(new SimpleTelemetryProcessorSpy());
((IQuickPulseTelemetryProcessor)telemetryProcessor).StartCollection(
accumulatorManager,
new Uri("http://microsoft.com"),
new TelemetryConfiguration() { InstrumentationKey = "some ikey" });

// ACT
// the initial quota is 3
telemetryProcessor.Process(new RequestTelemetry() { Context = { InstrumentationKey = "some ikey" } });

telemetryProcessor.Process(new DependencyTelemetry() { Context = { InstrumentationKey = "some ikey" } });
telemetryProcessor.Process(new DependencyTelemetry() { Context = { InstrumentationKey = "some ikey" } });

telemetryProcessor.Process(new ExceptionTelemetry() { Context = { InstrumentationKey = "some ikey" } });
telemetryProcessor.Process(new ExceptionTelemetry() { Context = { InstrumentationKey = "some ikey" } });
telemetryProcessor.Process(new ExceptionTelemetry() { Context = { InstrumentationKey = "some ikey" } });

// ACT
// the new configuration must carry the quotas over from the old one (only for those document streams that already existed)
var newCollectionConfigurationInfo = new CollectionConfigurationInfo() { DocumentStreams = newDocumentStreamInfos, ETag = "ETag1" };
var newCollectionConfiguration = new CollectionConfiguration(
newCollectionConfigurationInfo,
out errors,
timeProvider,
oldCollectionConfiguration.DocumentStreams);

// ASSERT
DocumentStream[] oldDocumentStreams = oldCollectionConfiguration.DocumentStreams.ToArray();
Assert.AreEqual(3, oldDocumentStreams.Length);

Assert.AreEqual("Stream1", oldDocumentStreams[0].Id);
Assert.AreEqual(9, oldDocumentStreams[0].RequestQuotaTracker.CurrentQuota);
Assert.AreEqual(10, oldDocumentStreams[0].DependencyQuotaTracker.CurrentQuota);
Assert.AreEqual(10, oldDocumentStreams[0].ExceptionQuotaTracker.CurrentQuota);
Assert.AreEqual(10, oldDocumentStreams[0].EventQuotaTracker.CurrentQuota);
Assert.AreEqual(10, oldDocumentStreams[0].EventQuotaTracker.CurrentQuota);

Assert.AreEqual("Stream2", oldDocumentStreams[1].Id);
Assert.AreEqual(10, oldDocumentStreams[1].RequestQuotaTracker.CurrentQuota);
Assert.AreEqual(8, oldDocumentStreams[1].DependencyQuotaTracker.CurrentQuota);
Assert.AreEqual(10, oldDocumentStreams[1].ExceptionQuotaTracker.CurrentQuota);
Assert.AreEqual(10, oldDocumentStreams[1].EventQuotaTracker.CurrentQuota);
Assert.AreEqual(10, oldDocumentStreams[1].EventQuotaTracker.CurrentQuota);

Assert.AreEqual("Stream3", oldDocumentStreams[2].Id);
Assert.AreEqual(10, oldDocumentStreams[2].RequestQuotaTracker.CurrentQuota);
Assert.AreEqual(10, oldDocumentStreams[2].DependencyQuotaTracker.CurrentQuota);
Assert.AreEqual(7, oldDocumentStreams[2].ExceptionQuotaTracker.CurrentQuota);
Assert.AreEqual(10, oldDocumentStreams[2].EventQuotaTracker.CurrentQuota);
Assert.AreEqual(10, oldDocumentStreams[2].EventQuotaTracker.CurrentQuota);

DocumentStream[] newDocumentStreams = newCollectionConfiguration.DocumentStreams.ToArray();
Assert.AreEqual(5, newDocumentStreams.Length);

Assert.AreEqual("Stream1", newDocumentStreams[0].Id);
Assert.AreEqual(9, newDocumentStreams[0].RequestQuotaTracker.CurrentQuota);
Assert.AreEqual(10, newDocumentStreams[0].DependencyQuotaTracker.CurrentQuota);
Assert.AreEqual(10, newDocumentStreams[0].ExceptionQuotaTracker.CurrentQuota);
Assert.AreEqual(10, newDocumentStreams[0].EventQuotaTracker.CurrentQuota);
Assert.AreEqual(10, newDocumentStreams[0].EventQuotaTracker.CurrentQuota);

Assert.AreEqual("Stream2", newDocumentStreams[1].Id);
Assert.AreEqual(10, newDocumentStreams[1].RequestQuotaTracker.CurrentQuota);
Assert.AreEqual(8, newDocumentStreams[1].DependencyQuotaTracker.CurrentQuota);
Assert.AreEqual(10, newDocumentStreams[1].ExceptionQuotaTracker.CurrentQuota);
Assert.AreEqual(10, newDocumentStreams[1].EventQuotaTracker.CurrentQuota);
Assert.AreEqual(10, newDocumentStreams[1].EventQuotaTracker.CurrentQuota);

Assert.AreEqual("Stream3", newDocumentStreams[2].Id);
Assert.AreEqual(10, newDocumentStreams[2].RequestQuotaTracker.CurrentQuota);
Assert.AreEqual(10, newDocumentStreams[2].DependencyQuotaTracker.CurrentQuota);
Assert.AreEqual(7, newDocumentStreams[2].ExceptionQuotaTracker.CurrentQuota);
Assert.AreEqual(10, newDocumentStreams[2].EventQuotaTracker.CurrentQuota);
Assert.AreEqual(10, newDocumentStreams[2].EventQuotaTracker.CurrentQuota);

Assert.AreEqual("Stream4", newDocumentStreams[3].Id);
Assert.AreEqual(3, newDocumentStreams[3].RequestQuotaTracker.CurrentQuota);
Assert.AreEqual(3, newDocumentStreams[3].DependencyQuotaTracker.CurrentQuota);
Assert.AreEqual(3, newDocumentStreams[3].ExceptionQuotaTracker.CurrentQuota);
Assert.AreEqual(3, newDocumentStreams[3].EventQuotaTracker.CurrentQuota);
Assert.AreEqual(3, newDocumentStreams[3].EventQuotaTracker.CurrentQuota);
}

[TestMethod]
public void CollectionConfigurationReportsDocumentStreamsWithDuplicateIds()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,5 +163,28 @@ public void QuickPulseQuotaTrackerIsThreadSafe()
Assert.AreEqual(correctResult, passedQuotaCount);
Assert.IsFalse(quotaTracker.ApplyQuota());
}

[TestMethod]
public void QuickPulseQuotaTrackerParameters()
{
// ARRANGE
int maxQuota = 500;
int experimentLengthInSeconds = 499;
var mockTimeProvider = new ClockMock();
var quotaTracker = new QuickPulseQuotaTracker(mockTimeProvider, maxQuota, 900, 1);

// ACT
for (int i = 0; i < experimentLengthInSeconds; i++)
{
mockTimeProvider.FastForward(TimeSpan.FromSeconds(1));

quotaTracker.ApplyQuota();
}

// ASSERT
Assert.AreEqual(499, quotaTracker.CurrentQuota);
Assert.AreEqual(500, quotaTracker.MaxQuota);
Assert.AreEqual(false, quotaTracker.QuotaExhausted);
}
}
}
Loading

0 comments on commit 2c9b722

Please sign in to comment.