using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Collections.Generic;
private static async Task Main(string[] args)
.ConfigureLogging(logger => logger.AddConsole())
.ConfigureServices(services =>
services.AddOpenTelemetry()
.WithMetrics(metricsBuilder =>
metricsBuilder.ConfigureResource(resourceBuilder =>
.AddService("ClickService")
new KeyValuePair<string, object>("dc", Environment.GetEnvironmentVariable("dc") ?? "il3"),
new KeyValuePair<string, object>("env", Environment.GetEnvironmentVariable("env") ?? "local"),
var meterProviderBuilder = metricsBuilder.AddMeter("custom-console-meter");
metricsBuilder.AddConsoleExporter();
metricsBuilder.AddPrometheusHttpListener(httpListenerOptions =>
httpListenerOptions.UriPrefixes = new[] { "http://localhost:9464/" };
services.AddHostedService<ClickAppHost>();
await host.RunConsoleAsync();
public class ClickAppHost : IHostedService
private readonly CancellationTokenSource _work = new();
public Task StartAsync(CancellationToken cancellationToken)
Console.CancelKeyPress += (sender, args) =>
Console.WriteLine("cancellation requested");
while (!_work.Token.IsCancellationRequested)
Console.WriteLine("Click a key");
var sw = Stopwatch.GetTimestamp();
var key = Console.ReadKey(intercept: true);
var elapsed = Stopwatch.GetElapsedTime(sw);
var combination = GetKeyLabel(key);
Console.WriteLine($"Clicked: {combination}");
Meters.ClickInstrument.Add(1,
new KeyValuePair<string, object?>("key", combination));
Meters.DurationInstrumentation.Record((long)elapsed.TotalMilliseconds);
return Task.CompletedTask;
static string GetKeyLabel(ConsoleKeyInfo keyInfo)
=> keyInfo.Modifiers != ConsoleModifiers.None
? $"{keyInfo.Modifiers}-{keyInfo.KeyChar}"
: keyInfo.KeyChar.ToString();
public Task StopAsync(CancellationToken cancellationToken)
return Task.CompletedTask;
public static class Meters
private static readonly Meter _applicationMeter = new("custom-console-meter", "1.0.0");
public static readonly Counter<int> ClickInstrument
= _applicationMeter.CreateCounter<int>("click_c", "clicks_total", "count the number of clicks");
public static readonly Histogram<long> DurationInstrumentation
= _applicationMeter.CreateHistogram<long>("click_t", "ms", "time to click after prompted");