public void DoubleObserverSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = Sdk.CreateMeterProvider(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 CounterSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = Sdk.CreateMeterProvider(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); }
public void MeasureSendsAggregateToRegisteredProcessor() { var testProcessor = new TestMetricProcessor(); var meter = Sdk.CreateMeterProvider(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); }
/// <summary>add MagicOnion Telemetry.</summary> public static IServiceCollection AddMagicOnionOpenTelemetry(this IServiceCollection services, MagicOnionOpenTelemetryOptions options, Action <MagicOnionOpenTelemetryOptions, MagicOnionOpenTelemetryMeterFactoryOption> configureMeterProvider, Action <MagicOnionOpenTelemetryOptions, IServiceProvider, TracerProviderBuilder> configureTracerProvider) { if (options == null) { throw new ArgumentNullException(nameof(options)); } services.AddSingleton(options); // configure MeterFactory if (configureMeterProvider != null) { var meterFactoryOption = new MagicOnionOpenTelemetryMeterFactoryOption(); configureMeterProvider(options, meterFactoryOption); MeterProvider.SetDefault(Sdk.CreateMeterProvider(builder => { builder.SetMetricProcessor(meterFactoryOption.MetricProcessor); builder.SetMetricExporter(meterFactoryOption.MetricExporter); builder.SetMetricPushInterval(meterFactoryOption.MetricPushInterval); })); services.AddSingleton(meterFactoryOption.MetricExporter); services.AddSingleton(MeterProvider.Default); } // configure TracerFactory if (configureTracerProvider != null) { if (string.IsNullOrEmpty(options.ActivitySourceName)) { throw new NullReferenceException(nameof(options.ActivitySourceName)); } var tracerFactory = services.AddOpenTelemetry((provider, builder) => { // ActivitySourceName must match to TracerName. builder.AddActivitySource(options.ActivitySourceName); configureTracerProvider(options, provider, builder); }); services.AddSingleton(tracerFactory); } return(services); }
public void MeterProvider_UpdateDefault_CachedTracer() { var defaultMeter = MeterProvider.Default.GetMeter(string.Empty); var noOpCounter = defaultMeter.CreateDoubleCounter("ctr"); Assert.IsType <NoOpCounterMetric <double> >(noOpCounter); MeterProvider.SetDefault(Sdk.CreateMeterProvider(b => { })); var counter = defaultMeter.CreateDoubleCounter("ctr"); Assert.IsType <DoubleCounterMetricSdk>(counter); var newdefaultMeter = MeterProvider.Default.GetMeter(string.Empty); Assert.NotSame(defaultMeter, newdefaultMeter); Assert.IsType <MeterSdk>(newdefaultMeter); }
public void MeterProvider_SetDefault() { var meterProvider = Sdk.CreateMeterProvider(b => { }); MeterProvider.SetDefault(meterProvider); var defaultMeter = MeterProvider.Default.GetMeter(string.Empty); Assert.NotNull(defaultMeter); Assert.IsType <MeterSdk>(defaultMeter); Assert.NotSame(defaultMeter, MeterProvider.Default.GetMeter("named meter")); var counter = defaultMeter.CreateDoubleCounter("ctr"); Assert.IsType <DoubleCounterMetricSdk>(counter); }
public void DefaultMeterShouldBeCollectedAsWell() { var testProcessor = new TestMetricProcessor(); var meterProvider = (MeterProviderSdk)Sdk.CreateMeterProvider(mb => mb.SetMetricProcessor(testProcessor)); 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); }
private static void CollectMetrics(UngroupedBatcher simpleProcessor, MetricExporter exporter) { var meter = Sdk.CreateMeterProvider(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> > { new KeyValuePair <string, string>("dim1", "value1"), new KeyValuePair <string, string>("dim2", "value1"), }; var labels2 = new List <KeyValuePair <string, string> > { new KeyValuePair <string, string>("dim1", "value2"), 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 LongCounterBoundInstrumentsStatusUpdatedCorrectlySingleThread() { var testProcessor = new TestMetricProcessor(); var meter = Sdk.CreateMeterProvider(mb => mb.SetMetricProcessor(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 = Sdk.CreateMeterProvider(mb => mb.SetMetricProcessor(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(); // 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); }
public void MeterProvider_SetDefaultTwice_Throws() { MeterProvider.SetDefault(Sdk.CreateMeterProvider(b => { })); Assert.Throws <InvalidOperationException>(() => MeterProvider.SetDefault(Sdk.CreateMeterProvider(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(); // Application which decides to enable OpenTelemetry metrics // would setup a MeterProvider and make it default. // All meters from this factory will be configured with the common processing pipeline. MeterProvider.SetDefault(Sdk.CreateMeterProvider(mb => { mb.SetMetricProcessor(processor); mb.SetMetricExporter(promExporter); mb.SetMetricPushInterval(TimeSpan.FromSeconds(pushIntervalInSecs)); })); // The following shows how libraries would obtain a MeterProvider. // MeterProvider is the entry point, which provides Meter. // If user did not set the Default MeterProvider (shown in earlier lines), // all metric operations become no-ops. var meterProvider = MeterProvider.Default; var meter = meterProvider.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); }