Skip to content

Commit

Permalink
Add IMeterFactory implementation to IoC
Browse files Browse the repository at this point in the history
This will be useful as we start using more System.Diagnostics.Metrics.
  • Loading branch information
PJB3005 committed Mar 22, 2024
1 parent f5ade69 commit f760929
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 0 deletions.
1 change: 1 addition & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ END TEMPLATE-->

* Made a new `IMetricsManager` interface with an `UpdateMetrics` event that can be used to update Prometheus metrics whenever they are scraped.
* Also added a `metrics.update_interval` CVar to go along with this, when metrics are scraped without usage of Prometheus directly.
* IoC now contains an `IMeterFactory` implementation that you can use to instantiate metric meters.

### Bugfixes

Expand Down
89 changes: 89 additions & 0 deletions Robust.Server/DataMetrics/MetricsManager.Factory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Linq;
using Robust.Shared.Utility;

namespace Robust.Server.DataMetrics;

internal sealed partial class MetricsManager : IMeterFactory
{
private readonly Dictionary<string, List<CachedMeter>> _meterCache = new();
private readonly object _meterCacheLock = new();

Meter IMeterFactory.Create(MeterOptions options)
{
if (options.Scope != null && options.Scope != this)
throw new InvalidOperationException("Cannot specify a custom scope when creating a meter");

lock (_meterCacheLock)
{
if (LockedFindCachedMeter(options) is { } cached)
return cached.Meter;

var meter = new Meter(options.Name, options.Version, options.Tags, this);
var meterList = _meterCache.GetOrNew(options.Name);
meterList.Add(new CachedMeter(options.Version, TagsToDict(options.Tags), meter));
return meter;
}
}

private CachedMeter? LockedFindCachedMeter(MeterOptions options)
{
if (!_meterCache.TryGetValue(options.Name, out var metersList))
return null;

var tagsDict = TagsToDict(options.Tags);

foreach (var cachedMeter in metersList)
{
if (cachedMeter.Version == options.Version && TagsMatch(tagsDict, cachedMeter.Tags))
return cachedMeter;
}

return null;
}

private static bool TagsMatch(Dictionary<string, object?> a, Dictionary<string, object?> b)
{
if (a.Count != b.Count)
return false;

foreach (var (key, valueA) in a)
{
if (!b.TryGetValue(key, out var valueB))
return false;

if (!Equals(valueA, valueB))
return false;
}

return true;
}

private static Dictionary<string, object?> TagsToDict(IEnumerable<KeyValuePair<string, object?>>? tags)
{
return tags?.ToDictionary() ?? [];
}

private void DisposeMeters()
{
lock (_meterCacheLock)
{
foreach (var meters in _meterCache.Values)
{
foreach (var meter in meters)
{
meter.Meter.Dispose();
}
}
}
}

private sealed class CachedMeter(string? version, Dictionary<string, object?> tags, Meter meter)
{
public readonly string? Version = version;
public readonly Dictionary<string, object?> Tags = tags;
public readonly Meter Meter = meter;
}
}
4 changes: 4 additions & 0 deletions Robust.Server/DataMetrics/MetricsManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics.Metrics;
using System.Diagnostics.Tracing;
using System.Globalization;
using System.Linq;
Expand Down Expand Up @@ -26,6 +27,7 @@ namespace Robust.Server.DataMetrics;
/// </para>
/// <para>
/// Metrics can be added through the types in <c>System.Diagnostics.Metrics</c> or <c>Prometheus</c>.
/// IoC contains an implementation of <see cref="IMeterFactory"/> that can be used to instantiate meters.
/// </para>
/// </remarks>
public interface IMetricsManager
Expand Down Expand Up @@ -101,6 +103,8 @@ private async Task Stop()

async void IDisposable.Dispose()
{
DisposeMeters();

await Stop();

_initialized = false;
Expand Down
2 changes: 2 additions & 0 deletions Robust.Server/ServerIoC.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Diagnostics.Metrics;
using Robust.Server.Configuration;
using Robust.Server.Console;
using Robust.Server.DataMetrics;
Expand Down Expand Up @@ -81,6 +82,7 @@ internal static void RegisterIoC(IDependencyCollection deps)
deps.Register<IScriptHost, ScriptHost>();
deps.Register<IMetricsManager, MetricsManager>();
deps.Register<IMetricsManagerInternal, MetricsManager>();
deps.Register<IMeterFactory, MetricsManager>();
deps.Register<IAuthManager, AuthManager>();
deps.Register<HubManager, HubManager>();
deps.Register<IRobustSerializer, ServerRobustSerializer>();
Expand Down

0 comments on commit f760929

Please sign in to comment.