public void MeasureSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = MeterFactory.Create(testProcessor).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")); testMeasure.Record(SpanContext.BlankLocal, 100, meter.GetLabelSet(labels1)); testMeasure.Record(SpanContext.BlankLocal, 10, meter.GetLabelSet(labels1)); testMeasure.Record(SpanContext.BlankLocal, 200, meter.GetLabelSet(labels2)); testMeasure.Record(SpanContext.BlankLocal, 20, meter.GetLabelSet(labels2)); meter.Collect(); Assert.Equal(2, testProcessor.measures.Count); Assert.Equal("testMeasure", testProcessor.measures[1].Item1); Assert.Equal("testMeasure", testProcessor.measures[0].Item1); Assert.Equal(meter.GetLabelSet(labels1), testProcessor.measures[1].Item2); Assert.Equal(meter.GetLabelSet(labels2), testProcessor.measures[0].Item2); Assert.Contains(100, testProcessor.measures[1].Item3); Assert.Contains(10, testProcessor.measures[1].Item3); Assert.Contains(200, testProcessor.measures[0].Item3); Assert.Contains(20, testProcessor.measures[0].Item3); }
private static void CollectMetrics(UngroupedBatcher simpleProcessor) { var meter = MeterFactory.Create(simpleProcessor).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 defaultContext = default(SpanContext); for (int i = 0; i < 1000; i++) { testCounter.Add(defaultContext, 100, meter.GetLabelSet(labels1)); testCounter.Add(defaultContext, 10, meter.GetLabelSet(labels1)); testCounter.Add(defaultContext, 200, meter.GetLabelSet(labels2)); testCounter.Add(defaultContext, 10, meter.GetLabelSet(labels2)); if (i % 10 == 0) { meter.Collect(); } } }
public void ObserverSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = MeterFactory.Create(testProcessor).GetMeter("library1") as MeterSdk; var testObserver = meter.CreateInt64Observer("testObserver"); 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); testObserver.Observe(context, 100, meter.GetLabelSet(labels1)); testObserver.Observe(context, 10, meter.GetLabelSet(labels1)); testObserver.Observe(context, 200, meter.GetLabelSet(labels2)); testObserver.Observe(context, 20, meter.GetLabelSet(labels2)); meter.Collect(); Assert.Equal(2, testProcessor.longMetrics.Count); Assert.Equal(2, testProcessor.longMetrics.Count(m => m.MetricName == "testObserver")); Assert.Single(testProcessor.longMetrics.Where(m => (m.Data as SumData <long>).Sum == 10)); Assert.Single(testProcessor.longMetrics.Where(m => (m.Data as SumData <long>).Sum == 20)); }
public void GaugeSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = MeterFactory.Create(testProcessor).GetMeter("library1") as MeterSdk; var testGauge = meter.CreateInt64Gauge("testGauge"); 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); testGauge.Set(context, 100, meter.GetLabelSet(labels1)); testGauge.Set(context, 10, meter.GetLabelSet(labels1)); testGauge.Set(context, 200, meter.GetLabelSet(labels2)); testGauge.Set(context, 20, meter.GetLabelSet(labels2)); meter.Collect(); Assert.Equal(2, testProcessor.gauges.Count); Assert.Equal("testGauge", testProcessor.gauges[1].Item1); Assert.Equal("testGauge", testProcessor.gauges[0].Item1); Assert.Equal(meter.GetLabelSet(labels1), testProcessor.gauges[1].Item2); Assert.Equal(meter.GetLabelSet(labels2), testProcessor.gauges[0].Item2); Assert.Equal(10, testProcessor.gauges[1].Item3.Item1); Assert.Equal(20, testProcessor.gauges[0].Item3.Item1); }
public void DoubleObserverSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = MeterFactory.Create(mb => mb.SetMetricProcessor(testProcessor)).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 MeasureSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = MeterFactory.Create(testProcessor).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, 200, meter.GetLabelSet(labels2)); testMeasure.Record(context, 20, meter.GetLabelSet(labels2)); meter.Collect(); Assert.Equal(2, testProcessor.measures.Count); Assert.Equal(2, testProcessor.measures.Count(kvp => kvp.Item1 == "testMeasure")); Assert.Single(testProcessor.measures.Where(kvp => kvp.Item2.Equals(meter.GetLabelSet(labels1)))); Assert.Single(testProcessor.measures.Where(kvp => kvp.Item2.Equals(meter.GetLabelSet(labels2)))); Assert.Single(testProcessor.measures.Where(kvp => kvp.Item3.Contains(100) && kvp.Item3.Contains(10))); Assert.Single(testProcessor.measures.Where(kvp => kvp.Item3.Contains(200) && kvp.Item3.Contains(20))); }
public void CounterSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = MeterFactory.Create(mb => mb.SetMetricProcessor(testProcessor)).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); }
internal static object Run() { var promOptions = new PrometheusExporterOptions() { Url = "http://localhost:9184/metrics/" }; var promExporter = new PrometheusExporter(promOptions); var simpleProcessor = new UngroupedBatcher(promExporter, TimeSpan.FromSeconds(5)); var meter = MeterFactory.Create(simpleProcessor).GetMeter("library1"); 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 httpServer = new PrometheusExporterMetricsHttpServer(promExporter); var defaultContext = default(SpanContext); try { httpServer.Start(); for (int i = 0; i < 1000; i++) { testCounter.Add(defaultContext, 100, meter.GetLabelSet(labels1)); testCounter.Add(defaultContext, 10, meter.GetLabelSet(labels1)); testCounter.Add(defaultContext, 200, meter.GetLabelSet(labels2)); testCounter.Add(defaultContext, 10, meter.GetLabelSet(labels2)); if (i % 10 == 0) { // Collect is called here explicitly as there is // no controller implementation yet. // TODO: There should be no need to cast to MeterSdk. (meter as MeterSdk).Collect(); } Task.Delay(1000).Wait(); } } finally { Task.Delay(3000).Wait(); httpServer.Stop(); } return(null); }
public void DoubleObserverSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = MeterFactory.Create(testProcessor).GetMeter("library1") as MeterSdk; var testObserver = meter.CreateDoubleObserver("testObserver", TestCallbackDouble); meter.Collect(); Assert.Equal(2, testProcessor.doubleMetrics.Count); Assert.Equal(2, testProcessor.doubleMetrics.Count(m => m.MetricName == "testObserver")); Assert.Single(testProcessor.doubleMetrics.Where(m => (m.Data as SumData <double>).Sum == 30.5)); Assert.Single(testProcessor.doubleMetrics.Where(m => (m.Data as SumData <double>).Sum == 300.5)); }
public void E2ETest1() { var promOptions = new PrometheusExporterOptions() { Url = "http://localhost:9184/metrics/" }; var promExporter = new PrometheusExporter(promOptions); var simpleProcessor = new UngroupedBatcher(promExporter); var meter = MeterFactory.Create(simpleProcessor).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 metricsHttpServer = new PrometheusExporterMetricsHttpServer(promExporter); try { metricsHttpServer.Start(); var defaultContext = default(SpanContext); for (int i = 0; i < 1000; i++) { testCounter.Add(defaultContext, 100, meter.GetLabelSet(labels1)); testCounter.Add(defaultContext, 10, meter.GetLabelSet(labels1)); testCounter.Add(defaultContext, 200, meter.GetLabelSet(labels2)); testCounter.Add(defaultContext, 10, meter.GetLabelSet(labels2)); if (i % 10 == 0) { meter.Collect(); } // Change delay to higher value to manually check Promtheus. // These tests are just to temporarily validate export to prometheus. // Task.Delay(100).Wait(); } } finally { Task.Delay(100).Wait(); metricsHttpServer.Stop(); } }
public void MeasureSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = MeterFactory.Create(mb => mb.SetMetricProcessor(testProcessor)).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 MeterFactory_UpdateDefault_CachedTracer() { var defaultMeter = MeterFactoryBase.Default.GetMeter(string.Empty); var noOpCounter = defaultMeter.CreateDoubleCounter("ctr"); Assert.IsType <NoOpCounterMetric <double> >(noOpCounter); MeterFactoryBase.SetDefault(MeterFactory.Create(b => { })); var counter = defaultMeter.CreateDoubleCounter("ctr"); Assert.IsType <DoubleCounterMetricSdk>(counter); var newdefaultMeter = MeterFactoryBase.Default.GetMeter(string.Empty); Assert.NotSame(defaultMeter, newdefaultMeter); Assert.IsType <MeterSdk>(newdefaultMeter); }
public void MeterFactory_SetDefault() { var factory = MeterFactory.Create(b => { }); MeterFactoryBase.SetDefault(factory); var defaultMeter = MeterFactoryBase.Default.GetMeter(string.Empty); Assert.NotNull(defaultMeter); Assert.IsType <MeterSdk>(defaultMeter); Assert.NotSame(defaultMeter, MeterFactoryBase.Default.GetMeter("named meter")); var counter = defaultMeter.CreateDoubleCounter("ctr"); Assert.IsType <DoubleCounterMetricSdk>(counter); }
/// <summary>add MagicOnion Telemetry.</summary> public static IServiceCollection AddMagicOnionOpenTelemetry(this IServiceCollection services, MagicOnionOpenTelemetryOptions options, Action <MagicOnionOpenTelemetryOptions, MagicOnionOpenTelemetryMeterFactoryOption> configureMeterFactory, Action <MagicOnionOpenTelemetryOptions, TracerBuilder> configureTracerFactory) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (string.IsNullOrEmpty(options.ServiceName)) { throw new ArgumentNullException($"{nameof(options)}.{nameof(options.ServiceName)}"); } services.AddSingleton(options); // configure MeterFactory if (configureMeterFactory != null) { var meterFactoryOption = new MagicOnionOpenTelemetryMeterFactoryOption(); configureMeterFactory(options, meterFactoryOption); var meterFactory = MeterFactory.Create(mb => { mb.SetMetricProcessor(meterFactoryOption.MetricProcessor); mb.SetMetricExporter(meterFactoryOption.MetricExporter); mb.SetMetricPushInterval(meterFactoryOption.MetricPushInterval); }); services.AddSingleton(meterFactoryOption.MetricExporter); services.AddSingleton(meterFactory); } // configure TracerFactory if (configureTracerFactory != null) { var tracerFactory = TracerFactory.Create(tracerBuilder => configureTracerFactory(options, tracerBuilder)); services.AddSingleton(tracerFactory); } return(services); }
public Task StartAsync(CancellationToken cancellationToken) { var interval = TimeSpan.FromSeconds(5); var simpleProcessor = new UngroupedBatcher(exporter, interval); this.meterFactory = MeterFactory.Create(simpleProcessor); foreach (var initializer in initializers) { initializer.Initialize(meterFactory); } this.timer = new Timer(CollectMetrics, meterFactory, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); exporter.Start(); this.timer.Change(interval, interval); return(Task.CompletedTask); }
private static void CollectMetrics(UngroupedBatcher simpleProcessor, MetricExporter exporter) { var meter = MeterFactory.Create(mb => { mb.SetMetricProcessor(simpleProcessor); mb.SetMetricExporter(exporter); mb.SetMetricPushInterval(TimeSpan.FromMilliseconds(metricPushIntervalMsec)); }).GetMeter("library1"); var testCounter = meter.CreateInt64Counter("testCounter"); var testMeasure = meter.CreateInt64Measure("testMeasure"); var labels1 = new List <KeyValuePair <string, string> >(); labels1.Add(new KeyValuePair <string, string>("dim1", "value1")); labels1.Add(new KeyValuePair <string, string>("dim2", "value1")); var labels2 = new List <KeyValuePair <string, string> >(); labels2.Add(new KeyValuePair <string, string>("dim1", "value2")); labels2.Add(new KeyValuePair <string, string>("dim2", "value2")); var defaultContext = default(SpanContext); for (int i = 0; i < 10; i++) { testCounter.Add(defaultContext, 100, meter.GetLabelSet(labels1)); testCounter.Add(defaultContext, 10, meter.GetLabelSet(labels1)); testCounter.Add(defaultContext, 200, meter.GetLabelSet(labels2)); testCounter.Add(defaultContext, 10, meter.GetLabelSet(labels2)); testMeasure.Record(defaultContext, 10, meter.GetLabelSet(labels1)); testMeasure.Record(defaultContext, 100, meter.GetLabelSet(labels1)); testMeasure.Record(defaultContext, 5, meter.GetLabelSet(labels1)); testMeasure.Record(defaultContext, 500, meter.GetLabelSet(labels1)); } }
public void DefaultMeterShouldBeCollectedAsWell() { var testProcessor = new TestMetricProcessor(); var factory = MeterFactory.Create(mb => mb.SetMetricProcessor(testProcessor)); var controller = factory.PushMetricController; var defaultMeter = factory.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 OpenTelemetryMetrics(MetricProcessor processor = null) { _meter = MeterFactory.Create(processor).GetMeter("Steeltoe"); }
public void MeterFactory_SetDefaultTwice_Throws() { MeterFactoryBase.SetDefault(MeterFactory.Create(b => { })); Assert.Throws <InvalidOperationException>(() => MeterFactoryBase.SetDefault(MeterFactory.Create(b => { }))); }
internal static async Task <object> RunAsync(int port, int pushIntervalInSecs, int totalDurationInMins) { System.Console.WriteLine($"OpenTelemetry Prometheus Exporter is making metrics available at http://localhost:{port}/metrics/"); /* * Following is sample prometheus.yml config. Adjust port,interval as needed. * * scrape_configs: # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config. # - job_name: 'OpenTelemetryTest' # # metrics_path defaults to '/metrics' # scheme defaults to 'http'. # # static_configs: # - targets: ['localhost:9184'] */ // Create and Setup Prometheus Exporter var promOptions = new PrometheusExporterOptions() { Url = $"http://localhost:{port}/metrics/" }; var promExporter = new PrometheusExporter(promOptions); var metricsHttpServer = new PrometheusExporterMetricsHttpServer(promExporter); metricsHttpServer.Start(); // Create Processor (called Batcher in Metric spec, this is still not decided) var processor = new UngroupedBatcher(); // MeterFactory is from where one can obtain Meters. // All meters from this factory will be configured with the common processor. var meterFactory = MeterFactory.Create(mb => { mb.SetMetricProcessor(processor); mb.SetMetricExporter(promExporter); mb.SetMetricPushInterval(TimeSpan.FromSeconds(pushIntervalInSecs)); }); // Obtain a Meter. Libraries would pass their name as argument. var meter = meterFactory.GetMeter("MyMeter"); // the rest is purely from Metrics API. var testCounter = meter.CreateInt64Counter("MyCounter"); var testMeasure = meter.CreateInt64Measure("MyMeasure"); var testObserver = meter.CreateInt64Observer("MyObservation", CallBackForMyObservation); 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 defaultContext = default(SpanContext); Stopwatch sw = Stopwatch.StartNew(); while (sw.Elapsed.TotalMinutes < totalDurationInMins) { testCounter.Add(defaultContext, 100, meter.GetLabelSet(labels1)); testMeasure.Record(defaultContext, 100, meter.GetLabelSet(labels1)); testMeasure.Record(defaultContext, 500, meter.GetLabelSet(labels1)); testMeasure.Record(defaultContext, 5, meter.GetLabelSet(labels1)); testMeasure.Record(defaultContext, 750, meter.GetLabelSet(labels1)); // Obviously there is no testObserver.Oberve() here, as Observer instruments // have callbacks that are called by the Meter automatically at each collection interval. await Task.Delay(1000); var remaining = (totalDurationInMins * 60) - sw.Elapsed.TotalSeconds; System.Console.WriteLine("Running and emitting metrics. Remaining time:" + (int)remaining + " seconds"); } // Stopping metricsHttpServer.Stop(); System.Console.WriteLine("Metrics server shutdown."); System.Console.WriteLine("Press Enter key to exit."); return(null); }
public void LongCounterBoundInstrumentsStatusUpdatedCorrectlySingleThread() { var testProcessor = new TestMetricProcessor(); var meter = MeterFactory.Create(testProcessor).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 = MeterFactory.Create(testProcessor).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(); Assert.Single(testProcessor.doubleMetrics.Where(m => (m.Data as SumData <double>).Sum == 110.0)); // 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 { mreToBlockStartOfThread = mre, callback = () => meter.Collect() }; var argsForCounterAdd = new ArgsToThread { mreToBlockStartOfThread = mre, 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.doubleMetrics) { sum += (exportedData.Data as SumData <double>).Sum; } // 210 = 110 from initial update, 100 from the multi-thread test case. Assert.Equal(210.0, sum); }