Hataları manuel olarak kaydetmek için ELMAH nasıl kullanılır


259

ELMAH kullanarak aşağıdakileri yapmak mümkün mü?

logger.Log(" something");

Ben böyle bir şey yapıyorum:

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

Bu istisna, ele alındığı için ELMAH tarafından otomatik olarak kaydedilmez.


1
Gelecekte başvurmak üzere, tam olarak bunun hakkında bir yazı yazdım: Hataları programlı olarak günlüğe kaydetme . Benim ELMAH Eğitimi de bu konuda bazı bilgiler var.
ThomasArdal

Yanıtlar:


412

ELMAH 1.0'dan beri çalışan doğrudan günlük yazma yöntemi:

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

ELMAH 1.2 daha esnek bir API sunar:

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

İki çözüm arasında bir fark vardır:

  • Raiseyöntemi istisna ELMAH filtreleme kurallarını uygular. Logyöntem değildir.
  • Raise abonelik tabanlıdır ve birkaç günlük dosyasına bir istisna kaydedebilir.

1
yönteminiz ve diğerleri arasındaki fark nedir?
Omu

3
Bunlar, uygulamanın durmasına neden olmadan Elmah'daki hatayı günlüğe kaydeder. Yaygın istisnaları yakalamanıza, düzgün bir şekilde işlemenize izin verir, ancak yine de bunları kaydedebilirsiniz.
PCasagrande

7
Elmah.ErrorSignal POST geri Mvc4 .Net 4.5 için güvenli olmayan Html, benim örneğimde bir SignInResponseMessage ile Windows Erişim Denetim Hizmetleri'nden bir POST içerdiğinde günlüğe kaydetmedi bulundu. Elmah.ErrorLog.GetDefault bu senaryoda çalıştı
Adam

1
Güvenli olmayan Html ile aynı sorunu yaşadım. ErrorLog.GetDefault hile yaptı
hgirish

4
Kullanırken büyük bir uyarı Elmah.ErrorLog.Log(): günlük çağrısının başarısız olması durumunda, tüm web uygulamasını indirir. Raise()sessizce başarısız olur. Örneğin: sunucu tarafında bir yanlış yapılandırma sorunu varsa (örn. Elmah hataları diske kaydetmek üzere yapılandırılmıştır, ancak günlükler klasörüne doğru erişime sahip değilse) .Log()yöntem atar. (Bu hata ayıklamak için iyidir, örneğin neden .Raise()hiçbir şey
kaydetmiyor

91

Elmah'a yaptığınız çağrıyı kendinize ait basit bir sarmalayıcı sınıfına almanızı tavsiye ederim.

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
        }
    }
}

Ardından, bir hata günlüğe kaydetmeniz gerektiğinde arayın.

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

Bunun aşağıdaki faydaları vardır:

  • Elmah çağrısının bu biraz arkaik sözdizimini hatırlamanıza gerek yok
  • Çok sayıda DLL'niz varsa, Elmah Core'a her birinden başvurmanız gerekmez ve bunu kendi 'Sistem' DLL'nize koyun.
  • Herhangi bir özel işlem yapmanız gerekiyorsa veya sadece hataları ayıklamak için bir kesme noktası koymak istiyorsanız, hepsi tek bir yere sahip olursunuz.
  • Elmah'tan uzaklaşırsanız, sadece bir yeri değiştirebilirsiniz.
  • Korumak istediğiniz eski hata günlüğünüz varsa (hemen kaldırmak için zamanım olmayan bazı kullanıcı arayüzlerine bağlı basit bir hata günlüğü mekanizmasına sahibim).

Not: İçerik bilgileri için bir 'contextualMessage' özelliği ekledim. İsterseniz bunu atlayabilirsiniz, ancak çok yararlı buluyorum. Elmah, istisnaları otomatik olarak açar, böylece altta yatan istisna günlükte hala raporlanır, ancak üzerine tıkladığınızda contextualMessage görülebilir.


1
Mükemmel cevap. Belki ELMAH kutudan benzer bir şey uygulamalıdır. Bazen bağlamsız bir hatayı ayıklamak gerçekten zordur.
ra00l

2
İle ikincil hataları yutma hariç tüm gibi // uh oh! just keep going. Hata işlemem başarısız olursa bilmek istiyorum. Biraz gürültü yapmasını istiyorum.
Jeremy Cook

3
@JeremyCook Kabul ediyorum, ancak dikkatli değilseniz başarısız hata işleme rutinleri kendilerini arama ve sonra havaya uçurmak eğilimindedir (oh ve ben de aslında hata günlüğü için burada bir üçüncü taraf API çağırıyordu). Muhtemelen bu cevap için bunu bırakmamalıydım, ancak daha önce böyle bir şeyle ilgili kötü deneyimlerim olurdu
Simon_Weaver

1
Bir genişletme yöntemi olarak daha iyi imho olurdu.
Stephen Kennedy

1
Düşünüyor olabilirsiniz: nah, kaç tane manuel hatayı günlüğe deneyebilirim? Bunu yaklaşık bir yıl önce düşündüm. Uzun lafın kısası: Bu ambalajı kullanın!
nmit026

29

Bir istisna oluşturmadan bir sorunu günlüğe kaydetmek için Elmah.ErrorSignal () yöntemini kullanabilirsiniz.

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

    // Continue
}


14

Evet mümkün. ELMAH, ele alınmayan istisnaları durdurmak için tasarlanmıştır. Ancak ErrorSignal sınıfı aracılığıyla ELMAH'a bir özel durum bildirebilirsiniz. Bu istisnalar atılmaz (kabarmaz), sadece ELMAH'a (ve ErrorSignal sınıfının Raise olayının abonelerine) gönderilir.

Küçük bir örnek:

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

13

Ben bir MVC4 uygulaması içinde posta sıraya başlamıştı bir iş parçacığında aynı şeyi yapmak için aradım, böyle bir istisna ortaya çıktığında kullanılabilir HttpContext yoktu. Bunu yapmak için bu soruya ve burada bulunan başka bir cevaba dayanarak aşağıdakileri buldum: elmah: HttpContext olmadan istisnalar?

Yapılandırma dosyasında bir uygulama adı belirttim:

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

Daha sonra kodda (yukarıda verilen cevap gibi, ancak HttpContext olmadan) bir HttpContext yerine null iletebilirsiniz:

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

Çözümünü seviyorum; ancak, "Elmah" ı çözemiyorum. benim projemde. "Elmah kullanarak" eklemeyi denedim; kodumda var, ancak geçerli bağlamımda mevcut değil.
Taersious

@Taersious packages.configGörünüşünüz nasıl? Şuna benzer bir şey görüyor musunuz <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 ile kurdunuz mu?
Matthew

Evet demek istiyorum, ancak projem şu anda kaynak kontrolünde kilitli. Elmah'ı projedeki örnek yapılandırma dosyasından manuel olarak uyguladım.
Taersious

@Taersious Manuel olarak yapıyorsanız, kullanmaya başlamadan önce projeye Elmah referansını eklediniz mi ... Her iki şekilde de çalışmasını beklerdim, ancak nuget eklediğinde yukarıdaki satırların ekleneceğini biliyorumpackages.config
Matthew

3

Bazen CurrentHttpContextmevcut olmayabilir.

Tanımlamak

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 { }
    }
}

kullanım

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

Ben duyuyorum ASP.NET çekirdek ve kullandığım ElmahCore .

Hataları HttpContext (denetleyicide) ile manuel olarak kaydetmek için şunları yazın:

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

HttpContext içermeyen uygulamanızın başka bir bölümünde :

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

0

Signal.FromCurrentContext () kullanarak elmah günlüklerine özel mesajlar yazmaya çalışıyordum. Raise (ex); ve bu istisnaların köpürdüğünü, örneğin:

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

Ayrıca elmah'ın farklı günlük kaydı düzeylerini nasıl desteklediğini göremiyorum - bir web.config ayarıyla ayrıntılı günlük kaydını kapatmak mümkün mü?


1
Bir istisna yakalar ve bir daha atmazsanız, istisnalar patlamaz. Belki yanlış anladım? ELMAH farklı düzeylerde günlük kaydını desteklemez. Sadece hatalar içindir.
ThomasArdal

Teşekkürler, Thomas. Tam olarak bunu doğrulamaya çalışıyordum
Valery Gavrilov

0

Bu çizgiyi kullandı ve mükemmel çalışıyor.

 try{
            //Code which may throw an error
    }
    catch(Exception ex){
            ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.