วิธีใช้ 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
อะไรคือความแตกต่างระหว่างวิธีการของคุณกับคนอื่น ๆ ?
Omu

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()เข้าสู่ระบบอะไร?)
คริสเตียน Diaconescu

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
  • หากคุณมี DLLs จำนวนมากคุณไม่จำเป็นต้องอ้างอิง Elmah Core จากทุก ๆ หนึ่ง - และเพียงแค่ใส่ค่านี้ใน 'System' DLL ของคุณเอง
  • หากคุณต้องการจัดการเป็นพิเศษหรือเพียงต้องการเบรกพอยต์เพื่อแก้ไขข้อผิดพลาดคุณมีทั้งหมดในที่เดียว
  • หากคุณย้ายออกจาก Elmah คุณสามารถเปลี่ยนที่เดียวได้
  • หากคุณมีการบันทึกข้อผิดพลาดดั้งเดิมที่คุณต้องการเก็บไว้ (ฉันเพิ่งเกิดขึ้นกับกลไกการบันทึกข้อผิดพลาดแบบง่ายที่ผูกกับ UIs บางอย่างที่ฉันไม่มีเวลาลบทันที)

หมายเหตุ: ฉันได้เพิ่มคุณสมบัติ 'contextualMessage' สำหรับข้อมูลเชิงบริบท คุณสามารถละเว้นสิ่งนี้หากคุณต้องการ แต่ฉันคิดว่ามันมีประโยชน์มาก Elmah จะแยกข้อยกเว้นโดยอัตโนมัติดังนั้นข้อยกเว้นที่พื้นฐานจะยังคงถูกรายงานในบันทึก แต่บริบทจะมองเห็นข้อความเมื่อคุณคลิกที่มัน


1
คำตอบที่ดี บางที ELMAH ควรใช้สิ่งที่คล้ายกันออกจากกล่อง บางครั้งเป็นการยากที่จะดีบักข้อผิดพลาดโดยไม่มีบริบท
ra00l

2
ผมชอบทุก แต่กลืนข้อผิดพลาดรองใด ๆ // uh oh! just keep goingกับ หากการจัดการข้อผิดพลาดล้มเหลวฉันต้องการทราบ ฉันต้องการให้ส่งเสียง
Jeremy Cook

3
@ JeremyCook ฉันเห็นด้วย แต่ด้วยข้อแม้ว่าถ้าคุณไม่ระวังข้อผิดพลาดในการจัดการข้อผิดพลาดมักจะจบลงด้วยการโทรหาตัวเองแล้วก็ระเบิดขึ้นมา (โอ้แล้วฉันก็เรียก API ของบุคคลที่สามที่นี่เพื่อบันทึกข้อผิดพลาด) ฉันอาจไม่ควรทิ้งคำตอบนี้ไว้ แต่ฉันมีประสบการณ์ที่ไม่ดีกับสิ่งที่เกิดขึ้นมาก่อน
Simon_Weaver

1
มันจะดียิ่งขึ้นถ้าฉันเป็นวิธีการขยาย
Stephen Kennedy

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" ในโครงการของฉัน ฉันพยายามเพิ่ม "using 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 () Raise (ex); และพบว่ามีข้อยกเว้นเหล่านี้เกิดขึ้นเช่น:

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

นอกจากนี้ฉันไม่เห็นว่า elmah สนับสนุนการบันทึกในระดับต่าง ๆ - เป็นไปได้ไหมที่จะปิดการบันทึก verbose โดยการตั้งค่า web.config


1
หากคุณรับข้อยกเว้นและไม่โยนอีกครั้งข้อยกเว้นจะไม่ทำให้เกิดฟอง บางทีฉันอาจเข้าใจผิด? ELMAH ไม่สนับสนุนการบันทึกในระดับต่างๆ มันมีไว้สำหรับข้อผิดพลาดเท่านั้น
ThomasArdal

ขอบคุณโทมัส นั่นคือสิ่งที่ฉันพยายามยืนยัน
Valery Gavrilov

0

ใช้บรรทัดนี้และทำงานได้อย่างสมบูรณ์แบบ

 try{
            //Code which may throw an error
    }
    catch(Exception ex){
            ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.