Pierre Henry
Pierre Henry

Reputation: 63

TelemetryConfiguration circular dependency with a custom ITelemetryInitializer - Application Insights ASP.NET Core 5.0

I'm trying to implement a custom ITelemetryInitializer (UserTelemetryInitialiser) that attaches some user metadata to app insights messages, and I'm getting the following circular dependency.

UserTelemetryInitialiser goes to a users cache that depends on IMemoryCache as implemented by Microsoft.Extensions.Caching.Memory.MemoryCache. MemoryCache is then dependent on ILoggerFactory (implemented by Microsoft.Extensions.Logging.LoggerFactory) and LoggerFactory eventually depends on TelemetryConfiguration.

So I have this (shortened) circular chain: TelemetryConfiguration -> UserTelemetryInitialiser -> MyUserCache -> MemoryCache -> LoggerFactory -> TelemetryConfiguration.

Any ideas on how to resolve this?

I'm using ASP.NET Core 5.0 with Microsoft.ApplicationInsights.AspNetCore 2.18.0.

EDIT: My simplified initializer looks like this (where IHttpContextAccessor is used to get the user identity):

   public class UserTelemetryInitialiser : ITelemetryInitializer
   {
       private readonly IHttpContextAccessor contextAccessor;
       private readonly IMemoryCache cache;

        public UserTelemetryInitialiser(IHttpContextAccessor contextAccessor,  IMemoryCache cache)
        {
            this.contextAccessor = contextAccessor;
            this.cache = cache;
        }
        public void Initialize(ITelemetry telemetry)
        {
        }
    }

Upvotes: 0

Views: 862

Answers (1)

mhaslhofer
mhaslhofer

Reputation: 141

Problem Root

The problem with Injecting IMemoryCache into a ITelemetryInitializer when using dependency-injection, is, that calling services.AddApplicationInsightsTelemetry() registers a ApplicationInsightsLoggerProvider for the LoggerFactory.

Since the default implementation of IMemoryCache (MemoryCache) has a dependency on a ILogger, and this requires a LoggerFactory which now in turn depends on ApplicationInsightsLoggerProvider which constructs a TelemetryClient and thus depends on all configured ITelemetryInitializers ... we now have a circular dependency.

Solution A (No logging in MemoryCache within the TelemetryInitializer)

if you are okay with not logging messages from MemoryCache within your TelemetryInitializer, you could configure your TelemetryInitializer simply by providing a Setup-method where you construct a MemoryCache without a Logger (which defaults to using a NullLogger.Instance):

            services.AddSingleton<ITelemetryInitializer>(serviceProvider 
                => new MyTelemetryInitializer(new MemoryCache(optionsAccessor: serviceProvider.GetRequiredService<IOptions<MemoryCacheOptions>>())));

Solution B (Remove ApplicationInsightsLoggerProvider from your logging configuration)

for the off-chance, that logging in MemoryCache is more important to you, than having warnings tracked by application insights, you could remove the ApplicationInsightsLoggerProvider from your LoggerFactory:

services.AddApplicationInsightsTelemetry();
services.AddSingleton<ITelemetryInitializer, MyTelemetryInitializer>();

//must be called *after* AddApplicationInsightsTelemetry()
services.AddLogging(loggingBuilder =>
            {
                foreach(var aiLoggingProvider in loggingBuilder.Services.Where(p => p.ImplementationType == typeof(Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider)).ToArray())
                {
                    loggingBuilder.Services.Remove(aiLoggingProvider);
                }
            });

Upvotes: 1

Related Questions