// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); var appInsightsConfig = app.ApplicationServices.GetService <TelemetryConfiguration>(); TelemetryProcessorChainBuilder builder = appInsightsConfig.TelemetryProcessorChainBuilder; // some custom telemetry processor for Application Insights that filters out synthetic traffic (e.g traffic that comes from Azure to keep the server awake). builder.UseAdaptiveSampling(excludedTypes: "Exception"); builder.UseAdaptiveSampling(maxTelemetryItemsPerSecond: 10000); builder.Build(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); //ApplicationInsight //Initializers: TelemetryConfiguration.Active.TelemetryInitializers.Add(new HttpTelemetryInitializer()); TelemetryConfiguration.Active.TelemetryInitializers.Add(new HttpRequestTelemetryInitializer()); TelemetryConfiguration.Active.TelemetryInitializers.Add(new WebMethodInitializer()); //Procesors: TelemetryProcessorChainBuilder builder = TelemetryConfiguration.Active.DefaultTelemetrySink.TelemetryProcessorChainBuilder; builder.Use((next) => new TelemetryUnAuthorizedFilter(next)); builder.Use((next) => new TelemetryPathFilter(next)); builder.Use((next) => new TelemetryBotFilter(next)); builder.Use((next) => new TelemetryFastRemoteDependencyCallsFilter(next)); builder.Use((next) => new SuccessfulDependencyFilter(next)); builder.Build(); }
private static TelemetryProcessorChain CreateTelemetryProcessorChainWithSampling(IList <ITelemetry> sentTelemetry, double samplingPercentage, string excludedTypes = null, string includedTypes = null) { var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel() }; tc.InstrumentationKey = Guid.NewGuid().ToString("D"); var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.UseSampling(samplingPercentage, excludedTypes, includedTypes); channelBuilder.Use(next => new StubTelemetryProcessor(next) { OnProcess = t => sentTelemetry.Add(t) }); channelBuilder.Build(); TelemetryProcessorChain processors = tc.TelemetryProcessorChain; foreach (ITelemetryProcessor processor in processors.TelemetryProcessors) { ITelemetryModule m = processor as ITelemetryModule; if (m != null) { m.Initialize(tc); } } return(processors); }
internal static TelemetryConfiguration CreateTelemetryConfigWithExtractor(IList <ITelemetry> telemetrySentToChannel, Func <ITelemetryProcessor, AutocollectedMetricsExtractor> extractorFactory) { ITelemetryChannel channel = new StubTelemetryChannel { OnSend = (t) => telemetrySentToChannel.Add(t) }; string iKey = Guid.NewGuid().ToString("D"); TelemetryConfiguration telemetryConfig = new TelemetryConfiguration(iKey, channel); var channelBuilder = new TelemetryProcessorChainBuilder(telemetryConfig); channelBuilder.Use(extractorFactory); channelBuilder.Build(); TelemetryProcessorChain processors = telemetryConfig.TelemetryProcessorChain; foreach (ITelemetryProcessor processor in processors.TelemetryProcessors) { ITelemetryModule m = processor as ITelemetryModule; if (m != null) { m.Initialize(telemetryConfig); } } return(telemetryConfig); }
public static TelemetryConfiguration CreateAITelemetryConfig(out IList <ITelemetry> telemetrySentToChannel) { StubApplicationInsightsTelemetryChannel channel = new StubApplicationInsightsTelemetryChannel(); string iKey = Guid.NewGuid().ToString("D"); TelemetryConfiguration telemetryConfig = new TelemetryConfiguration(iKey, channel); var channelBuilder = new TelemetryProcessorChainBuilder(telemetryConfig); channelBuilder.Build(); foreach (ITelemetryProcessor initializer in telemetryConfig.TelemetryInitializers) { ITelemetryModule m = initializer as ITelemetryModule; if (m != null) { m.Initialize(telemetryConfig); } } foreach (ITelemetryProcessor processor in telemetryConfig.TelemetryProcessors) { ITelemetryModule m = processor as ITelemetryModule; if (m != null) { m.Initialize(telemetryConfig); } } telemetrySentToChannel = channel.TelemetryItems; return(telemetryConfig); }
public ApplicationInsightsWriter(string instrumentationKey, WriterOptions options) { TelemetryConfiguration.Active.InstrumentationKey = instrumentationKey; TelemetryProcessorChainBuilder builder = TelemetryConfiguration.Active.TelemetryProcessorChainBuilder; QuickPulseTelemetryProcessor quickPulseProcessor = null; // add our own telemetry processor that can override session based variables //builder.Use(next => new LogMagicTelemetryProcessor(next)); // optionally enable QuickPulse /* * - Free and is not counted towards the bill. * - The latency is 1 second compared to a few minutes. * - Retention is while the data is on the chart, not 90 days. * - Data is only streamed while you are in Live Metrics view. */ if (options.EnableQuickPulse) { builder.Use((next) => { quickPulseProcessor = new QuickPulseTelemetryProcessor(next); return(quickPulseProcessor); }); } builder.Build(); _telemetryClient = new TelemetryClient(TelemetryConfiguration.Active); _telemetryClient.InstrumentationKey = instrumentationKey; _context = new InsightsContext(_telemetryClient, options); if (options.EnableQuickPulse) { var quickPulse = new QuickPulseTelemetryModule(); quickPulse.Initialize(TelemetryConfiguration.Active); quickPulse.RegisterTelemetryProcessor(quickPulseProcessor); } #if NETFULL // see https://github.com/Microsoft/ApplicationInsights-dotnet-server/blob/develop/Src/PerformanceCollector/Perf.Shared/PerformanceCollectorModule.cs if (options.CollectPerformanceCounters) { //optionally enable performance counters collection var pcm = new PerformanceCollectorModule(); //custom counters can be easily added here if required pcm.Counters.Add(new PerformanceCounterCollectionRequest(@"\.NET CLR Memory(LogMagic.Console)\# GC Handles", "GC Handles")); pcm.Initialize(TelemetryConfiguration.Active); } #endif TelemetryConfiguration.Active.TelemetryInitializers.Add(new OperationTelemetryInitialiser()); _options = options; }
public void UseAdaptiveSamplingAddsAdaptiveSamplingProcessorToTheChainWithCorrectExcludedTypes() { var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel() }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.UseAdaptiveSampling("request"); channelBuilder.Build(); Assert.AreEqual("request", ((AdaptiveSamplingTelemetryProcessor)tc.TelemetryProcessorChain.FirstTelemetryProcessor).ExcludedTypes); }
public void UseSamplingSetsAddsSamplingProcessorToTheChainWithCorrectPercentage() { var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel() }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.UseSampling(5); channelBuilder.Build(); Assert.AreEqual(5, ((SamplingTelemetryProcessor)tc.TelemetryProcessorChain.FirstTelemetryProcessor).SamplingPercentage); }
public void UseAdaptiveSamplingAddsAdaptiveSamplingProcessorToTheChain() { var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel() }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.UseAdaptiveSampling(); channelBuilder.Build(); AssertEx.IsType <AdaptiveSamplingTelemetryProcessor>(tc.TelemetryProcessorChain.FirstTelemetryProcessor); }
public void UseAdaptiveSamplingAddsAdaptiveSamplingProcessorToTheChainWithCorrectMaxTelemetryItemsPerSecond() { var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel() }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.UseAdaptiveSampling(5); channelBuilder.Build(); Assert.AreEqual(5, ((AdaptiveSamplingTelemetryProcessor)tc.TelemetryProcessorChain.FirstTelemetryProcessor).MaxTelemetryItemsPerSecond); }
internal TelemetryConfiguration InitializeConfiguration() { TelemetryConfiguration config = new TelemetryConfiguration() { InstrumentationKey = _instrumentationKey }; AddInitializers(config); // Plug in Live stream and adaptive sampling QuickPulseTelemetryProcessor processor = null; TelemetryProcessorChainBuilder builder = config.TelemetryProcessorChainBuilder .Use((next) => { processor = new QuickPulseTelemetryProcessor(next); return(processor); }); if (_samplingSettings != null) { builder.Use((next) => { return(new AdaptiveSamplingTelemetryProcessor(_samplingSettings, null, next)); }); } builder.Build(); _quickPulseModule = new QuickPulseTelemetryModule(); _quickPulseModule.Initialize(config); _quickPulseModule.RegisterTelemetryProcessor(processor); // Plug in perf counters _perfModule = new PerformanceCollectorModule(); _perfModule.Initialize(config); // Configure the TelemetryChannel ITelemetryChannel channel = CreateTelemetryChannel(); // call Initialize if available ITelemetryModule module = channel as ITelemetryModule; if (module != null) { module.Initialize(config); } config.TelemetryChannel = channel; return(config); }
public void AllTelemetryCapturedWhenProductionRateIsLow() { var sentTelemetry = new List <ITelemetry>(); int itemsProduced = 0; using (var tc = new TelemetryConfiguration() { TelemetryChannel = new StubTelemetryChannel() }) { var chainBuilder = new TelemetryProcessorChainBuilder(tc); // set up adaptive sampling that evaluates and changes sampling % frequently chainBuilder .UseAdaptiveSampling( new Channel.Implementation.SamplingPercentageEstimatorSettings() { EvaluationInterval = TimeSpan.FromSeconds(1), SamplingPercentageDecreaseTimeout = TimeSpan.FromSeconds(2), SamplingPercentageIncreaseTimeout = TimeSpan.FromSeconds(2), }, this.TraceSamplingPercentageEvaluation) .Use((next) => new StubTelemetryProcessor(next) { OnProcess = (t) => sentTelemetry.Add(t) }); chainBuilder.Build(); const int productionFrequencyMs = 1000; var productionTimer = new Timer( (state) => { tc.TelemetryProcessorChain.Process(new RequestTelemetry()); itemsProduced++; }, null, productionFrequencyMs, productionFrequencyMs); Thread.Sleep(25000); // dispose timer and wait for callbacks to complete DisposeTimer(productionTimer); } Assert.AreEqual(itemsProduced, sentTelemetry.Count); }
public ApplicationInsightsWriter(string instrumentationKey, WriterOptions options) { TelemetryConfiguration.Active.InstrumentationKey = instrumentationKey; TelemetryProcessorChainBuilder builder = TelemetryConfiguration.Active.TelemetryProcessorChainBuilder; builder.Use(next => new LogMagicTelemetryProcessor(next)); builder.Build(); _telemetryClient = new TelemetryClient(TelemetryConfiguration.Active); _telemetryClient.InstrumentationKey = instrumentationKey; _context = new InsightsContext(_telemetryClient, options); _options = options; }
public void AdaptiveSamplingSetsExcludedTypesOnInternalSamplingProcessor() { var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel() }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.UseAdaptiveSampling(5, "request;"); channelBuilder.Build(); var fieldInfo = typeof(AdaptiveSamplingTelemetryProcessor).GetField("samplingProcessor", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); SamplingTelemetryProcessor internalProcessor = (SamplingTelemetryProcessor)fieldInfo.GetValue(tc.TelemetryProcessorChain.FirstTelemetryProcessor); Assert.AreEqual("request;", internalProcessor.ExcludedTypes); }
private static TelemetryProcessorChain CreateTelemetryProcessorChainWithSampling(IList <ITelemetry> sentTelemetry, double samplingPercentage, string excludedTypes = null, string includedTypes = null) { var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel() }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.UseSampling(samplingPercentage, excludedTypes, includedTypes); channelBuilder.Use(next => new StubTelemetryProcessor(next) { OnProcess = t => sentTelemetry.Add(t) }); channelBuilder.Build(); return(tc.TelemetryProcessorChain); }
private static TelemetryProcessorChain CreateTelemetryProcessorChainWithSampling(IList <ITelemetry> sentTelemetry, double samplingPercentage) { var tc = new TelemetryConfiguration() { TelemetryChannel = new StubTelemetryChannel() }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.UseSampling(samplingPercentage); channelBuilder.Use((next) => new StubTelemetryProcessor(next) { OnProcess = (t) => sentTelemetry.Add(t) }); channelBuilder.Build(); return(tc.TelemetryProcessors); }
internal static TelemetryConfiguration CreateTelemetryConfigWithExtractor(IList <ITelemetry> telemetrySentToChannel, Func <ITelemetryProcessor, AutocollectedMetricsExtractor> extractorFactory) { ITelemetryChannel channel = new StubTelemetryChannel { OnSend = (t) => telemetrySentToChannel.Add(t) }; string iKey = Guid.NewGuid().ToString("D"); TelemetryConfiguration telemetryConfig = new TelemetryConfiguration(iKey, channel); var channelBuilder = new TelemetryProcessorChainBuilder(telemetryConfig); channelBuilder.Use(extractorFactory); channelBuilder.Build(); return(telemetryConfig); }
public void UseAdaptiveSamplingAddsAdaptiveSamplingProcessorToTheChainWithCorrectSettings() { SamplingPercentageEstimatorSettings settings = new SamplingPercentageEstimatorSettings { MaxSamplingPercentage = 13 }; AdaptiveSamplingPercentageEvaluatedCallback callback = (second, percentage, samplingPercentage, changed, estimatorSettings) => { }; var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel() }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.UseAdaptiveSampling(settings, callback); channelBuilder.Build(); Assert.AreEqual(13, ((AdaptiveSamplingTelemetryProcessor)tc.TelemetryProcessorChain.FirstTelemetryProcessor).MaxSamplingPercentage); }
public void ProactivelySampledInItemsPassIfCurrentRateIsLowerThanExpected() { var sentTelemetry = new List <ITelemetry>(); var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel(), InstrumentationKey = Guid.NewGuid().ToString("D") }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.Use(next => new SamplingTelemetryProcessor(next) { SamplingPercentage = 50, ProactiveSamplingPercentage = 100 }); channelBuilder.Use(next => new StubTelemetryProcessor(next) { OnProcess = t => sentTelemetry.Add(t) }); channelBuilder.Build(); int sampledInCount = 0; for (int i = 0; i < 1000; i++) { var item = new RequestTelemetry(); item.Context.Operation.Id = ActivityTraceId.CreateRandom().ToHexString(); // sample in random items - they all should pass through regardless of the score if (i % 2 == 0) { item.ProactiveSamplingDecision = SamplingDecision.SampledIn; sampledInCount++; } tc.TelemetryProcessorChain.Process(item); } // all proactively sampled in items passed through regardless of their score. Assert.AreEqual(sampledInCount, sentTelemetry.Count(i => ((ISupportAdvancedSampling)i).ProactiveSamplingDecision == SamplingDecision.SampledIn)); }
public void ProactivelySampledInItemsPassAccordingToScoreIfCurrentRateIsHigherThanExpected() { var sentTelemetry = new List <ITelemetry>(); var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel(), InstrumentationKey = Guid.NewGuid().ToString("D") }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.Use(next => new SamplingTelemetryProcessor(next) { SamplingPercentage = 50, ProactiveSamplingPercentage = 50 }); channelBuilder.Use(next => new StubTelemetryProcessor(next) { OnProcess = t => sentTelemetry.Add(t) }); channelBuilder.Build(); int count = 5000; for (int i = 0; i < count; i++) { var item = new RequestTelemetry(); item.Context.Operation.Id = ActivityTraceId.CreateRandom().ToHexString(); // generate a lot sampled-in items, only 1/CurrentProactiveSampledInRatioToTarget of them should pass through // and SamplingPercentage of sampled-out items if (SamplingScoreGenerator.GetSamplingScore(item.Context.Operation.Id) < 80) { item.ProactiveSamplingDecision = SamplingDecision.SampledIn; } tc.TelemetryProcessorChain.Process(item); } Assert.AreEqual(0, sentTelemetry.Count(i => ((ISupportAdvancedSampling)i).ProactiveSamplingDecision == SamplingDecision.None)); Assert.AreEqual(count / 2, sentTelemetry.Count(i => ((ISupportAdvancedSampling)i).ProactiveSamplingDecision == SamplingDecision.SampledIn), count / 2 / 10); }
private TelemetryConfiguration GetAppInsightsTestTelemetryConfiguration() { var config = new TelemetryConfiguration(); config.InstrumentationKey = "58ce4b98-2e30-4ac1-982b-e47c85b8d31d"; // Fake, but needs to be there in order for TelemetryClient to call the processor chain. var channel = new TestTelemetryChannel(); config.DefaultTelemetrySink.TelemetryChannel = channel; var chainbuilder = new TelemetryProcessorChainBuilder(config, config.DefaultTelemetrySink); chainbuilder.Use((next) => { var p1 = new EventFlowTelemetryProcessor(next); return(p1); }); config.DefaultTelemetrySink.TelemetryProcessorChainBuilder = chainbuilder; chainbuilder.Build(); return(config); }
public void SamplingPercentageAdjustsAccordingToConstantHighProductionRate() { var sentTelemetry = new List <ITelemetry>(); int itemsProduced = 0; using (var tc = new TelemetryConfiguration() { TelemetryChannel = new StubTelemetryChannel() }) { var chainBuilder = new TelemetryProcessorChainBuilder(tc); // set up adaptive sampling that evaluates and changes sampling % frequently chainBuilder .UseAdaptiveSampling( new Channel.Implementation.SamplingPercentageEstimatorSettings() { EvaluationInterval = TimeSpan.FromSeconds(1), SamplingPercentageDecreaseTimeout = TimeSpan.FromSeconds(2), SamplingPercentageIncreaseTimeout = TimeSpan.FromSeconds(2), }, this.TraceSamplingPercentageEvaluation) .Use((next) => new StubTelemetryProcessor(next) { OnProcess = (t) => sentTelemetry.Add(t) }); chainBuilder.Build(); const int productionFrequencyMs = 100; var productionTimer = new Timer( (state) => { for (int i = 0; i < 2; i++) { tc.TelemetryProcessorChain.Process(new RequestTelemetry()); itemsProduced++; } }, null, 0, productionFrequencyMs); Thread.Sleep(25000); // dispose timer and wait for callbacks to complete DisposeTimer(productionTimer); } // number of items produced should be close to target of 5/second int targetItemCount = 25 * 5; // tolrance +- int tolerance = targetItemCount / 2; Trace.WriteLine(string.Format("'Ideal' telemetry item count: {0}", targetItemCount)); Trace.WriteLine(string.Format( "Expected range: from {0} to {1}", targetItemCount - tolerance, targetItemCount + tolerance)); Trace.WriteLine(string.Format( "Actual telemetry item count: {0} ({1:##.##}% of ideal)", sentTelemetry.Count, 100.0 * sentTelemetry.Count / targetItemCount)); Assert.IsTrue(sentTelemetry.Count > targetItemCount - tolerance); Assert.IsTrue(sentTelemetry.Count < targetItemCount + tolerance); }
public (int proactivelySampledInAndSentCount, double sentCount) ProactiveSamplingTest( int proactivelySampledInRatePerSec, int beforeSamplingRatePerSec, double targetAfterSamplingRatePerSec, double precision, int testDurationInSec) { // we'll ignore telemetry reported during first few percentage evaluations int warmUpInSec = 12; // we'll produce proactively sampled in items and also 'normal' items with the same rate // but allow only proactively sampled in + a bit more // number of items produced should be close to target int targetItemCount = (int)(testDurationInSec * targetAfterSamplingRatePerSec); var sentTelemetry = new List <ITelemetry>(); using (var tc = new TelemetryConfiguration() { TelemetryChannel = new StubTelemetryChannel() }) { var chainBuilder = new TelemetryProcessorChainBuilder(tc); // set up adaptive sampling that evaluates and changes sampling % frequently chainBuilder .UseAdaptiveSampling( new Channel.Implementation.SamplingPercentageEstimatorSettings() { // help algo get to stabilize earlier InitialSamplingPercentage = targetAfterSamplingRatePerSec / (double)beforeSamplingRatePerSec * 100, MaxTelemetryItemsPerSecond = targetAfterSamplingRatePerSec, EvaluationInterval = TimeSpan.FromSeconds(2), SamplingPercentageDecreaseTimeout = TimeSpan.FromSeconds(4), SamplingPercentageIncreaseTimeout = TimeSpan.FromSeconds(4), }, this.TraceSamplingPercentageEvaluation) .Use((next) => new StubTelemetryProcessor(next) { OnProcess = (t) => sentTelemetry.Add(t) }); chainBuilder.Build(); var sw = Stopwatch.StartNew(); var productionTimer = new Timer( (state) => { var requests = new RequestTelemetry[beforeSamplingRatePerSec]; for (int i = 0; i < beforeSamplingRatePerSec; i++) { requests[i] = new RequestTelemetry() { ProactiveSamplingDecision = i < proactivelySampledInRatePerSec ? SamplingDecision.SampledIn : SamplingDecision.None }; requests[i].Context.Operation.Id = ActivityTraceId.CreateRandom().ToHexString(); } foreach (var request in requests) { if (((Stopwatch)state).Elapsed.TotalSeconds < warmUpInSec) { // let's ignore telemetry from first few rate evaluations - it does not make sense request.Properties["ignore"] = "true"; } tc.TelemetryProcessorChain.Process(request); } }, sw, 0, 1000); Thread.Sleep(TimeSpan.FromSeconds(testDurationInSec + warmUpInSec)); // dispose timer and wait for callbacks to complete DisposeTimer(productionTimer); } var notIgnoredSent = sentTelemetry.Where(i => i is ISupportProperties propItem && !propItem.Properties.ContainsKey("ignore")).ToArray(); var proactivelySampledInAndSentCount = notIgnoredSent.Count(i => i is ISupportAdvancedSampling advSamplingItem && advSamplingItem.ProactiveSamplingDecision == SamplingDecision.SampledIn); // check that normal sampling requirements still apply (we generated as much items as expected) Trace.WriteLine($"'Ideal' telemetry item count: {targetItemCount}"); Trace.WriteLine($"Expected range: from {targetItemCount - precision * targetItemCount} to {targetItemCount + precision * targetItemCount}"); Trace.WriteLine( $"Actual telemetry item count: {notIgnoredSent.Length} ({100.0 * notIgnoredSent.Length / targetItemCount:##.##}% of ideal)"); Trace.WriteLine( $"Actual proactive sampled in and sent: {proactivelySampledInAndSentCount}"); Assert.IsTrue(notIgnoredSent.Length / (double)targetItemCount > 1 - precision); Assert.IsTrue(notIgnoredSent.Length / (double)targetItemCount < 1 + precision); return(proactivelySampledInAndSentCount, notIgnoredSent.Length); }
public void SamplingPercentageAdjustsForSpikyProductionRate() { var sentTelemetry = new List <ITelemetry>(); int itemsProduced = 0; using (var tc = new TelemetryConfiguration() { TelemetryChannel = new StubTelemetryChannel() }) { var chainBuilder = new TelemetryProcessorChainBuilder(tc); // set up adaptive sampling that evaluates and changes sampling % frequently chainBuilder .UseAdaptiveSampling( new SamplingPercentageEstimatorSettings() { InitialSamplingPercentage = 5.0, EvaluationInterval = TimeSpan.FromSeconds(1), SamplingPercentageDecreaseTimeout = TimeSpan.FromSeconds(2), SamplingPercentageIncreaseTimeout = TimeSpan.FromSeconds(10), }, this.TraceSamplingPercentageEvaluation) .Use((next) => new StubTelemetryProcessor(next) { OnProcess = (t) => sentTelemetry.Add(t) }); chainBuilder.Build(); const int regularProductionFrequencyMs = 100; const int spikeProductionFrequencyMs = 3000; using (var regularProductionTimer = new Timer( (state) => { for (int i = 0; i < 2; i++) { tc.TelemetryProcessorChain.Process(new RequestTelemetry()); Interlocked.Increment(ref itemsProduced); } }, null, 0, regularProductionFrequencyMs)) using (var spikeProductionTimer = new Timer( (state) => { for (int i = 0; i < 200; i++) { tc.TelemetryProcessorChain.Process(new RequestTelemetry()); Interlocked.Increment(ref itemsProduced); } }, null, 0, spikeProductionFrequencyMs)) { Thread.Sleep(30000); } } // number of items produced should be close to target of 5/second int targetItemCount = 30 * 5; int tolerance = targetItemCount / 2; Trace.WriteLine(string.Format("'Ideal' telemetry item count: {0}", targetItemCount)); Trace.WriteLine(string.Format( "Expected range: from {0} to {1}", targetItemCount - tolerance, targetItemCount + tolerance)); Trace.WriteLine(string.Format( "Actual telemetry item count: {0} ({1:##.##}% of ideal)", sentTelemetry.Count, 100.0 * sentTelemetry.Count / targetItemCount)); Assert.IsTrue(sentTelemetry.Count > targetItemCount - tolerance); Assert.IsTrue(sentTelemetry.Count < targetItemCount + tolerance); }