Skip to content

Add built-in OpenTelemetry metrics to MemoryCache#126146

Merged
cincuranet merged 2 commits into
dotnet:mainfrom
rjmurillo:feature/memory-cache-metrics
Mar 30, 2026
Merged

Add built-in OpenTelemetry metrics to MemoryCache#126146
cincuranet merged 2 commits into
dotnet:mainfrom
rjmurillo:feature/memory-cache-metrics

Conversation

@rjmurillo

@rjmurillo rjmurillo commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds OpenTelemetry metrics to MemoryCache. Follows the System.Net.Http pattern (#87319).

Fixes #124140

API Changes

Microsoft.Extensions.Caching.Abstractions

public class MemoryCacheStatistics
{
    public long TotalEvictions { get; init; } // NEW
}

Microsoft.Extensions.Caching.Memory

public class MemoryCacheOptions
{
    public string Name { get; set; } = "Default"; // NEW
}

public class MemoryCache
{
    // ILoggerFactory now nullable
    public MemoryCache(IOptions<MemoryCacheOptions> optionsAccessor, ILoggerFactory? loggerFactory);

    // NEW
    public MemoryCache(IOptions<MemoryCacheOptions> optionsAccessor, ILoggerFactory? loggerFactory, IMeterFactory? meterFactory);
}

Instruments

Meter: Microsoft.Extensions.Caching.Memory.MemoryCache

Instrument Type Dimensions
cache.requests ObservableCounter<long> cache.name, cache.request.type (hit/miss)
cache.evictions ObservableCounter<long> cache.name
cache.entries ObservableUpDownCounter<long> cache.name
cache.estimated_size ObservableGauge<long> cache.name

Design

  • Gated on TrackStatistics — no instruments created unless TrackStatistics = true
  • SharedMeter fallback — no IMeterFactory, no problem. Singleton SharedMeter with NOP Dispose. Same pattern as System.Net.Http.MetricsHandler.SharedMeter
  • MeterOptions tags — factory path sets Tags = [new("cache.name", _options.Name)] for meter deduplication in DefaultMeterFactory
  • WeakReference callbacks — observable callbacks capture WeakReference<MemoryCache>. Dead caches return empty measurements. No GC leaks
  • IEnumerable overloadsFunc<IEnumerable<Measurement<long>>> prevents phantom zero measurements from disposed or collected caches
  • Eviction countingRemoveEntry calls ConcurrentDictionary.TryRemove(KVP). Only the thread that removes the entry increments TotalEvictions. No double-counting
  • DI unchanged — new constructor auto-selected. No changes to MemoryCacheServiceCollectionExtensions
  • Conditional DiagnosticSource ref — in-box for net11.0+

Tests

  • 142 tests pass (net11.0)
  • 11 new metrics tests: instrument creation, SharedMeter fallback, null factory/logger, TrackStatistics gate, Name property, eviction accuracy, disposed cache, MeterOptions tags, over-count prevention
  • 2 new eviction statistics tests

Copilot AI review requested due to automatic review settings March 26, 2026 04:35
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Mar 26, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-caching
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds built-in OpenTelemetry metrics support to Microsoft.Extensions.Caching.Memory.MemoryCache by exposing additional cache statistics and wiring them into observable instruments, gated by MemoryCacheOptions.TrackStatistics.

Changes:

  • Added TotalEvictions to MemoryCacheStatistics and tracked eviction counts in MemoryCache.
  • Introduced MemoryCacheOptions.Name and new MemoryCache ctor overload supporting IMeterFactory.
  • Added unit tests for metrics publication and eviction statistics, plus conditional DiagnosticSource references for non-inbox TFMs.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs Implements eviction counting and publishes OTEL observable instruments via Meter/IMeterFactory.
src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCacheOptions.cs Adds Name option used as a metrics dimension.
src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj Adds conditional DiagnosticSource reference for TFMs missing in-box metrics types.
src/libraries/Microsoft.Extensions.Caching.Memory/ref/Microsoft.Extensions.Caching.Memory.cs Updates public API surface for new ctor overload and Name option.
src/libraries/Microsoft.Extensions.Caching.Memory/tests/MemoryCacheMetricsTests.cs Adds tests validating instrument creation and basic measurements.
src/libraries/Microsoft.Extensions.Caching.Memory/tests/MemoryCacheGetCurrentStatisticsTests.cs Adds tests for eviction statistics behavior.
src/libraries/Microsoft.Extensions.Caching.Memory/tests/Microsoft.Extensions.Caching.Memory.Tests.csproj Adds conditional DiagnosticSource project reference for .NETFramework tests.
src/libraries/Microsoft.Extensions.Caching.Abstractions/src/MemoryCacheStatistics.cs Adds TotalEvictions to the statistics snapshot type.
src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.cs Updates ref assembly for TotalEvictions.

Comment thread src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs Outdated
Comment thread src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs Outdated
Comment thread src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs Outdated
Comment thread src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs Outdated
@cincuranet cincuranet self-assigned this Mar 26, 2026
@rjmurillo rjmurillo force-pushed the feature/memory-cache-metrics branch from 2d7d40d to f3ef1c4 Compare March 26, 2026 13:08
@rjmurillo rjmurillo marked this pull request as draft March 26, 2026 13:25

@cincuranet cincuranet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the _accumulatedEvictions comments from Copilot, I think the idea with bool return is sound.

Or maybe putting the logic into RemoveEntry - given there's already _cacheSize handling - with a flag whether to count or not (not all RemoveEntry calls (should) update _accumulatedEvictions).

Up to you.

Comment thread src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs Outdated
Comment thread src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs Outdated
Copilot AI review requested due to automatic review settings March 26, 2026 14:34
@rjmurillo rjmurillo force-pushed the feature/memory-cache-metrics branch from f3ef1c4 to 98aa196 Compare March 26, 2026 14:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Comment thread src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs Outdated
Implements dotnet#124140. Adds observable OTEL instruments for
cache requests (hit/miss), evictions, entry count, and estimated size.

Key design decisions:
- MeterOptions with cache.name tag for per-cache meter deduplication
- WeakReference<MemoryCache> in observable callbacks to prevent GC leaks
- RemoveEntry returns bool for accurate eviction counting
- IEnumerable<Measurement<long>> overloads to avoid phantom zero measurements
- No instruments without IMeterFactory (GetCurrentStatistics still works)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 27, 2026 16:43
@rjmurillo rjmurillo force-pushed the feature/memory-cache-metrics branch from c4b258a to eace3f4 Compare March 27, 2026 16:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

@cincuranet cincuranet marked this pull request as ready for review March 30, 2026 07:41
Copilot AI review requested due to automatic review settings March 30, 2026 07:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

@ManickaP ManickaP left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@cincuranet cincuranet merged commit e1d19fe into dotnet:main Mar 30, 2026
94 of 100 checks passed
cincuranet added a commit that referenced this pull request Apr 3, 2026
radekdoulik pushed a commit to radekdoulik/runtime that referenced this pull request Apr 9, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 30, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Caching community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Metrics for M.E.Caching.MemoryCache

4 participants