JobActivatorScope.Current is null in ILogProvider

We’re trying to add logging correlation to our hangfire background processes. For this we need a context where we can store the correlation ID (or use as the scope for our DI container). The JobActivatorScope.Current looks perfect and works well within the job’s run action, but when a job fails we need to log the error with a custom logger configured using HangfireLogProvider.SetCurrentLogProvider(…). Within our custom logger JobActivatorScope.Current is always null. We need to get the correlation ID for the task that failed to include it in our log.

Our configuration is:
public void Configuration(IAppBuilder app)
{
var kernel = new StandardKernel();
app.UseNinjectMiddleware(() => kernel)
GlobalConfiguration.Configuration.UseNinjectActivator(kernel);
HangfireLogProvider.SetCurrentLogProvider(new CustomLogProvider(() => kernel.Get<ILogger>()));
//… Other config to set standard hangfire options …
app.UseHangfireServer(options);
}

Inside of our job execution everything is fine
public void InternalRunAction(IJobCancellationToken cancellationToken, string identifier, T message, PerformContext context)
{
var debug = Hangfire.JobActivatorScope.Current; //Works perfectly!
}

But if something goes wrong inside our job the logger can’t see the scope:

public class CustomLogProvider : ILogProvider
{
private readonly Func<ILogger> loggerFunc;

    internal CustomLogProvider(Func<ILogger<CustomLogProvider>> loggerFunc)
    {
        this.loggerFunc = loggerFunc ?? throw new ArgumentNullException(nameof(loggerFunc));
    }

    public ILog GetLogger(string name)
    {
        return new CustomLog(loggerFunc, name);
    }


    private class CustomLog : ILog
    {
        private readonly Func<ILogger<CustomLogProvider>> loggerFunc;

        private ILogger<CustomLogProvider> Logger
        {
            get
            {
                return loggerFunc();
            }
        }

        public CustomLog(Func<ILogger<CustomLogProvider>> loggerFunc, string name)
        {
            this.loggerFunc = loggerFunc ?? throw new ArgumentNullException(nameof(loggerFunc));
        }

        public bool Log(LogLevel logLevel, Func<string> messageFunc, Exception exception = null)
        {
            if (messageFunc != null)
            {
                var debug = Hangfire.JobActivatorScope.Current; //ALWAYS NULL, SO NINJECT RESOLVES A NEW ILOGGER!
                ...
            }
        }

We need some sort of context in the custom logger that isn’t null and is consistent with the context in which the job executed. Any help / alternatives we could try would be much appreciated! Thanks.

1 Like