Open sandboxFocusImprove this doc

Troubleshooting Metalama Caching

If you need to troubleshoot the caching feature, you can enable verbose logging.

With dependency injection

If your application utilizes dependency injection, add the .NET logging service as usual using the AddLogging extension method. The the AddMetalamaCaching extension method automatically uses logging when available.

Therefore, to troubleshoot caching, just set the minimum caching level to Debug using the SetMinimumLevel method.

The following code snippet illustrates this:

15        // Add logging.
16        builder.ConfigureLogging(
17            logging =>
18                logging.SetMinimumLevel( LogLevel.Debug ) );

Example: Logging of caching with dependency injection

The following is an update to the getting started example, with logging enabled. You can observe detailed logging in the program output.

Source Code
1using Metalama.Patterns.Caching.Aspects;
2using System;

3

4namespace Doc.Logging;

5
6public sealed class CloudCalculator
7{
8    public int OperationCount { get; private set; }
9
10    [Cache]
11    public int Add( int a, int b )
12    {
13        Console.WriteLine( "Doing some very hard work." );
14










15        this.OperationCount++;
16
17        return a + b;
18    }
19}
Transformed Code
1using Metalama.Patterns.Caching;
2using Metalama.Patterns.Caching.Aspects;
3using Metalama.Patterns.Caching.Aspects.Helpers;
4using System;
5using System.Reflection;
6
7namespace Doc.Logging;
8
9public sealed class CloudCalculator
10{
11    public int OperationCount { get; private set; }
12
13    [Cache]
14    public int Add(int a, int b)
15    {
16        static object? Invoke(object? instance, object?[] args)
17        {
18            return ((CloudCalculator)instance).Add_Source((int)args[0], (int)args[1]);
19        }
20
21        return _cachingService.GetFromCacheOrExecute<int>(_cacheRegistration_Add, this, new object[] { a, b }, Invoke);
22    }
23
24    private int Add_Source(int a, int b)
25    {
26        Console.WriteLine("Doing some very hard work.");
27
28        this.OperationCount++;
29
30        return a + b;
31    }
32
33    private static readonly CachedMethodMetadata _cacheRegistration_Add;
34    private ICachingService _cachingService;
35
36    static CloudCalculator()
37    {
38        _cacheRegistration_Add = CachedMethodMetadata.Register(typeof(CloudCalculator).GetMethod("Add", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(int), typeof(int) }, null).ThrowIfMissing("CloudCalculator.Add(int, int)"), new CachedMethodConfiguration() { AbsoluteExpiration = null, AutoReload = null, IgnoreThisParameter = null, Priority = null, ProfileName = (string?)null, SlidingExpiration = null }, false);
39    }
40
41    public CloudCalculator(ICachingService? cachingService = null)
42    {
43        this._cachingService = cachingService ?? throw new System.ArgumentNullException(nameof(cachingService));
44    }
45}
1using System;
2using Metalama.Documentation.Helpers.ConsoleApp;
3
4namespace Doc.Logging;
5
6public sealed class ConsoleMain : IConsoleMain
7{
8    private readonly CloudCalculator _cloudCalculator;
9
10    public ConsoleMain( CloudCalculator cloudCalculator )
11    {
12        this._cloudCalculator = cloudCalculator;
13    }
14
15    public void Execute()
16    {
17        for ( var i = 0; i < 3; i++ )
18        {
19            var value = this._cloudCalculator.Add( 1, 1 );
20            Console.WriteLine( $"CloudCalculator returned {value}." );
21        }
22
23        Console.WriteLine(
24            $"In total, CloudCalculator performed {this._cloudCalculator.OperationCount} operation(s)." );
25    }
26}
Processing invocation of method Int32 Add(Int32, Int32): Starting
Key="Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)".
GetItem( backend = "{MemoryCachingBackend Id=27718499-55d6-4a98-96ad-3c122582f5e2, Status=Default}" key = "Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)" ): Starting
GetItem( backend = "{MemoryCachingBackend Id=27718499-55d6-4a98-96ad-3c122582f5e2, Status=Default}" key = "Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)" ): Succeeded, result = Cache miss.
Cache miss: Key="Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)".
Doing some very hard work.
SetItem( backend = "{MemoryCachingBackend Id=27718499-55d6-4a98-96ad-3c122582f5e2, Status=Initialized}" key = "Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)" ): Starting
SetItem( backend = "{MemoryCachingBackend Id=27718499-55d6-4a98-96ad-3c122582f5e2, Status=Initialized}" key = "Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)" ): Succeeded
Processing invocation of method Int32 Add(Int32, Int32): Succeeded
CloudCalculator returned 2.
Processing invocation of method Int32 Add(Int32, Int32): Starting
Key="Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)".
GetItem( backend = "{MemoryCachingBackend Id=27718499-55d6-4a98-96ad-3c122582f5e2, Status=Initialized}" key = "Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)" ): Starting
GetItem( backend = "{MemoryCachingBackend Id=27718499-55d6-4a98-96ad-3c122582f5e2, Status=Initialized}" key = "Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)" ): Succeeded, result = Cache hit.
Cache hit: Key="Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)".
Processing invocation of method Int32 Add(Int32, Int32): Succeeded
CloudCalculator returned 2.
Processing invocation of method Int32 Add(Int32, Int32): Starting
Key="Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)".
GetItem( backend = "{MemoryCachingBackend Id=27718499-55d6-4a98-96ad-3c122582f5e2, Status=Initialized}" key = "Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)" ): Starting
GetItem( backend = "{MemoryCachingBackend Id=27718499-55d6-4a98-96ad-3c122582f5e2, Status=Initialized}" key = "Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)" ): Succeeded, result = Cache hit.
Cache hit: Key="Doc.Logging.CloudCalculator.Add(this={Doc.Logging.CloudCalculator}, (int) 1, (int) 1)".
Processing invocation of method Int32 Add(Int32, Int32): Succeeded
CloudCalculator returned 2.
In total, CloudCalculator performed 1 operation(s).
1using Metalama.Documentation.Helpers.ConsoleApp;
2using Metalama.Patterns.Caching.Building;
3using Microsoft.Extensions.DependencyInjection;
4using Microsoft.Extensions.Logging;
5
6namespace Doc.Logging;
7
8internal static class Program
9{
10    public static void Main()
11    {
12        var builder = ConsoleApp.CreateBuilder();
13
14        // 
15        // Add logging.
16        builder.ConfigureLogging(
17            logging =>
18                logging.SetMinimumLevel( LogLevel.Debug ) );
19        // 
20
21        // Add the caching service.
22        builder.Services.AddMetalamaCaching();
23
24        // Add other components as usual, then run the application.
25        builder.Services.AddConsoleMain<ConsoleMain>();
26        builder.Services.AddSingleton<CloudCalculator>();
27
28        using var app = builder.Build();
29        app.Run();
30    }
31}

Without dependency injection

The CachingService object and other components of Metalama Caching acquire the IFlashtraceLoggerFactory interface through the IServiceProvider. To enable logging, you must provide an implementation of IServiceProvider that supports the IFlashtraceLoggerFactory interface. Then, pass this IServiceProvider to the CachingService.Create method. You can use the TraceSourceLoggerFactory class, which relies on the TraceSource system class.

If you plan to implement the IFlashtraceLoggerFactory yourself, you may find the SimpleFlashtraceLogger useful.