Cómo usar ELMAH para registrar errores manualmente

259

¿Es posible hacer lo siguiente usando ELMAH?

logger.Log(" something");

Estoy haciendo algo como esto:

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

ELMAH no registrará automáticamente esta excepción porque se manejó.

Omu
fuente
1
Para referencia futura, escribí una publicación sobre exactamente eso: errores de registro mediante programación . Mi tutorial de ELMAH también tiene información sobre esto.
ThomasArdal

Respuestas:

412

Método de escritura de registro directo, trabajando desde ELMAH 1.0:

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

ELMAH 1.2 presenta una API más flexible:

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

Hay una diferencia entre las dos soluciones:

  • RaiseEl método aplica las reglas de filtrado de ELMAH a la excepción. LogEl método no lo hace.
  • Raise se basa en la suscripción y puede registrar una excepción en varios registradores.
Andrey Kamaev
fuente
1
¿Cuál es la diferencia entre su método y los demás?
Omu
3
Estos registran el error en Elmah sin que la aplicación deje de funcionar. Le permite detectar excepciones comunes, manejarlas correctamente, pero aún así poder registrarlas.
PCasagrande
77
Descubrí que Elmah.ErrorSignal no estaba registrando cuando POST back contiene Html inseguro para Mvc4 .Net 4.5, en mi ejemplo, un POST back de los Servicios de control de acceso de Windows con un SignInResponseMessage. Elmah.ErrorLog.GetDefault funcionó en ese escenario
Adam
1
Tuve el mismo problema con HTML inseguro. ErrorLog.GetDefault hizo el truco
hgirish
44
Una gran advertencia cuando se usa Elmah.ErrorLog.Log(): se produce en caso de que la llamada de registro en sí misma falle, posiblemente derribando toda la aplicación web. Raise()falla en silencio Por ejemplo: si hay un problema de configuración incorrecta en el lado del servidor (por ejemplo, Elmah está configurado para guardar los errores en el disco, pero no tiene el acceso correcto a la carpeta de registros), el .Log()método arrojará. (Sin embargo, esto es bueno para la depuración, por ejemplo, ¿por qué no se .Raise()registra nada?)
Cristian Diaconescu
91

Recomiendo encapsular la llamada a Elmah en una clase de envoltura simple propia.

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

Luego, simplemente llámelo cuando necesite registrar un error.

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

Esto tiene los siguientes beneficios:

  • No necesita recordar esta sintaxis ligeramente arcaica de la llamada de Elmah
  • Si tiene muchas DLL, no necesita hacer referencia a Elmah Core de cada una de ellas, y simplemente poner esto en su propia DLL de 'Sistema'.
  • Si alguna vez necesita hacer un manejo especial o simplemente quiere poner un punto de interrupción para depurar errores, lo tiene todo en un solo lugar.
  • Si alguna vez te alejas de Elmah, puedes cambiar un lugar.
  • Si tiene un registro de errores heredado que desea conservar (solo tengo un mecanismo de registro de errores simple que está vinculado a algunas IU que no tengo tiempo de eliminar de inmediato).

Nota: He agregado una propiedad 'contextualMessage' para información contextual. Puede omitir esto si lo prefiere, pero me parece muy útil. Elmah desenvuelve automáticamente las excepciones, por lo que la excepción subyacente aún se informará en el registro, pero el mensaje contextual será visible cuando haga clic en él.

Simon_Weaver
fuente
1
Gran respuesta. Quizás ELMAH debería implementar algo similar fuera de la caja. A veces es realmente difícil depurar un error sin contexto.
ra00l
2
Me gusta todo, pero me trago cualquier error secundario con el // uh oh! just keep going. Si mi manejo de errores falla, quiero saberlo. Quiero que haga algo de ruido.
Jeremy Cook
3
@JeremyCook Estoy de acuerdo, pero con la advertencia de que si no tienes cuidado, las rutinas de manejo de errores fallidas tienden a terminar llamándose a sí mismas y luego explotando (oh, y también estaba llamando a una API de terceros aquí para registrar el error). Probablemente no debería haber dejado esto para esta respuesta, pero antes había tenido malas experiencias con tal cosa
Simon_Weaver
1
Sería aún mejor en mi humilde opinión como método de extensión.
Stephen Kennedy
1
Quizás esté pensando: no, ¿cuántos errores manuales podría intentar registrar? Pensé eso, hace aproximadamente un año. Larga historia corta: ¡usa este envoltorio!
nmit026
29

Puede usar el método Elmah.ErrorSignal () para registrar un problema sin generar una excepción.

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

    // Continue
}
bigtv
fuente
19
catch(Exception ex)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
Darin Dimitrov
fuente
14

Sí, es posible. ELMAH fue diseñado para interceptar excepciones no manejadas. Sin embargo, puede señalar una excepción a ELMAH a través de la clase ErrorSignal. Esas excepciones no se lanzan (no burbujean), sino que solo se envían a ELMAH (y a los suscriptores del evento Raise de la clase ErrorSignal).

Un pequeño ejemplo:

protected void ThrowExceptionAndSignalElmah()
{
    ErrorSignal.FromCurrentContext().Raise(new NotSupportedException());
}
Christophe Geers
fuente
13

Estaba buscando hacer lo mismo en un hilo en el que había comenzado a poner en cola el correo desde mi aplicación MVC4, por lo que no tenía el HttpContext disponible cuando se produjo una excepción. Para hacer esto, terminé con lo siguiente basado en esta pregunta y otra respuesta encontrada aquí: elmah: ¿excepciones sin HttpContext?

En el archivo de configuración especifiqué un nombre de aplicación:

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

Luego, en el código (como la respuesta proporcionada anteriormente, pero sin el HttpContext) puede pasar nulo en lugar de un HttpContext:

ThreadPool.QueueUserWorkItem(t => {
     try {
         ...
         mySmtpClient.Send(message);
     } catch (SomeException e) {
         Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(e));
     }
 });
Mateo
fuente
Me gusta tu solucion; sin embargo, no puedo resolver "Elmah". en mi proyecto Traté de agregar "usando Elmah"; en mi código, pero no existe en mi contexto actual.
Taersious
@Taersious ¿Cómo te packages.configves? ¿Ves algo como <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" />':? ¿Instalaste con NuGET?
Matthew
Me gustaría decir que sí, pero mi proyecto está actualmente bloqueado en el control de código fuente. Implementé elmah manualmente desde el archivo de configuración de muestra en el proyecto.
Taersious
@Taersious Si lo hace manualmente, ¿agregó la referencia de Elmah al proyecto antes de invocar el uso ... Esperaría que funcione de cualquier manera, pero sé que cuando Nuget lo agrega, las líneas anteriores se agregan apackages.config
Matthew
3

A veces CurrentHttpContextpuede no estar disponible.

Definir

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

Utilizar

public class MyClass
{
    readonly ILogger _logger;

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

    public void MethodOne()
    {
        try
        {

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

Estoy en ASP.NET core y uso ElmahCore .

Para registrar errores manualmente con HttpContext (en el controlador) simplemente escriba:

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

En otra parte de su aplicación sin HttpContext :

using ElmahCore;
...
ElmahExtensions.RiseError(new Exception("Your Exception"));
A. Morel
fuente
0

Intenté escribir mensajes personalizados en los registros de elmah usando Signal.FromCurrentContext (). Raise (ex); y descubrimos que estas excepciones aparecen, por ejemplo:

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

Además, no veo cómo elmah admite diferentes niveles de registro: ¿es posible desactivar el registro detallado mediante una configuración web.config?

Valery Gavrilov
fuente
1
Si detecta una excepción y no la vuelve a lanzar, las excepciones no aparecen. Tal vez no entiendo? ELMAH no admite diferentes niveles de registro. Es solo para errores.
ThomasArdal
Gracias Thomas. Eso es exactamente lo que estaba tratando de confirmar
Valery Gavrilov,
0

Usé esta línea y funciona perfectamente bien.

 try{
            //Code which may throw an error
    }
    catch(Exception ex){
            ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
    }
Prajakta Kale
fuente