Skip to content

Instantly share code, notes, and snippets.

@itn3000
Last active November 26, 2021 07:51
Show Gist options
  • Save itn3000/21e472f7a840d5dfea5ab79f2f03bab6 to your computer and use it in GitHub Desktop.
Save itn3000/21e472f7a840d5dfea5ab79f2f03bab6 to your computer and use it in GitHub Desktop.
Example code for treating System.Diagnostics.Metrics as EventCounter(for dotnet-counters)
using System.Collections.Concurrent;
using System.Diagnostics.Metrics;
using System.Diagnostics.Tracing;
using var cts = new CancellationTokenSource();
using var meter = new Meter("m1");
using var counterCollector = new CounterCollector(MyEventSource.Log);
var c1 = meter.CreateCounter<int>("metric-counter");
counterCollector.AddCounter(c1);
await Task.WhenAll(
Task.Run(async () =>
{
int cnt = 0;
while (!cts.IsCancellationRequested)
{
try
{
c1.Add(cnt++);
if ((cnt & 0x100) != 0)
{
cnt = 0;
}
await Task.Delay(2000, cts.Token);
}
catch (OperationCanceledException)
{
}
}
}),
Task.Run(() =>
{
Console.ReadLine();
cts.Cancel();
})
);
// used by EventCounter(EventCounter must be tied with EventSource)
[EventSource]
class MyEventSource: EventSource
{
private MyEventSource() : base()
{
}
public static readonly MyEventSource Log = new MyEventSource();
}
class CounterCollector : IDisposable
{
ConcurrentDictionary<string, EventCounter> _Counters;
MeterListener _Listener;
private bool disposedValue;
EventSource _EventSource;
public CounterCollector(EventSource eventSource)
{
_Counters = new ConcurrentDictionary<string, EventCounter>();
_EventSource = eventSource;
_Listener = new MeterListener();
_Listener.SetMeasurementEventCallback<int>((inst, value, tags, state) =>
{
if (_Counters.TryGetValue(inst.Name, out var counter))
{
counter.WriteMetric(value);
}
});
_Listener.SetMeasurementEventCallback<long>((inst, value, tags, state) =>
{
if (_Counters.TryGetValue(inst.Name, out var counter))
{
counter.WriteMetric(value);
}
});
_Listener.SetMeasurementEventCallback<double>((inst, value, tags, state) =>
{
if (_Counters.TryGetValue(inst.Name, out var counter))
{
counter.WriteMetric(value);
}
});
_Listener.SetMeasurementEventCallback<float>((inst, value, tags, state) =>
{
if (_Counters.TryGetValue(inst.Name, out var counter))
{
counter.WriteMetric(value);
}
});
}
public void AddCounter<T>(Counter<T> inst) where T : struct
{
if (!_Counters.ContainsKey(inst.Name))
{
var c = new EventCounter(inst.Name, _EventSource);
if (_Counters.TryAdd(inst.Name, c))
{
_Listener.EnableMeasurementEvents(inst);
}
else
{
c.Dispose();
}
}
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
_Listener?.Dispose();
foreach (var c in _Counters.Values)
{
c.Dispose();
}
_Counters.Clear();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment