Como usar o ELMAH para registrar manualmente os erros


259

É possível fazer o seguinte usando o ELMAH?

logger.Log(" something");

Estou fazendo algo parecido com isto:

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

Essa exceção não será registrada automaticamente pelo ELMAH, porque foi tratada.


1
Para referência futura, escrevi um post sobre exatamente isso: Registrando erros programaticamente . Meu tutorial ELMAH também tem algumas informações sobre isso.
ThomasArdal

Respostas:


412

Método de gravação direta de log, trabalhando desde o ELMAH 1.0:

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

O ELMAH 1.2 apresenta uma API mais flexível:

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

Há uma diferença entre as duas soluções:

  • RaiseO método aplica regras de filtragem ELMAH à exceção. Logmétodo não.
  • Raise é baseado em assinatura e é capaz de registrar uma exceção nos vários registradores.

1
qual a diferença entre o seu método e os outros?
Omu

3
Eles registram o erro no Elmah sem fazer com que o aplicativo pare de funcionar. Ele permite capturar exceções comuns, manipulá-las adequadamente, mas ainda assim poder registrá-las.
precisa saber é o seguinte

7
Descobri que Elmah.ErrorSignal não estava registrando quando o POST back contém HTML inseguro para o Mvc4 .Net 4.5, no meu exemplo, um POST de volta do Windows Access Control Services com uma SignInResponseMessage. Elmah.ErrorLog.GetDefault fez um trabalho nesse cenário
Adam

1
Eu tive o mesmo problema com HTML inseguro. O ErrorLog.GetDefault fez o truque
hgirish

4
Uma grande ressalva ao usar Elmah.ErrorLog.Log(): ele lança caso a chamada de log falhe, possivelmente derrubando o aplicativo Web inteiro. Raise()falha silenciosamente. Por exemplo: se houver um problema de configuração incorreta no servidor (por exemplo, o Elmah estiver configurado para salvar os erros no disco, mas não tiver o acesso correto à pasta de logs), o .Log()método será lançado. (Isso é bom para a depuração, porém, por exemplo, por que não .Raise()log qualquer coisa?)
Cristian Diaconescu

91

Eu recomendo encerrar a chamada para Elmah em uma classe de wrapper simples.

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

Em seguida, basta chamá-lo sempre que precisar registrar um erro.

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

Isso tem os seguintes benefícios:

  • Você não precisa se lembrar dessa sintaxe levemente arcaica da chamada Elmah
  • Se você possui muitas DLLs, não precisa fazer referência a Elmah Core a partir de cada uma delas - basta colocar isso na sua própria DLL do 'Sistema'.
  • Se você precisar fazer algum tratamento especial ou apenas desejar colocar um ponto de interrupção para depurar erros, você tem tudo em um só lugar.
  • Se você se afastar de Elmah, poderá mudar de lugar.
  • Se você possui um log de erro herdado, você deseja reter (por acaso, tenho um mecanismo simples de log de erro vinculado a algumas UIs que não tenho tempo para remover imediatamente).

Nota: eu adicionei uma propriedade 'contextualMessage' para informações contextuais. Você pode omitir isso, se preferir, mas acho muito útil. O Elmah desembrulha automaticamente as exceções para que a exceção subjacente ainda seja relatada no log, mas o contextualMessage ficará visível quando você clicar nele.


1
Ótima resposta. Talvez o ELMAH deva implementar algo similar imediatamente. Às vezes, é realmente difícil depurar um erro sem contexto.
ra00l

2
Eu gosto de tudo, mas engolir quaisquer erros secundários com o // uh oh! just keep going. Se meu tratamento de erros estiver falhando, quero saber. Eu quero fazer algum barulho.
Jeremy Cook

3
@ JeremyCook Eu concordo, mas com a ressalva de que, se você não tomar cuidado, as rotinas de manipulação de erros com falha tendem a acabar se chamando e explodindo (ah, eu também estava chamando uma API de terceiros aqui para registrar o erro). Provavelmente eu não deveria ter deixado isso para esta resposta, mas já tive experiências ruins com uma coisa dessas antes
Simon_Weaver

1
Seria ainda melhor como um método de extensão.
Stephen Kennedy

1
Você pode estar pensando: nah, quantos erros manuais eu poderia tentar registrar? Eu pensei isso, cerca de um ano atrás. Para encurtar a história: use este invólucro!
N

29

Você pode usar o método Elmah.ErrorSignal () para registrar um problema sem gerar uma exceção.

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

    // Continue
}


14

Sim, é possível. O ELMAH foi projetado para interceptar exceções não tratadas. No entanto, você pode sinalizar uma exceção para o ELMAH através da classe ErrorSignal. Essas exceções não são lançadas (não fazem bolhas), mas são enviadas apenas para o ELMAH (e para os assinantes do evento Raise da classe ErrorSignal).

Um pequeno exemplo:

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

13

Eu estava procurando fazer a mesma coisa em um encadeamento em que comecei a enfileirar emails no meu aplicativo MVC4; portanto, não tinha o HttpContext disponível quando uma exceção foi gerada. Para fazer isso, terminei com o seguinte com base nesta pergunta e em outra resposta encontrada aqui: elmah: exceções sem o HttpContext?

No arquivo de configuração, especifiquei um nome de aplicativo:

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

Em seguida, no código (como a resposta fornecida acima, mas sem o HttpContext), você pode passar nulo em vez de um HttpContext:

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

Eu gosto da sua solução; no entanto, não consigo resolver "Elmah". no meu projeto. Eu tentei adicionar "using Elmah;" no meu código, mas ele não existe no meu contexto atual.
Taersious

@ Taersious Como é a sua packages.configaparência? Você vê 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" />':? Você instalou com o NuGET?
Matthew

Eu gostaria de dizer que sim, mas meu projeto está atualmente bloqueado no controle de origem. Eu implementei o elmah manualmente a partir do arquivo de configuração de amostra no projeto.
Taersious

@ Taersious Se fazendo isso manualmente, você adicionou a referência Elmah ao projeto antes de invocar o uso ... Eu esperaria que funcionasse de qualquer maneira, mas sei que quando o nuget o adiciona, as linhas acima são adicionadas aopackages.config
Matthew

3

Às vezes, CurrentHttpContextpode não estar disponível.

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

Usar

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

Estou no núcleo do ASP.NET e uso o ElmahCore .

Para registrar manualmente erros com o HttpContext (no controlador), basta escrever:

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

Em outra parte do seu aplicativo sem o HttpContext :

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

0

Eu estava tentando gravar mensagens personalizadas em logs elmah usando Signal.FromCurrentContext (). Raise (ex); e constatou que essas exceções estão surgindo, por exemplo:

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

Além disso, não vejo como o elmah suporta diferentes níveis de registro - é possível desativar o registro detalhado por meio de uma configuração web.config?


1
Se você pegar uma exceção e não a lançar novamente, as exceções não surgem. Talvez eu entenda mal? O ELMAH não suporta diferentes níveis de registro. É apenas para erros.
21317 ThomasArdal

Obrigado, Thomas. Isso é exatamente o que eu estava tentando confirmar
Valery Gavrilov

0

Utilizou esta linha e funciona perfeitamente bem.

 try{
            //Code which may throw an error
    }
    catch(Exception ex){
            ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));
    }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.