Last active
November 26, 2021 07:51
-
-
Save itn3000/21e472f7a840d5dfea5ab79f2f03bab6 to your computer and use it in GitHub Desktop.
Example code for treating System.Diagnostics.Metrics as EventCounter(for dotnet-counters)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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