Как использовать ELMAH для регистрации ошибок вручную


259

Можно ли сделать следующее с помощью ELMAH?

logger.Log(" something");

Я делаю что-то вроде этого:

try 
{
    // Code that might throw an exception 
}
catch(Exception ex)
{
    // I need to log error here...
}

Это исключение не будет автоматически зарегистрировано ELMAH, потому что оно было обработано.


1
Для дальнейшего использования, я написал пост о том, что именно: Регистрация ошибок программно . В моем ELMAH Tutorial также есть некоторая информация об этом.
ThomasArdal

Ответы:


412

Метод прямой записи журнала, работающий с ELMAH 1.0:

try 
{
    some code 
}
catch(Exception ex)
{
    Elmah.ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
}

ELMAH 1.2 представляет более гибкий API:

try 
{
    some code 
}
catch(Exception ex)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}

Существует разница между двумя решениями:

  • RaiseМетод применяет правила фильтрации ELMAH к исключению. Logметод не.
  • Raise основан на подписке и может регистрировать одно исключение в нескольких регистраторах.

1
В чем разница между вашим методом и другими?
Ому

3
Они регистрируют ошибку в Elmah, не заставляя приложение перестать работать. Это позволяет вам отлавливать распространенные исключения, обрабатывать их правильно, но при этом иметь возможность регистрировать их.
PCasagrande

7
Я обнаружил, что Elmah.ErrorSignal не регистрируется, когда POST back содержит небезопасный HTML для Mvc4 .Net 4.5, в моем примере это POST обратно из Windows Access Control Services с SignInResponseMessage. Elmah.ErrorLog.GetDefault работал в этом сценарии
Адам

1
У меня была такая же проблема с небезопасным HTML. ErrorLog.GetDefault добились цели
hgirish

4
Одно большое предостережение при использовании Elmah.ErrorLog.Log(): оно выдает в случае сбоя самого вызова журнала, что может привести к выходу из строя всего веб-приложения. Raise()молчит Например: если на стороне сервера возникла проблема с неправильной настройкой (например, Elmah настроен на сохранение ошибок на диск, но не имеет правильного доступа к папке журналов), .Log()метод будет выброшен. (Хотя это хорошо для отладки, например, почему ничего не .Raise()регистрируется?)
Кристиан Диаконеску,

91

Я бы порекомендовал обернуть звонок в Elmah в свой собственный простой класс-обертку.

using Elmah;

public static class ErrorLog
{
    /// <summary>
    /// Log error to Elmah
    /// </summary>
    public static void LogError(Exception ex, string contextualMessage=null)
    {
        try
        {
            // log error to Elmah
            if (contextualMessage != null) 
            {
                // log exception with contextual information that's visible when 
                // clicking on the error in the Elmah log
                var annotatedException = new Exception(contextualMessage, ex); 
                ErrorSignal.FromCurrentContext().Raise(annotatedException, HttpContext.Current);
            }
            else 
            {
                ErrorSignal.FromCurrentContext().Raise(ex, HttpContext.Current);
            }

            // send errors to ErrorWS (my own legacy service)
            // using (ErrorWSSoapClient client = new ErrorWSSoapClient())
            // {
            //    client.LogErrors(...);
            // }
        }
        catch (Exception)
        {
            // uh oh! just keep going
        }
    }
}

Тогда просто звоните, когда вам нужно записать ошибку.

try {
   ...
} 
catch (Exception ex) 
{
    // log this and continue
    ErrorLog.LogError(ex, "Error sending email for order " + orderID);
}

Это имеет следующие преимущества:

  • Вам не нужно помнить этот слегка архаичный синтаксис вызова Elmah
  • Если у вас много DLL, вам не нужно ссылаться на Elmah Core из каждой отдельной библиотеки - и просто поместите это в свою собственную «Системную» DLL.
  • Если вам когда-либо понадобится выполнить какую-либо специальную обработку или просто захотите поставить точку останова для отладки ошибок, у вас все это в одном месте.
  • Если вы когда-нибудь отойдете от Эльмы, вы можете просто поменять одно место.
  • Если у вас есть устаревшая регистрация ошибок, которую вы хотите сохранить (у меня просто есть простой механизм регистрации ошибок, связанный с некоторыми пользовательскими интерфейсами, которые я не могу сразу удалить).

Примечание. Я добавил свойство contextualMessage для контекстной информации. Вы можете опустить это, если хотите, но я нахожу это очень полезным. Elmah автоматически разворачивает исключения, поэтому основное исключение все равно будет отображаться в журнале, но contextualMessage будет виден, когда вы щелкнете по нему.


1
Отличный ответ. Может быть, ELMAH должен реализовать нечто подобное из коробки. Иногда действительно сложно отладить ошибку без контекста.
ra00l

2
Я люблю все, кроме глотания любых вторичных ошибок с // uh oh! just keep going. Если моя обработка ошибок терпит неудачу, я хочу знать. Я хочу, чтобы это шуметь.
Джереми Кук

3
@JeremyCook Я согласен, но с оговоркой, что, если вы не будете осторожны, подпрограммы обработки ошибок, как правило, заканчивают тем, что вызывают себя, а затем взрываются (о, и я также фактически вызывал сторонний API для регистрации ошибки). Я, вероятно, не должен был оставлять это для этого ответа, но у меня был плохой опыт, когда подобное происходило раньше
Simon_Weaver

1
Было бы еще лучше imho в качестве метода расширения.
Стивен Кеннеди

1
Вы можете подумать: нет, сколько ошибок я мог бы попытаться войти? Я думал об этом около года назад. Короче говоря: используйте эту обертку!
nmit026

29

Вы можете использовать метод Elmah.ErrorSignal (), чтобы зарегистрировать проблему, не вызывая исключения.

try
{
    // Some code
}
catch(Exception ex)
{
    // Log error
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);

    // Continue
}


14

Да, это возможно. ELMAH был разработан для перехвата необработанных исключений. Однако вы можете сообщить об исключении в ELMAH через класс ErrorSignal. Эти исключения не генерируются (не всплывают), а отправляются только в ELMAH (и подписчикам события Raise класса ErrorSignal).

Небольшой пример:

protected void ThrowExceptionAndSignalElmah()
{
    ErrorSignal.FromCurrentContext().Raise(new NotSupportedException());
}

13

Я пытался сделать то же самое в потоке, который я начал помещать в очередь почты из моего приложения MVC4, так как у меня не было HttpContext, доступного при возникновении исключения. Чтобы сделать это, я получил следующее основанное на этом вопросе и другой ответ, найденный здесь: elmah: исключения без HttpContext?

В конфигурационном файле я указал имя приложения:

<elmah>
    <security allowRemoteAccess="false" />
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" applicationName="myApplication"/>   
</elmah>

Затем в коде (как ответ, приведенный выше, но без HttpContext) вы можете передать значение null вместо HttpContext:

ThreadPool.QueueUserWorkItem(t => {
     try {
         ...
         mySmtpClient.Send(message);
     } catch (SomeException e) {
         Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(e));
     }
 });

Мне нравится ваше решение; однако я не могу разрешить "Эльму". в моем проекте. Я попытался добавить "использование Elmah;" в моем коде, но он не существует в моем текущем контексте.
Taersious

@Taersious Как ты packages.configвыглядишь? Вы видите что - то вроде: <package id="elmah" version="1.2.2" targetFramework="net45" /> <package id="elmah.corelibrary" version="1.2.2" targetFramework="net45" /> <package id="elmah.sqlserver" version="1.2" targetFramework="net45" />'? Вы устанавливали с NuGET?
Матфея

Я хотел бы сказать да, но мой проект в настоящее время заблокирован в системе контроля версий. Я реализовал elmah вручную из примера файла конфигурации в проекте.
Taersious

@Taersious Если вы делаете это вручную, вы добавили ссылку Elmah в проект, прежде чем вызывать использование ... Я ожидаю, что это будет работать в любом случае, но я знаю, что когда nuget добавляет его, строки выше добавляются вpackages.config
Мэтью

3

Иногда CurrentHttpContextможет быть недоступно.

определять

public class ElmahLogger : ILogger
{
    public void LogError(Exception ex, string contextualMessage = null, bool withinHttpContext = true)
    {
        try
        {
            var exc = contextualMessage == null 
                      ? ex 
                      : new ContextualElmahException(contextualMessage, ex);
            if (withinHttpContext)
                ErrorSignal.FromCurrentContext().Raise(exc);
            else
                ErrorLog.GetDefault(null).Log(new Error(exc));
        }
        catch { }
    }
}

использование

public class MyClass
{
    readonly ILogger _logger;

    public MyClass(ILogger logger)
    {
        _logger = logger;
    }

    public void MethodOne()
    {
        try
        {

        }
        catch (Exception ex)
        {
            _logger.LogError(ex, withinHttpContext: false);
        }
    }
}

2

Я использую ядро ASP.NET и использую ElmahCore .

Чтобы вручную регистрировать ошибки с помощью HttpContext (в контроллере), просто напишите:

using ElmahCore;
...
HttpContext.RiseError(new Exception("Your Exception"));

В другой части вашего приложения без HttpContext :

using ElmahCore;
...
ElmahExtensions.RiseError(new Exception("Your Exception"));

0

Я пытался записать пользовательские сообщения в журналы elmah, используя Signal.FromCurrentContext (). Raise (ex); и обнаружил, что эти исключения всплывают, например:

try
{
    ...
}
catch (Exception ex)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
    // this will write to the log AND throw the exception
}

Кроме того, я не понимаю, как elmah поддерживает разные уровни ведения журнала - возможно ли отключить подробное ведение журнала настройкой web.config?


1
Если вы перехватываете исключение и не генерируете его снова, исключения не всплывают. Может быть, я неправильно понимаю? ELMAH не поддерживает разные уровни ведения журнала. Это только для ошибок.
ThomasArdal

Спасибо, Томас. Это именно то, что я пытался подтвердить
Валерий Гаврилов

0

Использовал эту строчку и она отлично работает.

 try{
            //Code which may throw an error
    }
    catch(Exception ex){
            ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.