/// <summary> /// Initializes a new instance of the <see cref="QuickPulseTelemetryModule"/> class. Internal constructor for unit tests only. /// </summary> /// <param name="collectionTimeSlotManager">Collection time slot manager.</param> /// <param name="dataAccumulatorManager">Data hub to sink QuickPulse data to.</param> /// <param name="serviceClient">QPS service client.</param> /// <param name="performanceCollector">Performance counter collector.</param> /// <param name="timings">Timings for the module.</param> internal QuickPulseTelemetryModule( QuickPulseCollectionTimeSlotManager collectionTimeSlotManager, QuickPulseDataAccumulatorManager dataAccumulatorManager, IQuickPulseServiceClient serviceClient, IPerformanceCollector performanceCollector, QuickPulseTimings timings) : this() { this.collectionTimeSlotManager = collectionTimeSlotManager; this.dataAccumulatorManager = dataAccumulatorManager; this.serviceClient = serviceClient; this.performanceCollector = performanceCollector; this.timings = timings; }
public void QuickPulseTelemetryModuleCollectsData() { // ARRANGE var pause = TimeSpan.FromMilliseconds(100); var interval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(interval, interval); var collectionTimeSlotManager = new QuickPulseCollectionTimeSlotManagerMock(timings); var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = true, ReturnValueFromSubmitSample = true }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule(collectionTimeSlotManager, null, serviceClient, performanceCollector, timings); var telemetryProcessor = new QuickPulseTelemetryProcessor(new SimpleTelemetryProcessorSpy()); telemetryProcessor.Initialize(new TelemetryConfiguration()); module.RegisterTelemetryProcessor(telemetryProcessor); // ACT module.Initialize(new TelemetryConfiguration() { InstrumentationKey = "some ikey" }); Thread.Sleep(pause); telemetryProcessor.Process(new RequestTelemetry() { Context = { InstrumentationKey = "some ikey" } }); telemetryProcessor.Process(new DependencyTelemetry() { Context = { InstrumentationKey = "some ikey" } }); Thread.Sleep(pause); Assert.AreEqual(1, serviceClient.PingCount); // ASSERT serviceClient.ReturnValueFromPing = false; serviceClient.ReturnValueFromSubmitSample = false; Thread.Sleep(pause); Assert.IsTrue(serviceClient.SnappedSamples.Count > 0); Assert.IsTrue(serviceClient.SnappedSamples.Any(s => s.AIRequestsPerSecond > 0)); Assert.IsTrue(serviceClient.SnappedSamples.Any(s => s.AIDependencyCallsPerSecond > 0)); Assert.IsTrue( serviceClient.SnappedSamples.Any( s => Math.Abs(s.PerfCountersLookup[@"\Processor(_Total)\% Processor Time"]) > double.Epsilon)); }
public void QuickPulseTelemetryModuleDisposesCorrectly() { // ARRANGE var interval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(interval, interval, interval, interval, interval, interval); var collectionTimeSlotManager = new QuickPulseCollectionTimeSlotManagerMock(timings); var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = true, ReturnValueFromSubmitSample = true }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule( collectionTimeSlotManager, null, serviceClient, performanceCollector, timings); module.Initialize(new TelemetryConfiguration() { InstrumentationKey = "some ikey" }); // ACT Thread.Sleep(TimeSpan.FromMilliseconds(100)); // ASSERT module.Dispose(); }
public QuickPulseCollectionTimeSlotManagerMock(QuickPulseTimings timings) { this.interval = timings.CollectionInterval; }
private static QuickPulseCollectionStateManager CreateManager( IQuickPulseServiceClient serviceClient, Clock timeProvider, List<string> actions, List<QuickPulseDataSample> returnedSamples = null, QuickPulseTimings timings = null) { var manager = new QuickPulseCollectionStateManager( serviceClient, timeProvider, timings ?? QuickPulseTimings.Default, () => actions.Add(StartCollectionMessage), () => actions.Add(StopCollectionMessage), () => { actions.Add(CollectMessage); var now = DateTimeOffset.UtcNow; return new[] { new QuickPulseDataSample( new QuickPulseDataAccumulator { AIRequestSuccessCount = 5, StartTimestamp = now, EndTimestamp = now.AddSeconds(1) }, new Dictionary<string, Tuple<PerformanceCounterData, double>>()) }.ToList(); }, samples => { if (returnedSamples != null) { returnedSamples.AddRange(samples); } }); return manager; }
/// <summary> /// Initialize method is called after all configuration properties have been loaded from the configuration. /// </summary> /// <param name="configuration">TelemetryConfiguration passed to the module.</param> public void Initialize(TelemetryConfiguration configuration) { if (!this.isInitialized) { lock (this.lockObject) { if (!this.isInitialized) { QuickPulseEventSource.Log.ModuleIsBeingInitializedEvent( string.Format( CultureInfo.InvariantCulture, "QuickPulseServiceEndpoint: '{0}', DisableFullTelemetryItems: '{1}'", this.QuickPulseServiceEndpoint, this.DisableFullTelemetryItems)); QuickPulseEventSource.Log.TroubleshootingMessageEvent("Validating configuration..."); this.ValidateConfiguration(configuration); this.config = configuration; QuickPulseEventSource.Log.TroubleshootingMessageEvent("Initializing members..."); this.collectionTimeSlotManager = this.collectionTimeSlotManager ?? new QuickPulseCollectionTimeSlotManager(); this.dataAccumulatorManager = this.dataAccumulatorManager ?? new QuickPulseDataAccumulatorManager(); this.performanceCollector = this.performanceCollector ?? (PerformanceCounterUtility.IsWebAppRunningInAzure() ? (IPerformanceCollector)new WebAppPerformanceCollector() : (IPerformanceCollector)new StandardPerformanceCollector()); this.timeProvider = this.timeProvider ?? new Clock(); this.timings = timings ?? QuickPulseTimings.Default; this.InitializeServiceClient(configuration); this.stateManager = new QuickPulseCollectionStateManager( this.serviceClient, this.timeProvider, this.timings, this.OnStartCollection, this.OnStopCollection, this.OnSubmitSamples, this.OnReturnFailedSamples); this.CreateStateThread(); this.isInitialized = true; } } } }
public void QuickPulseTelemetryModuleDoesNothingWithoutInstrumentationKey() { // ARRANGE var interval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(interval, interval); var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = true, ReturnValueFromSubmitSample = true }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule(null, null, serviceClient, performanceCollector, timings); module.Initialize(new TelemetryConfiguration()); // ACT Thread.Sleep(TimeSpan.FromMilliseconds(100)); // ASSERT Assert.AreEqual(0, serviceClient.PingCount); Assert.AreEqual(0, serviceClient.SnappedSamples.Count); }
public void QuickPulseTelemetryModuleTimestampsDataSamples() { // ARRANGE var interval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(interval, interval); var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = true, ReturnValueFromSubmitSample = true }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule(null, null, serviceClient, performanceCollector, timings); var timestampStart = DateTimeOffset.UtcNow; // ACT module.Initialize(new TelemetryConfiguration()); Thread.Sleep((int)(interval.TotalMilliseconds * 100)); // ASSERT var timestampEnd = DateTimeOffset.UtcNow; Assert.IsTrue(serviceClient.SnappedSamples.All(s => s.StartTimestamp > timestampStart)); Assert.IsTrue(serviceClient.SnappedSamples.All(s => s.StartTimestamp < timestampEnd)); Assert.IsTrue(serviceClient.SnappedSamples.All(s => s.StartTimestamp <= s.EndTimestamp)); }
public void QuickPulseTelemetryModuleSupportsMultipleTelemetryProcessorsForMultipleConfigurations() { // ARRANGE var pollingInterval = TimeSpan.FromMilliseconds(1); var collectionInterval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(pollingInterval, collectionInterval); var collectionTimeSlotManager = new QuickPulseCollectionTimeSlotManagerMock(timings); var accumulatorManager = new QuickPulseDataAccumulatorManager(); var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = true, ReturnValueFromSubmitSample = true }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule(collectionTimeSlotManager, accumulatorManager, serviceClient, performanceCollector, timings); const int TelemetryProcessorCount = 4; var ikey = "some ikey"; var config = new TelemetryConfiguration { InstrumentationKey = ikey }; // spawn a bunch of configurations, each one having an individual instance of QuickPulseTelemetryProcessor var telemetryProcessors = new List<QuickPulseTelemetryProcessor>(); for (int i = 0; i < TelemetryProcessorCount; i++) { var configuration = new TelemetryConfiguration(); var builder = configuration.TelemetryProcessorChainBuilder; builder = builder.Use(current => new QuickPulseTelemetryProcessor(new SimpleTelemetryProcessorSpy())); builder.Build(); telemetryProcessors.Add(configuration.TelemetryProcessors.OfType<QuickPulseTelemetryProcessor>().Single()); } // ACT foreach (var telemetryProcessor in telemetryProcessors) { module.RegisterTelemetryProcessor(telemetryProcessor); } module.Initialize(config); Thread.Sleep(TimeSpan.FromMilliseconds(100)); // send data to each instance of QuickPulseTelemetryProcessor var request = new RequestTelemetry() { ResponseCode = "200", Success = true, Context = { InstrumentationKey = ikey } }; telemetryProcessors[0].Process(request); request = new RequestTelemetry() { ResponseCode = "500", Success = false, Context = { InstrumentationKey = ikey } }; telemetryProcessors[1].Process(request); var dependency = new DependencyTelemetry() { Success = true, Context = { InstrumentationKey = ikey } }; telemetryProcessors[2].Process(dependency); dependency = new DependencyTelemetry() { Success = false, Context = { InstrumentationKey = ikey } }; telemetryProcessors[3].Process(dependency); Thread.Sleep(TimeSpan.FromMilliseconds(100)); // ASSERT // verify that every telemetry processor has contributed to the accumulator int samplesWithSomeRequests = serviceClient.SnappedSamples.Count(s => s.AIRequestsPerSecond > 0); int samplesWithSomeDependencies = serviceClient.SnappedSamples.Count(s => s.AIDependencyCallsPerSecond > 0); Assert.AreEqual(TelemetryProcessorCount, QuickPulseTestHelper.GetTelemetryProcessors(module).Count); Assert.IsTrue(samplesWithSomeRequests > 0 && samplesWithSomeRequests <= 2); Assert.AreEqual(1, serviceClient.SnappedSamples.Count(s => s.AIRequestsFailedPerSecond > 0)); Assert.IsTrue(samplesWithSomeDependencies > 0 && samplesWithSomeDependencies < 2); Assert.AreEqual(1, serviceClient.SnappedSamples.Count(s => s.AIDependencyCallsFailedPerSecond > 0)); }
public void QuickPulseTelemetryModuleResendsFailedSamples() { // ARRANGE var interval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(interval, interval); var collectionTimeSlotManager = new QuickPulseCollectionTimeSlotManagerMock(timings); var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = true, ReturnValueFromSubmitSample = null }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule( collectionTimeSlotManager, null, serviceClient, performanceCollector, timings); module.Initialize(new TelemetryConfiguration() { InstrumentationKey = "some ikey" }); // ACT // below timeout should be sufficient for the module to get to the maximum storage capacity Thread.Sleep(TimeSpan.FromMilliseconds(300)); // ASSERT Assert.AreEqual(10, serviceClient.LastSampleBatchSize); }
public void QuickPulseTelemetryModulePingsService() { // ARRANGE var interval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(interval, interval); var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = false, ReturnValueFromSubmitSample = false }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule( null, null, serviceClient, performanceCollector, timings); // ACT module.Initialize(new TelemetryConfiguration() { InstrumentationKey = "some ikey" }); // ASSERT Thread.Sleep((int)(interval.TotalMilliseconds * 100)); Assert.IsTrue(serviceClient.PingCount > 0); Assert.AreEqual(0, serviceClient.SnappedSamples.Count); }
public void QuickPulseTelemetryModulePicksUpInstrumentationKeyAsItGoes() { // ARRANGE var interval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(interval, interval); var collectionTimeSlotManager = new QuickPulseCollectionTimeSlotManagerMock(timings); var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = true, ReturnValueFromSubmitSample = true }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule( collectionTimeSlotManager, null, serviceClient, performanceCollector, timings); var config = new TelemetryConfiguration(); module.Initialize(config); // ACT Thread.Sleep(TimeSpan.FromMilliseconds(100)); config.InstrumentationKey = "some ikey"; Thread.Sleep(TimeSpan.FromMilliseconds(100)); // ASSERT Assert.IsTrue(serviceClient.PingCount > 0); Assert.IsTrue(serviceClient.SnappedSamples.Count > 0); }
public void QuickPulseTelemetryModuleOnlyInitializesPerformanceCollectorAfterCollectionStarts() { // ARRANGE var interval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(interval, interval); var collectionTimeSlotManager = new QuickPulseCollectionTimeSlotManagerMock(timings); var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = false, ReturnValueFromSubmitSample = false }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule(collectionTimeSlotManager, null, serviceClient, performanceCollector, timings); // ACT & ASSERT module.Initialize(new TelemetryConfiguration() { InstrumentationKey = "some ikey" }); Thread.Sleep((int)(interval.TotalMilliseconds * 100)); Assert.IsFalse(performanceCollector.PerformanceCounters.Any()); serviceClient.ReturnValueFromPing = true; Thread.Sleep((int)(interval.TotalMilliseconds * 100)); Assert.IsTrue(performanceCollector.PerformanceCounters.Any()); Assert.IsTrue(serviceClient.SnappedSamples.All(s => Math.Abs(s.PerfCountersLookup[@"\Processor(_Total)\% Processor Time"]) > double.Epsilon)); }
public void QuickPulseTelemetryModuleManagesTimersCorrectly() { // ARRANGE var pollingInterval = TimeSpan.FromMilliseconds(200); var collectionInterval = TimeSpan.FromMilliseconds(80); var timings = new QuickPulseTimings(pollingInterval, collectionInterval); var collectionTimeSlotManager = new QuickPulseCollectionTimeSlotManagerMock(timings); var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = false, ReturnValueFromSubmitSample = true }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule( collectionTimeSlotManager, null, serviceClient, performanceCollector, timings); // ACT & ASSERT module.Initialize(new TelemetryConfiguration() { InstrumentationKey = "some ikey" }); // initially, the module is in the polling state Thread.Sleep((int)(2.5 * pollingInterval.TotalMilliseconds)); serviceClient.CountersEnabled = false; // 2.5 polling intervals have elapsed, we must have pinged the service 3 times (the first time immediately upon initialization), but no samples yet Assert.AreEqual(3, serviceClient.PingCount, "Ping count 1"); Assert.AreEqual(0, serviceClient.SnappedSamples.Count, "Sample count 1"); // now the service wants the data serviceClient.Reset(); serviceClient.ReturnValueFromPing = true; serviceClient.ReturnValueFromSubmitSample = true; serviceClient.CountersEnabled = true; Thread.Sleep((int)(5 * collectionInterval.TotalMilliseconds)); serviceClient.CountersEnabled = false; // a number of collection intervals have elapsed, we must have pinged the service once, and then started sending samples Assert.AreEqual(1, serviceClient.PingCount, "Ping count 2"); Assert.IsTrue(serviceClient.SnappedSamples.Count > 0, "Sample count 2"); lock (serviceClient.ResponseLock) { // the service doesn't want the data anymore serviceClient.ReturnValueFromPing = false; serviceClient.ReturnValueFromSubmitSample = false; serviceClient.Reset(); serviceClient.CountersEnabled = true; } Thread.Sleep((int)(2.9 * pollingInterval.TotalMilliseconds)); serviceClient.CountersEnabled = false; // 2 polling intervals have elapsed, we must have submitted one batch of samples, stopped collecting and pinged the service twice afterwards Assert.AreEqual(1, serviceClient.SnappedSamples.Count / serviceClient.LastSampleBatchSize, "Sample count 3"); Assert.AreEqual(2, serviceClient.PingCount, "Ping count 3"); }
public void QuickPulseTelemetryModuleHandlesUnexpectedExceptions() { // ARRANGE var interval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(interval, interval, interval, interval, interval, interval); var collectionTimeSlotManager = new QuickPulseCollectionTimeSlotManagerMock(timings); var serviceClient = new QuickPulseServiceClientMock { AlwaysThrow = true, ReturnValueFromPing = false, ReturnValueFromSubmitSample = null }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule( collectionTimeSlotManager, null, serviceClient, performanceCollector, timings); module.Initialize(new TelemetryConfiguration() { InstrumentationKey = "some ikey" }); // ACT Thread.Sleep(TimeSpan.FromMilliseconds(100)); // ASSERT // it shouldn't throw and must keep pinging Assert.IsTrue(serviceClient.PingCount > 5); }
public void QuickPulseTelemetryModuleDoesNotLeakThreads() { // ARRANGE var interval = TimeSpan.FromMilliseconds(1); var timings = new QuickPulseTimings(interval, interval, interval, interval, interval, interval); var collectionTimeSlotManager = new QuickPulseCollectionTimeSlotManagerMock(timings); // this will flip-flop between collection and no collection, creating and ending a collection thread each time var serviceClient = new QuickPulseServiceClientMock { ReturnValueFromPing = true, ReturnValueFromSubmitSample = false }; var performanceCollector = new PerformanceCollectorMock(); var module = new QuickPulseTelemetryModule( collectionTimeSlotManager, null, serviceClient, performanceCollector, timings); module.Initialize(new TelemetryConfiguration() { InstrumentationKey = "some ikey" }); int initialThreadCount = Process.GetCurrentProcess().Threads.Count; // ACT Thread.Sleep(TimeSpan.FromMilliseconds(300)); // ASSERT // we don't expect to find many more threads, even though other components might be spinning new ones up and down var threadDelta = Process.GetCurrentProcess().Threads.Count - initialThreadCount; Assert.IsTrue(Math.Abs(threadDelta) < 5, threadDelta.ToString(CultureInfo.InvariantCulture)); }