From 3fbf1d98df0712d433d3025cb783e9b421b6ccd3 Mon Sep 17 00:00:00 2001 From: Reiley Yang Date: Fri, 12 Nov 2021 11:29:26 -0800 Subject: [PATCH] Improve Prometheus example (#2601) --- .../learning-more-instruments/Program.cs | 2 +- examples/Console/Program.cs | 7 +- examples/Console/TestPrometheusExporter.cs | 113 +++++++++--------- 3 files changed, 57 insertions(+), 65 deletions(-) diff --git a/docs/metrics/learning-more-instruments/Program.cs b/docs/metrics/learning-more-instruments/Program.cs index e082f28da..1c4a91fef 100644 --- a/docs/metrics/learning-more-instruments/Program.cs +++ b/docs/metrics/learning-more-instruments/Program.cs @@ -30,7 +30,7 @@ public class Program { var process = Process.GetCurrentProcess(); - MyMeter.CreateObservableCounter("Thread.CpuTime", () => GetThreadCpuTime(process), "seconds"); + MyMeter.CreateObservableCounter("Thread.CpuTime", () => GetThreadCpuTime(process), "ms"); MyMeter.CreateObservableGauge("Thread.State", () => GetThreadState(process)); } diff --git a/examples/Console/Program.cs b/examples/Console/Program.cs index afebf22d8..3ee742505 100644 --- a/examples/Console/Program.cs +++ b/examples/Console/Program.cs @@ -47,7 +47,7 @@ namespace Examples.Console .MapResult( (JaegerOptions options) => TestJaegerExporter.Run(options.Host, options.Port), (ZipkinOptions options) => TestZipkinExporter.Run(options.Uri), - (PrometheusOptions options) => TestPrometheusExporter.Run(options.Port, options.DurationInMins), + (PrometheusOptions options) => TestPrometheusExporter.Run(options.Port), (MetricsOptions options) => TestMetrics.Run(options), (LogsOptions options) => TestLogs.Run(options), (GrpcNetClientOptions options) => TestGrpcNetClient.Run(), @@ -85,11 +85,8 @@ namespace Examples.Console [Verb("prometheus", HelpText = "Specify the options required to test Prometheus")] internal class PrometheusOptions { - [Option('p', "port", Default = 9184, HelpText = "The port to expose metrics. The endpoint will be http://localhost:port/metrics (This is the port from which your Prometheus server scraps metrics from.)", Required = false)] + [Option('p', "port", Default = 9184, HelpText = "The port to expose metrics. The endpoint will be http://localhost:port/metrics/ (this is the port from which your Prometheus server scraps metrics from.)", Required = false)] public int Port { get; set; } - - [Option('d', "duration", Default = 2, HelpText = "Total duration in minutes to run the demo.", Required = false)] - public int DurationInMins { get; set; } } [Verb("metrics", HelpText = "Specify the options required to test Metrics")] diff --git a/examples/Console/TestPrometheusExporter.cs b/examples/Console/TestPrometheusExporter.cs index 3e512bb6f..3b6d2a24d 100644 --- a/examples/Console/TestPrometheusExporter.cs +++ b/examples/Console/TestPrometheusExporter.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.Metrics; using System.Threading; using System.Threading.Tasks; @@ -23,73 +24,67 @@ using OpenTelemetry; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; -namespace Examples.Console +namespace Examples.Console; + +internal class TestPrometheusExporter { - internal class TestPrometheusExporter + private static readonly Meter MyMeter = new Meter("MyMeter"); + private static readonly Counter Counter = MyMeter.CreateCounter("myCounter", description: "A counter for demonstration purpose."); + private static readonly Histogram MyHistogram = MyMeter.CreateHistogram("myHistogram"); + private static readonly ThreadLocal ThreadLocalRandom = new ThreadLocal(() => new Random()); + + internal static object Run(int port) { - private static readonly Meter MyMeter = new Meter("TestMeter"); - private static readonly Counter Counter = MyMeter.CreateCounter("myCounter", description: "A counter for demonstration purpose."); - private static readonly Histogram MyHistogram = MyMeter.CreateHistogram("myHistogram"); - private static readonly ThreadLocal ThreadLocalRandom = new ThreadLocal(() => new Random()); + /* prometheus.yml - internal static object Run(int port, int totalDurationInMins) + 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(() => { - /* - Following is sample prometheus.yml config. Adjust port,interval as needed. - - scrape_configs: - # The job name is added as a label `job=` to any timeseries scraped from this config. - - job_name: 'OpenTelemetryTest' - - # metrics_path defaults to '/metrics' - # scheme defaults to 'http'. - - 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(); - - ObservableGauge gauge = MyMeter.CreateObservableGauge( - "myGauge", - () => + while (!token.IsCancellationRequested) { - return new List>() - { - new Measurement(ThreadLocalRandom.Value.Next(1, 1000), new("tag1", "value1"), new("tag2", "value2")), - new Measurement(ThreadLocalRandom.Value.Next(1, 1000), new("tag1", "value1"), new("tag2", "value3")), - }; - }, - description: "A gauge for demonstration purpose."); + 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(); + } + }); - using var token = new CancellationTokenSource(); - Task writeMetricTask = new Task(() => - { - 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")); + System.Console.WriteLine($"PrometheusExporter is listening on http://localhost:{port}/metrics/"); + System.Console.WriteLine($"Press any key to exit..."); + System.Console.ReadKey(); + token.Cancel(); - Task.Delay(10).Wait(); - } - }); - writeMetricTask.Start(); + return null; + } - token.CancelAfter(totalDurationInMins * 60 * 1000); - - System.Console.WriteLine($"OpenTelemetry Prometheus Exporter is making metrics available at http://localhost:{port}/metrics/"); - System.Console.WriteLine($"Press Enter key to exit now or will exit automatically after {totalDurationInMins} minutes."); - System.Console.ReadLine(); - token.Cancel(); - System.Console.WriteLine("Exiting..."); - return null; + private static IEnumerable> GetThreadCpuTime(Process process) + { + foreach (ProcessThread thread in process.Threads) + { + yield return new(thread.TotalProcessorTime.TotalMilliseconds, new("ProcessId", process.Id), new("ThreadId", thread.Id)); } } }