I am trying to use the Hangfire Filter and ILogger.BeginScope to log the correlation id. The requirement is that each job execution will have its own correlation id so that it's easier to group the logs of the same job execution together if something happens.
My approach is that in IServerFilter.OnPerforming
method, I first create a GUID, then using below code to begin the scope
logger.BeginScope(new FormattedDictionary<string, object>
{
["CorrelationId"] = correlationId
})
The subsequent log statements in the method IServerFilter.OnPerforming
will have correlation id attached. But unfortunately, during job execution, the log statement won't have the correlation id scope. The ILogger
instance of the job class is resolved using constructor. And the ILogger
instance of the method IServerFilter.OnPerforming
is resolved using a IServiceProvider.GetRequiredService
method
I am wondering why so? And how can we fix this issue? I am open to other approaches of implementing logging correlation id as long as it works.
Finally figured it out. The reason being that when the local IDisposable
in IServerFilter.OnPerforming
created by a local ILogger
instance are out of scope, since nothing reference it again, after a while, GC will collect it and thus the locally created scope will be lost. The solution is simple, using AsyncLocal<ILogger>
instance on the filter to hold a reference to the created scope and only dispose it after the job finishes