FusionCache.AppMetrics is a plugin to capture caching metrics using FusionCache
Metrics are missing from open-source resiliency projects in the .NET ecosystem where in equivalent Java libraries, metrics tend to be common. FusionCache is a feature rich caching library addressing resiliency needs of today’s enterprise implementations. Appmetrics is an easy-to-use metrics library that works in .NET Framework and .NET Core. Joining these two excellent libraries together you can easily be caching and writing metrics to your favorite timeseries database.
var hostNameCache = new MemoryCache(new MemoryCacheOptions());
var appMetricsContextLabel = "MyApplication";
var appMetrics = new MetricsBuilder()
.Configuration.Configure(
options =>
{
options.DefaultContextLabel = appMetricsContextLabel;
})
.Report
.ToInfluxDb(
options =>
{
var filter = new MetricsFilter();
filter.WhereContext(c => c == appMetricsContextLabel); //remove default AppMetrics metrics.
options.InfluxDb.BaseUri = new Uri($"http://{ Configuration["InfluxDbConfig.Host"] }:{ Configuration["InfluxDbConfig.Port"] }");
options.InfluxDb.Database = Configuration["InfluxDbConfig.Database"];
options.InfluxDb.RetentionPolicy = Configuration["InfluxDbConfig.RetentionPolicy"];
options.InfluxDb.UserName = Configuration["InfluxDbConfig.Username"];
options.InfluxDb.Password = Configuration["InfluxDbConfig.Password"];
options.InfluxDb.CreateDataBaseIfNotExists = false;
options.MetricsOutputFormatter = new MetricsInfluxDbLineProtocolOutputFormatter(
new MetricsInfluxDbLineProtocolOptions
{
MetricNameFormatter = (metricContext, metricName) => $"{appMetricsContextLabel}_{metricContext}"
});
})
// .Report.ToTextFile(
// options => {
// options.MetricsOutputFormatter = new MetricsJsonOutputFormatter();
// options.AppendMetricsToTextFile = true;
// // options.Filter = filter;
// options.FlushInterval = TimeSpan.FromSeconds(20);
// options.OutputPathAndFileName = @"C:\temp\metrics.txt";
// })
.Build();
//
// Cache called "domain"
//
// Register AppMetricsProvider as a IFusionCachePlugin.
// Note that a MemoryCache object must be created outside of AddFusionCache extension method so that
// AppMetricsProvider is holding the same object as FusionCache to enabled cache count reporting.
// See line 180 in FusionCacheEventSource.cs
//
services.AddSingleton<IMemoryCache>(hostNameCache);
services.AddSingleton<IFusionCachePlugin>(new AppMetricsProvider("domain", appMetrics, hostNameCache));
services.AddFusionCache(options =>
options.DefaultEntryOptions = new FusionCacheEntryOptions
{
Duration = TimeSpan.FromSeconds(1),
JitterMaxDuration = TimeSpan.FromMilliseconds(200),
IsFailSafeEnabled = true,
FailSafeMaxDuration = TimeSpan.FromHours(1),
FailSafeThrottleDuration = TimeSpan.FromSeconds(1),
FactorySoftTimeout = TimeSpan.FromMilliseconds(100),
FactoryHardTimeout = TimeSpan.FromSeconds(1)
});
var metricsReporterService = new MetricsReporterBackgroundService(appMetrics, appMetrics.Options, appMetrics.Reporters);
metricsReporterService.StartAsync(CancellationToken.None);
services.AddSingleton(sp => metricsReporterService );
AppMetrics Plugin is an easy to use solution for .NET Framework apps. If you already use AppMetrics then this would be an easy way to go.
There are two example WebApi style projects included:
Metrics plugins are created by subscribing to FusionCache Events.
MetricsConfig
contains the following properties and can be overriden by adding a CacheMetrics
section to appsettings.json.
-
ApplicationName
is defaulted to the executing assembly name. -
ApplicationVersion
is defaulted to the executing assembly version. -
Prefix
is defaulted to "appMetrics" -
MeasurementName
is defaulted to "Cache-Events"see Examples for usage
The following Events are subscribed to. Each event includes a Tag named "cacheEvent" and a tag value. Both the "cacheEvent" name and Tag values are defined in the SemanticConventions
class. These conventions can be changed by implementing a new ISemanticConventions
interface and registering in you dependency injection framework. Tags are typical in time series databases and are indexed making them friendly to searching and grouping over time.
The following counters all set AppMetrics's CounterOptions for ResetOnReporting to true. The effect is each time a reporter queries the counter it will be reset. All the following counters accept the CacheCountIncrement and CacheCountDecrement set ResetOnReporting to true.
The cache tag is "HIT". Every cache hit will increment a counter.
The cache tag is "MISS". Every cache miss will increment a counter.
The cache tag is "STALE_HIT". When FailSafe is enabled and a request times out due to a "soft timeout" and a stale cache item exists then increment a counter. Note this will not trigger the CacheMiss() counter.
The cache tag is "STALE_REFRESH". When FailSafe is enabled and a request times out due to a "soft timeout" the request will continue for the length of a "hard timeout". If the request finds data it will call this CacheBackgroundRefresh() and increment a counter. Note it would be normal for this counter and CacheStaleHit() to track with eachother.
The cache tag is "REMOVE". When the cache is removed by user code.
Eviction counters are wired into the ICacheEntries with the PostEvictionDelegate.
The cache tag is "EXPIRE". When the EvictionReason is Expired increment a counter.
The cache tag is "CAPACITY". When the EvictionReason is Capacity increment a counter.
The cach tag is "ITEM_COUNT". Calls the MemoryCache.Count
For this feature MemoryCache
must be created and passed to FusionCache
and AppMetricsProvider
so they share the same intance of MemoryCache