Add feature-usage tracking and dashboard charts
Instruments FeatureEvaluationService with System.Diagnostics.Metrics (Counter + IMeterFactory). Accumulates per-feature/day evaluation counts in-process, flushed every 30s to a new FeatureUsageDaily Postgres table via PostgreSQL ON CONFLICT upsert. Caches dashboard query results for 180s in IMemoryCache. New GET /api/v1/environments/{id}/usage endpoint returns top-10 features last day and 14-day per-day breakdown. Admin dashboard shows two ApexCharts bar charts: top features and evaluations by day with per-flag hover tooltip.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
using System.Diagnostics.Metrics;
|
||||
using MicCheck.Api.Data;
|
||||
using MicCheck.Api.Features;
|
||||
using MicCheck.Api.Identities;
|
||||
using MicCheck.Api.Segments;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using AppEnvironment = MicCheck.Api.Environments.Environment;
|
||||
|
||||
@@ -14,6 +16,7 @@ public class FeatureEvaluationServiceTests
|
||||
{
|
||||
private MicCheckDbContext _db = null!;
|
||||
private FeatureEvaluationService _service = null!;
|
||||
private FeatureUsageMetrics _usageMetrics = null!;
|
||||
private const int EnvironmentId = 1;
|
||||
private const int ProjectId = 1;
|
||||
|
||||
@@ -25,14 +28,22 @@ public class FeatureEvaluationServiceTests
|
||||
.Options;
|
||||
_db = new MicCheckDbContext(options);
|
||||
|
||||
var meterFactory = new Mock<IMeterFactory>();
|
||||
meterFactory.Setup(f => f.Create(It.IsAny<MeterOptions>())).Returns(new Meter("test"));
|
||||
_usageMetrics = new FeatureUsageMetrics(meterFactory.Object);
|
||||
|
||||
var cache = new FlagCache(new MemoryCache(new MemoryCacheOptions()));
|
||||
_service = new FeatureEvaluationService(_db, new SegmentEvaluator(), cache);
|
||||
_service = new FeatureEvaluationService(_db, new SegmentEvaluator(), cache, _usageMetrics);
|
||||
|
||||
SeedBaseData();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown() => _db.Dispose();
|
||||
public void TearDown()
|
||||
{
|
||||
_db.Dispose();
|
||||
_usageMetrics.Dispose();
|
||||
}
|
||||
|
||||
private void SeedBaseData()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user