Як використовувати 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 також має деяку інформацію про це.
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 назад містить небезпечний Html для Mvc4. 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 з кожного окремого - і просто покладіть це у свою власну «System» DLL.
  • Якщо вам коли-небудь потрібно зробити якесь спеціальне оброблення або просто хочете поставити точку перелому для налагодження помилок, у вас це все в одному місці.
  • Якщо ви коли-небудь відійдете від Elmah, ви можете просто змінити одне місце.
  • Якщо у вас є застарілий журнал помилок, який ви хочете зберегти (у мене просто трапляється простий механізм реєстрації помилок, який пов'язаний з деякими інтерфейсами, які я не маю часу видалити).

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


1
Чудова відповідь. Можливо, ELMAH повинен реалізувати щось подібне поза коробкою. Іноді дуже важко налагодити помилку без контексту.
ra00l

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

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

1
Ще краще було б імхо як метод розширення.
Стівен Кеннеді

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". в моєму проекті. Я спробував додати "використання 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
Matthew

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 (). Підвищення (колишній); і виявило, що ці винятки спливають, наприклад:

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.