Hangfire integration with Elmah

I was able to get it up and running this morning without using any additional common logging package. I created a custom log provider and with some decompilation of Elmah I was able to work with the ElmahDataProvider in Hangfire to let it perform the logging to the database, but then add some additional code to send the email based on the web.config settings for Elmah. Not ideal, but I felt it was a decent interim solution:

Here are the classes:

using System;
using System.Web;
using Elmah;
using Hangfire.Logging;
using Hangfire.Logging.LogProviders;

namespace API {
    public class HangfireErrorMailModule : Elmah.ErrorMailModule {
        public HangfireErrorMailModule() {
            base.OnInit(HttpContext.Current.ApplicationInstance);
        }

        public void SendEmailAsync(Error error) {
            base.ReportErrorAsync(error);
        }

        public void SendEmail(Error error) {
            base.ReportError(error);
        }
    }

    public class HangfireLogProvider : ElmahLogProvider, ILogProvider {
        private const LogLevel DefaultMinLevel = LogLevel.Warn;
        private readonly HangfireErrorMailModule _mailModule;

        public HangfireLogProvider()
            : this(DefaultMinLevel) {
        }

        public HangfireLogProvider(LogLevel minLevel) : base(minLevel) {
            this._mailModule = new HangfireErrorMailModule();
        }

        public new ILog GetLogger(string name) {
            return new HangfireLogger(
                base.GetLogger(name)
                , Type.GetType("Elmah.Error, Elmah")
                , this._mailModule);
        }
    }

    public class HangfireLogger : ILog {
        private readonly ILog _logger;
        private readonly Type _errorType;
        private readonly HangfireErrorMailModule _mailModule;
        
        public HangfireLogger(ILog logger, Type errorType, HangfireErrorMailModule mailModule) {
            this._logger = logger;
            this._errorType = errorType;
            this._mailModule = mailModule;
        }
        public bool Log(LogLevel logLevel, Func messageFunc, Exception exception = null) {
            var logged = this._logger.Log(logLevel, messageFunc, exception);

            if (messageFunc == null) return logged;

            var message = messageFunc();

            dynamic error = exception == null
                ? Activator.CreateInstance(_errorType)
                : Activator.CreateInstance(_errorType, exception);

            error.Message = message;
            error.Type = logLevel.ToString();
            error.Time = DateTime.UtcNow;
            this._mailModule.SendEmailAsync(error);

            return logged;
        }
    }
}

Here is where I configure Hangfire to use them:

using System;
using Hangfire;
using Hangfire.Dashboard;
using Hangfire.SimpleInjector;
using Hangfire.SqlServer;
using SimpleInjector;

namespace API {
    public class HangfireConfig {
        
        public static BackgroundJobServer SetupBackgroundJobServer(BackgroundJobServer backgroundJobServer, Container container) {
            GlobalConfiguration.Configuration
               .UseSqlServerStorage("HangFire", new SqlServerStorageOptions {
                    QueuePollInterval = TimeSpan.FromSeconds(30)
                    , PrepareSchemaIfNecessary = true
                })
                .UseDashboardMetric(SqlServerStorage.ActiveConnections)
                .UseDashboardMetric(SqlServerStorage.TotalConnections)
                .UseDashboardMetric(DashboardMetrics.EnqueuedAndQueueCount)
                .UseDashboardMetric(DashboardMetrics.ProcessingCount)
                .UseDashboardMetric(DashboardMetrics.FailedCount)
                .UseDashboardMetric(DashboardMetrics.SucceededCount)
                .UseLogProvider(new HangfireLogProvider());
                
            return new BackgroundJobServer(new BackgroundJobServerOptions() {
                Activator = new SimpleInjectorJobActivator(container)
                , WorkerCount = 40
            });
        }
    }
}
1 Like