Last active
October 29, 2023 00:48
-
-
Save NickCraver/551ff8ad90d63344f0604442d33ad728 to your computer and use it in GitHub Desktop.
MetricsPrototyping
This file contains 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.Collections.Immutable; | |
using System.Collections.Generic; | |
using System.Net; | |
using System.Threading; | |
using System; | |
namespace MetricsPrototype | |
{ | |
public class Example | |
{ | |
public void Foo() | |
{ | |
var counter = Counter.Create("my_counter", "requests", "asldjkhasjklhda"); | |
counter.Increment(); | |
var counterWithTags1 = Counter.Create("my_counter_with_tags", "requests", "asldjkhasjklhda", new Tag<HttpStatusCode>("status_code")); | |
counterWithTags1.Increment(HttpStatusCode.OK); | |
var counterWithTags2 = Counter.Create("my_counter_with_tags", "requests", "asldjkhasjklhda", new Tag<HttpStatusCode>("status_code"), new Tag<string>("route")); | |
counterWithTags2.Increment(HttpStatusCode.OK, "Questions/Show"); | |
} | |
} | |
public abstract class MetricBase | |
{ | |
protected MetricBase() { } | |
public MetricBase(string name, string unit, string description) | |
=> (Name, Unit, Description) = (name, unit, description); | |
public MetricBase(string name, string unit, string description, IReadOnlyDictionary<string, string> tags) | |
=> (Name, Unit, Description, Tags) = (name, unit, description, tags); | |
internal void Init(MetricBase baseProps, ImmutableDictionary<string, string>.Builder tagBuilder) | |
=> (Name, Unit, Description, Tags) = (baseProps.Name, baseProps.Unit, baseProps.Description, tagBuilder); | |
public string Name { get; protected set; } | |
public string Unit { get; protected set; } | |
public string Description { get; protected set; } | |
public IReadOnlyDictionary<string, string> Tags { get; protected set; } | |
} | |
public abstract class MetricBase<TMetric, TTag> : MetricBase where TMetric : MetricBase, new() | |
{ | |
protected readonly ConcurrentDictionary<TTag, TMetric> Metrics = new ConcurrentDictionary<TTag, TMetric>(); | |
public Tag<TTag> Tag { get; private set; } | |
public MetricBase(string name, string unit, string description, Tag<TTag> tag) : base(name, unit, description) | |
=> Tag = tag; | |
public TMetric Get(TTag value) => Metrics.GetOrAdd(value, key => GetFor(key)); | |
private TMetric GetFor(TTag value) | |
{ | |
var tags = ImmutableDictionary.CreateBuilder<string, string>(); | |
tags.Add(Tag.Name, value.ToString()); | |
var result = new TMetric(); | |
result.Init(this, tags); | |
return result; | |
} | |
} | |
public abstract class MetricBase<TMetric, TTag1, TTag2> : MetricBase where TMetric : MetricBase, new() | |
{ | |
protected readonly ConcurrentDictionary<(TTag1, TTag2), TMetric> Metrics = new ConcurrentDictionary<(TTag1, TTag2), TMetric>(); | |
public Tag<TTag1> Tag1 { get; private set; } | |
public Tag<TTag2> Tag2 { get; private set; } | |
public MetricBase(string name, string unit, string description, Tag<TTag1> tag1, Tag<TTag2> tag2) : base(name, unit, description) | |
=> (Tag1, Tag2) = (tag1, tag2); | |
public TMetric Get(TTag1 value1, TTag2 value2) => Metrics.GetOrAdd((value1, value2), key => GetFor(key)); | |
private TMetric GetFor((TTag1, TTag2) tagValues) | |
{ | |
var tags = ImmutableDictionary.CreateBuilder<string, string>(); | |
tags.Add(Tag1.Name, tagValues.Item1.ToString()); | |
tags.Add(Tag2.Name, tagValues.Item2.ToString()); | |
var result = new TMetric(); | |
result.Init(this, tags); | |
return result; | |
} | |
} | |
public sealed class Counter : MetricBase | |
{ | |
[Obsolete("For initialization only", true)] | |
public Counter() { } | |
private Counter(string name, string unit, string description) : base(name, unit, description, ImmutableDictionary<string, string>.Empty) { } | |
private long i; | |
public void Increment() => Interlocked.Increment(ref i); | |
public static Counter Create(string name, string unit, string description) | |
=> new Counter(name, unit, description); | |
public static Counter<T> Create<T>(string name, string unit, string description, Tag<T> tag) | |
=> new Counter<T>(name, unit, description, tag); | |
public static Counter<T1, T2> Create<T1, T2>(string name, string unit, string description, Tag<T1> tag1, Tag<T2> tag2) | |
=> new Counter<T1, T2>(name, unit, description, tag1, tag2); | |
} | |
public sealed class Counter<T> : MetricBase<Counter, T> | |
{ | |
internal Counter(string name, string unit, string description, Tag<T> tag) : base(name, unit, description, tag) { } | |
public void Increment(T t) => Get(t).Increment(); | |
} | |
public class Counter<T1, T2> : MetricBase<Counter, T1, T2> | |
{ | |
internal Counter(string name, string unit, string description, Tag<T1> tag1, Tag<T2> tag2) : base (name, unit, description, tag1, tag2) { } | |
public void Increment(T1 t1, T2 t2) => Get(t1, t2).Increment(); | |
} | |
public sealed class SnapshotGauge : MetricBase | |
{ | |
[Obsolete("For initialization only", true)] | |
public SnapshotGauge() { } | |
private SnapshotGauge(string name, string unit, string description) : base(name, unit, description, ImmutableDictionary<string, string>.Empty) { } | |
public static SnapshotGauge Create(string name, string unit, string description) | |
=> new SnapshotGauge(name, unit, description); | |
public static SnapshotGauge<T> Create<T>(string name, string unit, string description, Tag<T> tag) | |
=> new SnapshotGauge<T>(name, unit, description, tag); | |
public static SnapshotGauge<T1, T2> Create<T1, T2>(string name, string unit, string description, Tag<T1> tag1, Tag<T2> tag2) | |
=> new SnapshotGauge<T1, T2>(name, unit, description, tag1, tag2); | |
} | |
public class SnapshotGauge<T> : MetricBase<SnapshotGauge, T> | |
{ | |
internal SnapshotGauge(string name, string unit, string description, Tag<T> tag) : base(name, unit, description, tag) { } | |
} | |
public class SnapshotGauge<T1, T2> : MetricBase<SnapshotGauge, T1, T2> | |
{ | |
internal SnapshotGauge(string name, string unit, string description, Tag<T1> tag1, Tag<T2> tag2) : base(name, unit, description, tag1, tag2) { } | |
} | |
public readonly struct Tag<T> | |
{ | |
public string Name { get; } | |
public Tag(string name) => Name = name; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment