Skip to content

Commit

Permalink
Add cache admin stats and move some shit internally
Browse files Browse the repository at this point in the history
  • Loading branch information
Simyon264 committed Jun 24, 2024
1 parent 8e8d556 commit 96bfc6c
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 2 deletions.
59 changes: 59 additions & 0 deletions ReplayBrowser/Helpers/MemoryCacheExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using Microsoft.Extensions.Caching.Memory;

namespace ReplayBrowser.Helpers;

public static class MemoryCacheExtensions
{
#region Microsoft.Extensions.Caching.Memory_6_OR_OLDER

private static readonly Lazy<Func<MemoryCache, object>> GetEntries6 =
new Lazy<Func<MemoryCache, object>>(() => (Func<MemoryCache, object>)Delegate.CreateDelegate(
typeof(Func<MemoryCache, object>),
typeof(MemoryCache).GetProperty("EntriesCollection", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true),
throwOnBindFailure: true));

#endregion

#region Microsoft.Extensions.Caching.Memory_7_OR_NEWER

private static readonly Lazy<Func<MemoryCache, object>> GetCoherentState =
new Lazy<Func<MemoryCache, object>>(() =>
CreateGetter<MemoryCache, object>(typeof(MemoryCache)
.GetField("_coherentState", BindingFlags.NonPublic | BindingFlags.Instance)));

private static readonly Lazy<Func<object, IDictionary>> GetEntries7 =
new Lazy<Func<object, IDictionary>>(() =>
CreateGetter<object, IDictionary>(typeof(MemoryCache)
.GetNestedType("CoherentState", BindingFlags.NonPublic)
.GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance)));

private static Func<TParam, TReturn> CreateGetter<TParam, TReturn>(FieldInfo field)
{
var methodName = $"{field.ReflectedType.FullName}.get_{field.Name}";
var method = new DynamicMethod(methodName, typeof(TReturn), new[] { typeof(TParam) }, typeof(TParam), true);
var ilGen = method.GetILGenerator();
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, field);
ilGen.Emit(OpCodes.Ret);
return (Func<TParam, TReturn>)method.CreateDelegate(typeof(Func<TParam, TReturn>));
}

#endregion

private static readonly Func<MemoryCache, IDictionary> GetEntries =
Assembly.GetAssembly(typeof(MemoryCache)).GetName().Version.Major < 7
? (Func<MemoryCache, IDictionary>)(cache => (IDictionary)GetEntries6.Value(cache))
: cache => GetEntries7.Value(GetCoherentState.Value(cache));

public static ICollection GetKeys(this IMemoryCache memoryCache) =>
GetEntries((MemoryCache)memoryCache).Keys;

public static IEnumerable<T> GetKeys<T>(this IMemoryCache memoryCache) =>
memoryCache.GetKeys().OfType<T>();
}
File renamed without changes.
87 changes: 87 additions & 0 deletions ReplayBrowser/Pages/Admin/AdminStats.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
@page "/account/admin/stats"
@using System.Text.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.Extensions.Caching.Memory
@using ReplayBrowser.Helpers
@using ReplayBrowser.Services
@using Microsoft.AspNetCore.Components.Web
@attribute [Authorize]
@inject IMemoryCache MemoryCache
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject AccountService AccountService
@inject NavigationManager NavigationManager

<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/themes/prism.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/components/prism-json.min.js"></script>

<PageTitle>Cache Stats</PageTitle>

<h3>AdminStats</h3>
@if(!_authed)
{
<div class="alert alert-danger" role="alert">
Not authorized
</div>
}
else
{
var stats = MemoryCache.GetCurrentStatistics();
if (stats == null)
{
<div class="alert alert-info" role="alert">
No stats available
</div>
}
else
{
<div class="card">
<div class="card-body">
<p>Total hits: <span class="badge bg-primary">@stats.TotalHits</span></p>
<p>Total misses: <span class="badge bg-danger">@stats.TotalMisses</span></p>
<p>Total entries: <span class="badge bg-info">@stats.CurrentEntryCount</span></p>
<p>Estimated size: <span class="badge bg-warning">@stats.CurrentEstimatedSize</span></p>
</div>
</div>
}

var keys = MemoryCache.GetKeys();
foreach (var key in keys)
{
var entry = MemoryCache.Get(key);

<div class="card mt-3">
<div class="card-body">
<p>
Key: <span class="text-muted">@key</span><br/>
Value:
<pre><code class="language-json">@JsonSerializer.Serialize(entry, new JsonSerializerOptions() { WriteIndented = true })</code></pre><br/>
</p>
</div>
</div>
}

<script>
$(document).ready(function() {
Prism.highlightAll();
});
</script>
}
@code {
private bool _authed = false;

protected override async Task OnInitializedAsync()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = await AccountService.GetAccount(authState);

if (user == null || !user.IsAdmin)
{
NavigationManager.NavigateTo("/");
return;
}

_authed = true;
}
}
File renamed without changes.
File renamed without changes.
9 changes: 7 additions & 2 deletions ReplayBrowser/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Reflection;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using OpenTelemetry.Metrics;
using ReplayBrowser.Data;
Expand All @@ -27,6 +29,11 @@ public Startup(IConfiguration configuration)

public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache(opts =>
{
opts.TrackStatistics = true;
});

services.AddControllersWithViews().AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
Expand Down Expand Up @@ -95,8 +102,6 @@ public void ConfigureServices(IServiceCollection services)
});
});

services.AddMemoryCache();

// Endpoint logging
services.Configure<RequestLoggingOptions>(options =>
{
Expand Down

0 comments on commit 96bfc6c

Please sign in to comment.