Example #1
0
    static Program()
    {
        var process = Process.GetCurrentProcess();

        MyMeter.CreateObservableCounter("Thread.CpuTime", () => GetThreadCpuTime(process), "ms");

        MyMeter.CreateObservableGauge("Thread.State", () => GetThreadState(process));
    }
Example #2
0
    internal static object Run(int port)
    {
        /* prometheus.yml
         *
         * global:
         * scrape_interval: 1s
         * evaluation_interval: 1s
         *
         * scrape_configs:
         * - job_name: "opentelemetry"
         *  static_configs:
         *    - targets: ["localhost:9184"]
         */

        using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                  .AddMeter(MyMeter.Name)
                                  .AddMeter(MyMeter2.Name)
                                  .AddPrometheusExporter(options =>
        {
            options.StartHttpListener    = true;
            options.HttpListenerPrefixes = new string[] { $"http://localhost:{port}/" };
            options.ScrapeResponseCacheDurationMilliseconds = 0;
        })
                                  .Build();

        var process = Process.GetCurrentProcess();

        MyMeter.CreateObservableCounter("thread.cpu_time", () => GetThreadCpuTime(process), "ms");

        // If the same Instrument name+unit combination happened under different Meters, PrometheusExporter
        // exporter will output duplicated metric names. Related issues and PRs:
        // * https://github.com/open-telemetry/opentelemetry-specification/pull/2017
        // * https://github.com/open-telemetry/opentelemetry-specification/pull/2035
        // * https://github.com/open-telemetry/opentelemetry-dotnet/pull/2593
        //
        // MyMeter2.CreateObservableCounter("thread.cpu_time", () => GetThreadCpuTime(process), "ms");

        using var token = new CancellationTokenSource();

        Task.Run(() =>
        {
            while (!token.IsCancellationRequested)
            {
                Counter.Add(9.9, new("name", "apple"), new("color", "red"));
                Counter.Add(99.9, new("name", "lemon"), new("color", "yellow"));
                MyHistogram.Record(ThreadLocalRandom.Value.Next(1, 1500), new("tag1", "value1"), new("tag2", "value2"));
                Task.Delay(10).Wait();
            }
        });

        System.Console.WriteLine($"PrometheusExporter is listening on http://localhost:{port}/metrics/");
        System.Console.WriteLine($"Press any key to exit...");
        System.Console.ReadKey();
        token.Cancel();

        return(null);
    }
        public void ObservableCounterAggregationTest(bool exportDelta)
        {
            var metricItems    = new List <Metric>();
            var metricExporter = new InMemoryExporter <Metric>(metricItems);

            var metricReader = new BaseExportingMetricReader(metricExporter)
            {
                PreferredAggregationTemporality = exportDelta ? AggregationTemporality.Delta : AggregationTemporality.Cumulative,
            };

            using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{exportDelta}");
            int i           = 1;
            var counterLong = meter.CreateObservableCounter(
                "observable-counter",
                () =>
            {
                return(new List <Measurement <long> >()
                {
                    new Measurement <long>(i++ *10),
                });
            });

            using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                      .AddMeter(meter.Name)
                                      .AddReader(metricReader)
                                      .Build();

            metricReader.Collect();
            long sumReceived = GetLongSum(metricItems);

            Assert.Equal(10, sumReceived);

            metricItems.Clear();
            metricReader.Collect();
            sumReceived = GetLongSum(metricItems);
            if (exportDelta)
            {
                Assert.Equal(10, sumReceived);
            }
            else
            {
                Assert.Equal(20, sumReceived);
            }

            metricItems.Clear();
            metricReader.Collect();
            sumReceived = GetLongSum(metricItems);
            if (exportDelta)
            {
                Assert.Equal(10, sumReceived);
            }
            else
            {
                Assert.Equal(30, sumReceived);
            }
        }
Example #4
0
        public void ViewToDropSingleInstrumentObservableCounter()
        {
            using var meter = new Meter(Utils.GetCurrentMethodName());
            var exportedItems = new List <Metric>();

            using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                      .AddMeter(meter.Name)
                                      .AddView("observableCounterNotInteresting", MetricStreamConfiguration.Drop)
                                      .AddInMemoryExporter(exportedItems)
                                      .Build();

            // Expecting one metric stream.
            meter.CreateObservableCounter("observableCounterNotInteresting", () => { return(10); }, "ms");
            meter.CreateObservableCounter("observableCounterInteresting", () => { return(10); }, "ms");

            meterProvider.ForceFlush(MaxTimeToAllowForFlush);
            Assert.Single(exportedItems);
            var metric = exportedItems[0];

            Assert.Equal("observableCounterInteresting", metric.Name);
        }
Example #5
0
    internal static object Run(int port)
    {
        /* prometheus.yml
         *
         * global:
         * scrape_interval: 1s
         * evaluation_interval: 1s
         *
         * scrape_configs:
         * - job_name: "opentelemetry"
         *  static_configs:
         *    - targets: ["localhost:9184"]
         */

        using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                  .AddMeter(MyMeter.Name)
                                  .AddPrometheusExporter(opt =>
        {
            opt.StartHttpListener    = true;
            opt.HttpListenerPrefixes = new string[] { $"http://localhost:{port}/" };
        })
                                  .Build();

        var process = Process.GetCurrentProcess();

        MyMeter.CreateObservableCounter("thread.cpu_time", () => GetThreadCpuTime(process), "ms");

        using var token = new CancellationTokenSource();

        Task.Run(() =>
        {
            while (!token.IsCancellationRequested)
            {
                Counter.Add(9.9, new("name", "apple"), new("color", "red"));
                Counter.Add(99.9, new("name", "lemon"), new("color", "yellow"));
                MyHistogram.Record(ThreadLocalRandom.Value.Next(1, 1500), new("tag1", "value1"), new("tag2", "value2"));
                Task.Delay(10).Wait();
            }
        });

        System.Console.WriteLine($"PrometheusExporter is listening on http://localhost:{port}/metrics/");
        System.Console.WriteLine($"Press any key to exit...");
        System.Console.ReadKey();
        token.Cancel();

        return(null);
    }
Example #6
0
    public static async Task Main(string[] args)
    {
        using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                  .AddSource("TestMeter")
                                  .AddConsoleExporter()
                                  .Build();

        int i = 1;
        var observableCounter = MyMeter.CreateObservableCounter <long>(
            "observable-counter",
            () =>
        {
            var tag1 = new KeyValuePair <string, object>("tag1", "value1");
            var tag2 = new KeyValuePair <string, object>("tag2", "value2");
            return(new List <Measurement <long> >()
            {
                // Report an absolute value (not an increment/delta value).
                new Measurement <long>(i++ *10, tag1, tag2),
            });
        });

        await Task.Delay(10000);
    }
Example #7
0
        public void SdkSupportsMultipleReaders(MetricReaderTemporalityPreference aggregationTemporality, bool hasViews)
        {
            var exportedItems1 = new List <Metric>();
            var exportedItems2 = new List <Metric>();

            using var meter = new Meter($"{Utils.GetCurrentMethodName()}.{aggregationTemporality}.{hasViews}");

            var counter = meter.CreateCounter <long>("counter");

            int index  = 0;
            var values = new long[] { 100, 200, 300, 400 };

            long GetValue() => values[index++];

            var gauge = meter.CreateObservableGauge("gauge", () => GetValue());

            int indexSum  = 0;
            var valuesSum = new long[] { 1000, 1200, 1300, 1400 };

            long GetSum() => valuesSum[indexSum++];

            var observableCounter = meter.CreateObservableCounter("obs-counter", () => GetSum());

            var meterProviderBuilder = Sdk.CreateMeterProviderBuilder()
                                       .AddMeter(meter.Name)
                                       .AddInMemoryExporter(exportedItems1, metricReaderOptions =>
            {
                metricReaderOptions.TemporalityPreference = MetricReaderTemporalityPreference.Delta;
            })
                                       .AddInMemoryExporter(exportedItems2, metricReaderOptions =>
            {
                metricReaderOptions.TemporalityPreference = aggregationTemporality;
            });

            if (hasViews)
            {
                meterProviderBuilder.AddView("counter", "renamedCounter");
                meterProviderBuilder.AddView("gauge", "renamedGauge");
                meterProviderBuilder.AddView("obs-counter", "renamedObservableCounter");
            }

            using var meterProvider = meterProviderBuilder.Build();

            counter.Add(10, new KeyValuePair <string, object>("key", "value"));

            meterProvider.ForceFlush();

            Assert.Equal(3, exportedItems1.Count);
            Assert.Equal(3, exportedItems2.Count);

            if (hasViews)
            {
                Assert.Equal("renamedCounter", exportedItems1[0].Name);
                Assert.Equal("renamedCounter", exportedItems2[0].Name);

                Assert.Equal("renamedGauge", exportedItems1[1].Name);
                Assert.Equal("renamedGauge", exportedItems2[1].Name);

                Assert.Equal("renamedObservableCounter", exportedItems1[2].Name);
                Assert.Equal("renamedObservableCounter", exportedItems2[2].Name);
            }
            else
            {
                Assert.Equal("counter", exportedItems1[0].Name);
                Assert.Equal("counter", exportedItems2[0].Name);

                Assert.Equal("gauge", exportedItems1[1].Name);
                Assert.Equal("gauge", exportedItems2[1].Name);

                Assert.Equal("obs-counter", exportedItems1[2].Name);
                Assert.Equal("obs-counter", exportedItems2[2].Name);
            }

            // Check value exported for Counter
            AssertLongSumValueForMetric(exportedItems1[0], 10);
            AssertLongSumValueForMetric(exportedItems2[0], 10);

            // Check value exported for Gauge
            AssertLongSumValueForMetric(exportedItems1[1], 100);
            AssertLongSumValueForMetric(exportedItems2[1], 200);

            // Check value exported for ObservableCounter
            AssertLongSumValueForMetric(exportedItems1[2], 1000);
            if (aggregationTemporality == MetricReaderTemporalityPreference.Delta)
            {
                AssertLongSumValueForMetric(exportedItems2[2], 1200);
            }
            else
            {
                AssertLongSumValueForMetric(exportedItems2[2], 1200);
            }

            exportedItems1.Clear();
            exportedItems2.Clear();

            counter.Add(15, new KeyValuePair <string, object>("key", "value"));

            meterProvider.ForceFlush();

            Assert.Equal(3, exportedItems1.Count);
            Assert.Equal(3, exportedItems2.Count);

            // Check value exported for Counter
            AssertLongSumValueForMetric(exportedItems1[0], 15);
            if (aggregationTemporality == MetricReaderTemporalityPreference.Delta)
            {
                AssertLongSumValueForMetric(exportedItems2[0], 15);
            }
            else
            {
                AssertLongSumValueForMetric(exportedItems2[0], 25);
            }

            // Check value exported for Gauge
            AssertLongSumValueForMetric(exportedItems1[1], 300);
            AssertLongSumValueForMetric(exportedItems2[1], 400);

            // Check value exported for ObservableCounter
            AssertLongSumValueForMetric(exportedItems1[2], 300);
            if (aggregationTemporality == MetricReaderTemporalityPreference.Delta)
            {
                AssertLongSumValueForMetric(exportedItems2[2], 200);
            }
            else
            {
                AssertLongSumValueForMetric(exportedItems2[2], 1400);
            }
        }
        public void ObservableCounterAggregationTest(bool exportDelta)
        {
            var meterName      = "TestMeter" + exportDelta;
            var metricItems    = new List <Metric>();
            var metricExporter = new TestExporter <Metric>(ProcessExport);

            void ProcessExport(Batch <Metric> batch)
            {
                foreach (var metricItem in batch)
                {
                    metricItems.Add(metricItem);
                }
            }

            var metricReader = new BaseExportingMetricReader(metricExporter)
            {
                PreferredAggregationTemporality = exportDelta ? AggregationTemporality.Delta : AggregationTemporality.Cumulative,
            };

            using var meter = new Meter(meterName);
            int i           = 1;
            var counterLong = meter.CreateObservableCounter <long>(
                "observable-counter",
                () =>
            {
                return(new List <Measurement <long> >()
                {
                    new Measurement <long>(i++ *10),
                });
            });

            using var meterProvider = Sdk.CreateMeterProviderBuilder()
                                      .AddMeter(meterName)
                                      .AddReader(metricReader)
                                      .Build();

            metricReader.Collect();
            long sumReceived = GetLongSum(metricItems);

            Assert.Equal(10, sumReceived);

            metricItems.Clear();
            metricReader.Collect();
            sumReceived = GetLongSum(metricItems);
            if (exportDelta)
            {
                Assert.Equal(10, sumReceived);
            }
            else
            {
                Assert.Equal(20, sumReceived);
            }

            metricItems.Clear();
            metricReader.Collect();
            sumReceived = GetLongSum(metricItems);
            if (exportDelta)
            {
                Assert.Equal(10, sumReceived);
            }
            else
            {
                Assert.Equal(30, sumReceived);
            }
        }
        public void ObservableCounterAggregationTest(bool exportDelta)
        {
            var meterName      = "TestMeter" + exportDelta;
            var metricItems    = new List <MetricItem>();
            var metricExporter = new TestExporter <MetricItem>(ProcessExport);

            void ProcessExport(Batch <MetricItem> batch)
            {
                foreach (var metricItem in batch)
                {
                    metricItems.Add(metricItem);
                }
            }

            var pullProcessor = new PullMetricProcessor(metricExporter, exportDelta);

            var meter       = new Meter(meterName);
            int i           = 1;
            var counterLong = meter.CreateObservableCounter <long>(
                "observable-counter",
                () =>
            {
                return(new List <Measurement <long> >()
                {
                    new Measurement <long>(i++ *10),
                });
            });
            var meterProvider = Sdk.CreateMeterProviderBuilder()
                                .AddSource(meterName)
                                .AddMetricProcessor(pullProcessor)
                                .Build();

            pullProcessor.PullRequest();
            long sumReceived = GetSum(metricItems);

            Assert.Equal(10, sumReceived);

            metricItems.Clear();
            pullProcessor.PullRequest();
            sumReceived = GetSum(metricItems);
            if (exportDelta)
            {
                Assert.Equal(10, sumReceived);
            }
            else
            {
                Assert.Equal(20, sumReceived);
            }

            metricItems.Clear();
            pullProcessor.PullRequest();
            sumReceived = GetSum(metricItems);
            if (exportDelta)
            {
                Assert.Equal(10, sumReceived);
            }
            else
            {
                Assert.Equal(30, sumReceived);
            }
        }
Example #10
0
    public static void Stress(int concurrency = 0, int prometheusPort = 0)
    {
#if DEBUG
        Console.WriteLine("***WARNING*** The current build is DEBUG which may affect timing!");
        Console.WriteLine();
#endif

        if (concurrency < 0)
        {
            throw new ArgumentOutOfRangeException(nameof(concurrency), "concurrency level should be a non-negative number.");
        }

        if (concurrency == 0)
        {
            concurrency = Environment.ProcessorCount;
        }

        using var meter = new Meter("OpenTelemetry.Tests.Stress." + Guid.NewGuid().ToString("D"));
        var cntLoopsTotal = 0UL;
        meter.CreateObservableCounter(
            "OpenTelemetry.Tests.Stress.Loops",
            () => unchecked ((long)cntLoopsTotal),
            description: "The total number of `Run()` invocations that are completed.");
        var dLoopsPerSecond = 0D;
        meter.CreateObservableGauge(
            "OpenTelemetry.Tests.Stress.LoopsPerSecond",
            () => dLoopsPerSecond,
            description: "The rate of `Run()` invocations based on a small sliding window of few hundreds of milliseconds.");
        var dCpuCyclesPerLoop = 0D;
#if NET462
        if (Environment.OSVersion.Platform == PlatformID.Win32NT)
#else
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
#endif
        {
            meter.CreateObservableGauge(
                "OpenTelemetry.Tests.Stress.CpuCyclesPerLoop",
                () => dCpuCyclesPerLoop,
                description: "The average CPU cycles for each `Run()` invocation, based on a small sliding window of few hundreds of milliseconds.");
        }

        using var meterProvider = prometheusPort != 0 ? Sdk.CreateMeterProviderBuilder()
                                  .AddMeter(StressMeter.Name)
                                  .AddMeter(meter.Name)
                                  .AddPrometheusExporter(options =>
        {
            options.StartHttpListener    = true;
            options.HttpListenerPrefixes = new string[] { $"http://localhost:{prometheusPort}/" };
            options.ScrapeResponseCacheDurationMilliseconds = 0;
        })
                                  .Build() : null;

        var statistics    = new long[concurrency];
        var watchForTotal = new Stopwatch();
        watchForTotal.Start();

        Parallel.Invoke(
            () =>
        {
            Console.Write($"Running (concurrency = {concurrency}");

            if (prometheusPort != 0)
            {
                Console.Write($", prometheusEndpoint = http://localhost:{prometheusPort}/metrics/");
            }

            Console.WriteLine("), press <Esc> to stop...");

            var bOutput = false;
            var watch   = new Stopwatch();
            while (true)
            {
                if (Console.KeyAvailable)
                {
                    var key = Console.ReadKey(true).Key;

                    switch (key)
                    {
                    case ConsoleKey.Enter:
                        Console.WriteLine(string.Format("{0} {1}", DateTime.UtcNow.ToString("O"), output));
                        break;

                    case ConsoleKey.Escape:
                        bContinue = false;
                        return;

                    case ConsoleKey.Spacebar:
                        bOutput = !bOutput;
                        break;
                    }

                    continue;
                }

                if (bOutput)
                {
                    Console.WriteLine(string.Format("{0} {1}", DateTime.UtcNow.ToString("O"), output));
                }

                var cntLoopsOld     = (ulong)statistics.Sum();
                var cntCpuCyclesOld = GetCpuCycles();

                watch.Restart();
                Thread.Sleep(200);
                watch.Stop();

                cntLoopsTotal       = (ulong)statistics.Sum();
                var cntCpuCyclesNew = GetCpuCycles();

                var nLoops     = cntLoopsTotal - cntLoopsOld;
                var nCpuCycles = cntCpuCyclesNew - cntCpuCyclesOld;

                dLoopsPerSecond   = (double)nLoops / ((double)watch.ElapsedMilliseconds / 1000.0);
                dCpuCyclesPerLoop = nLoops == 0 ? 0 : nCpuCycles / nLoops;

                output        = $"Loops: {cntLoopsTotal:n0}, Loops/Second: {dLoopsPerSecond:n0}, CPU Cycles/Loop: {dCpuCyclesPerLoop:n0}";
                Console.Title = output;
            }
        },
            () =>
        {
            Parallel.For(0, concurrency, (i) =>
            {
                statistics[i] = 0;
                while (bContinue)
                {
                    Run();
                    statistics[i]++;
                }
            });
        });

        watchForTotal.Stop();
        cntLoopsTotal = (ulong)statistics.Sum();
        var totalLoopsPerSecond   = (double)cntLoopsTotal / ((double)watchForTotal.ElapsedMilliseconds / 1000.0);
        var cntCpuCyclesTotal     = GetCpuCycles();
        var cpuCyclesPerLoopTotal = cntLoopsTotal == 0 ? 0 : cntCpuCyclesTotal / cntLoopsTotal;
        Console.WriteLine("Stopping the stress test...");
        Console.WriteLine($"* Total Loops: {cntLoopsTotal:n0}");
        Console.WriteLine($"* Average Loops/Second: {totalLoopsPerSecond:n0}");
        Console.WriteLine($"* Average CPU Cycles/Loop: {cpuCyclesPerLoopTotal:n0}");
    }