public void DoubleObserverSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = Sdk.CreateMeterProviderBuilder() .SetProcessor(testProcessor) .Build() .GetMeter("library1") as MeterSdk; var testObserver = meter.CreateDoubleObserver("testObserver", this.TestCallbackDouble); meter.Collect(); Assert.Single(testProcessor.Metrics); var metric = testProcessor.Metrics[0]; Assert.Equal("testObserver", metric.MetricName); Assert.Equal("library1", metric.MetricNamespace); // 2 time series, as 2 unique label sets. Assert.Equal(2, metric.Data.Count); var metricSeries = metric.Data.Single(data => data.Labels.Any(l => l.Key == "dim1" && l.Value == "value1")); var metricLong = metricSeries as DoubleSumData; Assert.Equal(30.5, metricLong.Sum); metricSeries = metric.Data.Single(data => data.Labels.Any(l => l.Key == "dim1" && l.Value == "value2")); metricLong = metricSeries as DoubleSumData; Assert.Equal(300.5, metricLong.Sum); }
public void DefaultMeterShouldBeCollectedAsWell() { var testProcessor = new TestMetricProcessor(); var meterProvider = Sdk.CreateMeterProviderBuilder() .SetProcessor(testProcessor) .Build() as MeterProviderSdk; var controller = meterProvider.PushMetricController; var defaultMeter = meterProvider.GetMeter(string.Empty) as MeterSdk; // Record some metrics using default meter var testCounter = defaultMeter.CreateInt64Counter("testCounter"); var context = default(SpanContext); var labels = LabelSet.BlankLabelSet; testCounter.Add(context, 100, labels); testCounter.Add(context, 10, labels); // Collect using PushMetricController var sw = Stopwatch.StartNew(); var metricToExport = controller.Collect(sw).ToList(); Assert.Single(metricToExport); Assert.Single(metricToExport[0].Data); Assert.Equal(110, (metricToExport[0].Data[0] as Int64SumData).Sum); }
public void CounterSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = Sdk.CreateMeterProviderBuilder() .SetProcessor(testProcessor) .Build() .GetMeter("library1") as MeterSdk; var testCounter = meter.CreateInt64Counter("testCounter"); var labels1 = new List <KeyValuePair <string, string> >(); labels1.Add(new KeyValuePair <string, string>("dim1", "value1")); var labels2 = new List <KeyValuePair <string, string> >(); labels2.Add(new KeyValuePair <string, string>("dim1", "value2")); var labels3 = new List <KeyValuePair <string, string> >(); labels3.Add(new KeyValuePair <string, string>("dim1", "value3")); var context = default(SpanContext); testCounter.Add(context, 100, meter.GetLabelSet(labels1)); testCounter.Add(context, 10, meter.GetLabelSet(labels1)); var boundCounterLabel2 = testCounter.Bind(labels2); boundCounterLabel2.Add(context, 200); testCounter.Add(context, 200, meter.GetLabelSet(labels3)); testCounter.Add(context, 10, meter.GetLabelSet(labels3)); meter.Collect(); Assert.Single(testProcessor.Metrics); var metric = testProcessor.Metrics[0]; Assert.Equal("testCounter", metric.MetricName); Assert.Equal("library1", metric.MetricNamespace); // 3 time series, as 3 unique label sets. Assert.Equal(3, metric.Data.Count); var metricSeries = metric.Data.Single(data => data.Labels.Any(l => l.Key == "dim1" && l.Value == "value1")); var metricLong = metricSeries as Int64SumData; Assert.Equal(110, metricLong.Sum); metricSeries = metric.Data.Single(data => data.Labels.Any(l => l.Key == "dim1" && l.Value == "value2")); metricLong = metricSeries as Int64SumData; Assert.Equal(200, metricLong.Sum); metricSeries = metric.Data.Single(data => data.Labels.Any(l => l.Key == "dim1" && l.Value == "value3")); metricLong = metricSeries as Int64SumData; Assert.Equal(210, metricLong.Sum); }
public void MeasureSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = Sdk.CreateMeterProviderBuilder() .SetProcessor(testProcessor) .Build() .GetMeter("library1") as MeterSdk; var testMeasure = meter.CreateInt64Measure("testMeasure"); var labels1 = new List <KeyValuePair <string, string> >(); labels1.Add(new KeyValuePair <string, string>("dim1", "value1")); var labels2 = new List <KeyValuePair <string, string> >(); labels2.Add(new KeyValuePair <string, string>("dim1", "value2")); var context = default(SpanContext); testMeasure.Record(context, 100, meter.GetLabelSet(labels1)); testMeasure.Record(context, 10, meter.GetLabelSet(labels1)); testMeasure.Record(context, 1, meter.GetLabelSet(labels1)); testMeasure.Record(context, 200, meter.GetLabelSet(labels2)); testMeasure.Record(context, 20, meter.GetLabelSet(labels2)); meter.Collect(); Assert.Single(testProcessor.Metrics); var metric = testProcessor.Metrics[0]; Assert.Equal("testMeasure", metric.MetricName); Assert.Equal("library1", metric.MetricNamespace); // 2 time series, as 2 unique label sets. Assert.Equal(2, metric.Data.Count); var metricSeries = metric.Data.Single(data => data.Labels.Any(l => l.Key == "dim1" && l.Value == "value1")); var metricSummary = metricSeries as Int64SummaryData; Assert.Equal(111, metricSummary.Sum); Assert.Equal(3, metricSummary.Count); Assert.Equal(1, metricSummary.Min); Assert.Equal(100, metricSummary.Max); metricSeries = metric.Data.Single(data => data.Labels.Any(l => l.Key == "dim1" && l.Value == "value2")); metricSummary = metricSeries as Int64SummaryData; Assert.Equal(220, metricSummary.Sum); Assert.Equal(2, metricSummary.Count); Assert.Equal(20, metricSummary.Min); Assert.Equal(200, metricSummary.Max); }
public void PushControllerCollectsAllMeters() { // Setup controller to collect every 25 msec. var controllerPushIntervalInMsec = 25; var collectionCountExpectedMin = 3; var maxWaitInMsec = (controllerPushIntervalInMsec * collectionCountExpectedMin) + 2000; int exportCalledCount = 0; var testExporter = new TestMetricExporter(() => exportCalledCount++); var testProcessor = new TestMetricProcessor(); // Setup 2 meters whose Collect will increment the collect count. int meter1CollectCount = 0; int meter2CollectCount = 0; var meters = new Dictionary <MeterRegistryKey, MeterSdk>(); var testMeter1 = new TestMeter("meter1", testProcessor, () => meter1CollectCount++); meters.Add(new MeterRegistryKey("meter1", string.Empty), testMeter1); var testMeter2 = new TestMeter("meter2", testProcessor, () => meter2CollectCount++); meters.Add(new MeterRegistryKey("meter2", string.Empty), testMeter2); var pushInterval = TimeSpan.FromMilliseconds(controllerPushIntervalInMsec); var pushController = new PushMetricController( meters, testProcessor, testExporter, pushInterval, new CancellationTokenSource()); // Validate that collect is called on Meter1, Meter2. this.ValidateMeterCollect(ref meter1CollectCount, collectionCountExpectedMin, "meter1", TimeSpan.FromMilliseconds(maxWaitInMsec)); this.ValidateMeterCollect(ref meter2CollectCount, collectionCountExpectedMin, "meter2", TimeSpan.FromMilliseconds(maxWaitInMsec)); // Export must be called same no: of times as Collect. Assert.True(exportCalledCount >= collectionCountExpectedMin); }
public void LongCounterBoundInstrumentsStatusUpdatedCorrectlySingleThread() { var testProcessor = new TestMetricProcessor(); var meter = Sdk.CreateMeterProviderBuilder() .SetProcessor(testProcessor) .Build() .GetMeter("library1") as MeterSdk; var testCounter = meter.CreateInt64Counter("testCounter") as CounterMetricSdkBase <long>; var labels1 = new List <KeyValuePair <string, string> >(); labels1.Add(new KeyValuePair <string, string>("dim1", "value1")); var ls1 = meter.GetLabelSet(labels1); var labels2 = new List <KeyValuePair <string, string> >(); labels2.Add(new KeyValuePair <string, string>("dim1", "value2")); var ls2 = meter.GetLabelSet(labels2); var labels3 = new List <KeyValuePair <string, string> >(); labels3.Add(new KeyValuePair <string, string>("dim1", "value3")); var ls3 = meter.GetLabelSet(labels3); var context = default(SpanContext); // We have ls1, ls2, ls3 // ls1 and ls3 are not bound so they should removed when no usage for a Collect cycle. // ls2 is bound by user. testCounter.Add(context, 100, ls1); testCounter.Add(context, 10, ls1); // initial status for temp bound instruments are UpdatePending. Assert.Equal(RecordStatus.UpdatePending, testCounter.GetAllBoundInstruments()[ls1].Status); var boundCounterLabel2 = testCounter.Bind(ls2); boundCounterLabel2.Add(context, 200); // initial/forever status for user bound instruments are Bound. Assert.Equal(RecordStatus.Bound, testCounter.GetAllBoundInstruments()[ls2].Status); testCounter.Add(context, 200, ls3); testCounter.Add(context, 10, ls3); // initial status for temp bound instruments are UpdatePending. Assert.Equal(RecordStatus.UpdatePending, testCounter.GetAllBoundInstruments()[ls3].Status); // This collect should mark ls1, ls3 as NoPendingUpdate, leave ls2 untouched. meter.Collect(); // Validate collect() has marked records correctly. Assert.Equal(RecordStatus.NoPendingUpdate, testCounter.GetAllBoundInstruments()[ls1].Status); Assert.Equal(RecordStatus.NoPendingUpdate, testCounter.GetAllBoundInstruments()[ls3].Status); Assert.Equal(RecordStatus.Bound, testCounter.GetAllBoundInstruments()[ls2].Status); // Use ls1 again, so that it'll be promoted to UpdatePending testCounter.Add(context, 100, ls1); // This collect should mark ls1 as NoPendingUpdate, leave ls2 untouched. // And ls3 as CandidateForRemoval, as it was not used since last Collect meter.Collect(); // Validate collect() has marked records correctly. Assert.Equal(RecordStatus.NoPendingUpdate, testCounter.GetAllBoundInstruments()[ls1].Status); Assert.Equal(RecordStatus.CandidateForRemoval, testCounter.GetAllBoundInstruments()[ls3].Status); Assert.Equal(RecordStatus.Bound, testCounter.GetAllBoundInstruments()[ls2].Status); // This collect should mark // ls1 as CandidateForRemoval as it was not used since last Collect // leave ls2 untouched. // ls3 should be physically removed as it remained CandidateForRemoval during an entire Collect cycle. meter.Collect(); Assert.Equal(RecordStatus.CandidateForRemoval, testCounter.GetAllBoundInstruments()[ls1].Status); Assert.Equal(RecordStatus.Bound, testCounter.GetAllBoundInstruments()[ls2].Status); Assert.False(testCounter.GetAllBoundInstruments().ContainsKey(ls3)); }
public void DoubleCounterBoundInstrumentsStatusUpdatedCorrectlyMultiThread() { var testProcessor = new TestMetricProcessor(); var meter = Sdk.CreateMeterProviderBuilder() .SetProcessor(testProcessor) .Build() .GetMeter("library1") as MeterSdk; var testCounter = meter.CreateDoubleCounter("testCounter") as CounterMetricSdkBase <double>; var labels1 = new List <KeyValuePair <string, string> >(); labels1.Add(new KeyValuePair <string, string>("dim1", "value1")); var ls1 = meter.GetLabelSet(labels1); var context = default(SpanContext); // Call metric update with ls1 so that ls1 wont be brand new labelset when doing multi-thread test. testCounter.Add(context, 100.0, ls1); testCounter.Add(context, 10.0, ls1); // This collect should mark ls1 NoPendingUpdate meter.Collect(); // Validate collect() has marked records correctly. Assert.Equal(RecordStatus.NoPendingUpdate, testCounter.GetAllBoundInstruments()[ls1].Status); // Another collect(). This collect should mark ls1 as CandidateForRemoval. meter.Collect(); Assert.Equal(RecordStatus.CandidateForRemoval, testCounter.GetAllBoundInstruments()[ls1].Status); // Call Collect() and update with ls1 parallelly to validate no update is lost, as ls1 is marked // candidate for removal after above step. var mre = new ManualResetEvent(false); var argsForMeterCollect = new ArgsToThread(); argsForMeterCollect.MreToBlockStartOfThread = mre; argsForMeterCollect.Callback = () => meter.Collect(); var argsForCounterAdd = new ArgsToThread(); argsForCounterAdd.MreToBlockStartOfThread = mre; argsForCounterAdd.Callback = () => testCounter.Add(context, 100.0, ls1); var collectThread = new Thread(ThreadMethod); var updateThread = new Thread(ThreadMethod); collectThread.Start(argsForMeterCollect); updateThread.Start(argsForCounterAdd); // Attempt to start both threads. // TODO: // Instead of this, evaluate if a different testing approach is needed. // One or more thread doing Updates in parallel. // One thread doing occasional Collect. // At the end, validate that no metric update is lost. mre.Set(); collectThread.Join(); updateThread.Join(); // Validate that the exported record doesn't miss any update. // The Add(100) value must have already been exported, or must be exported in the next Collect(). meter.Collect(); double sum = 0; foreach (var exportedData in testProcessor.Metrics) { exportedData.Data.ForEach(data => sum += (data as DoubleSumData).Sum); } // 210 = 110 from initial update, 100 from the multi-thread test case. Assert.Equal(210.0, sum); }