Hangfire integration with Elmah

There are any way to use Elmah with Hangfire ?

If an exception are throw by a task, Elmah intercept the error but the HttpContext is null and other exception are throwed.

Thanks for any suggestion.

I assume you are using the Common.Logging.Elmah package. Have you tried to set application name for ELMAH configuration as written here?

<errorLog type="Elmah.SqlErrorLog, Elmah" 
          connectionStringName="nibWeb" 
          applicationName="Nib.Services" />

@e_zambrano just curious – does the application name setting work for you?

Just as a side note, the common.logging.elmah nuget package (referenced above) has not been updated to work with common.logging 2.2

I found ElmahCommonLogging to work succesfully.

Awesome, this is the simplest logging tool for web apps and I’m happy to hear that it can be integrated with easy (perhaps there should be a blog post) unlike other more heavy but powerful tools (like NLog, log4net, etc).

Hi Odinserj,

I agree a blog post on showing how to use Elmah and Elmah.Common.Logging, with Hangfire :smile:

I like Elmah dashboard and like all errors going into one place where it is easy to read.

Now add Hangfire + Elmah and now we have a great system.

Does anyone have any complete solutions for this? I have a console application running an OWIN self host and I am trying to implement logging with ELMAH.

I followed the lead from the posts here, http://stackoverflow.com/questions/841451/using-elmah-in-a-console-application. After a few days, I managed to be able to log exceptions with ELMAH (albeit using a try catch in my console application) and im still struggling to see the axd viewer from the OWIN self hosted URL .

Is there a cleaner way to get this to work with Hangfires reflection detection, can anyone share?

This advice seems out of date? The latest documentation says Elmah will be picked up automatically via reflection. Exceptions do get logged to Elmah, however Elmah email notifications are not working. (hhtpcontext issue?)

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