Sexta-feira, 19 de fevereiro de 2010 às 11h00

Detectando erro a todo custo

Conheça o curso ao vivo: Redes e Protocolos TCP/IP Avançado com Laboratório

Olá, pessoal! Hoje veremos uma técnica para detectar erro de uma aplicação a todo custo.

Detectar todo tipo de erro dentro de um sistema é muito importante, pois é uma forma de prevenir qualquer problema do software para o seu cliente, não importa como foi construído.

Referência:

- Visual Studio .NET

- Linguagem C#.NET

- Tecnologia: ASP.NET

 

Você deve estar se perguntando como fazer e pra que serve isso. Pois é, a minha resposta é bem grande e precisa de mais de um documento para explicar, porém vou tentar resumir e exemplificar na prática e no desenvolvimento.

Não sei se o ser humano de hoje está muito difícil ou se antigamente era mais fácil conversar e fazer a pessoa te escutar, só sei que trabalhar em grupo, principalmente se o grupo fizer algo que não tem documentação nenhuma, é muito difícil. Eu sempre defendi o uso de documentação, mas acabei entrando em uma empresa onde isso não existe e tudo é para ontem. Mesmo assim, brigo e peço sempre a documentação a todos.

Imagina pegar um sistema pela metade sem documentação, código ruim, feio e, para finalizar, o pessoal que fez saiu da empresa. Se você já passou por isso, vai concordar que o melhor mesmo é criar métodos que possam pegar o erro, caso ocorra.

Primeiro de tudo, use sempre try catch e, se possível, finally:

Try{}Catch( Exception ex){}Finally{}

Code 1.1

A segunda coisa é sempre deixar uma camada para o erro no sistema, ou seja, caso ocorra o catch, melhor mesmo é identificar onde aconteceu o erro, mandar e-mail, logar em um arquivo ou deixar registrado no eventview do sistema operacional. Existem casos que o erro até loga no banco de dados, mas, em minha opinião, acredito que não seja a melhor alternativa.

Lembra da empresa que te falei que não tem documentação nenhuma? Pois é, para saber direito o que o sistema faz, é necessário fazer engenharia reversa do código, o que, na minha opinião, é uma das piores coisas que existem na programação!

Quando não existe solução, ou não há tempo para verificar o código porque está dando erro em produção, o melhor mesmo é fazer uma solução genérica para pegar qualquer tipo de erro. Veja:

protected void Application_Error(object sender, EventArgs e)

{
HttpContext ctx = HttpContext.Current;

Exception exception = ctx.Server.GetLastError();

StringBuilder str = new StringBuilder();
str.Append("Error: "+exception.Message.ToString());
str.Append("\r\n Details: "+ exception.InnerException.Message.ToString());
str.Append("\r\n URL: " + Request.Url.AbsoluteUri.ToString());
str.Append("\r\n Stack Trace: " + exception.InnerException.StackTrace.ToString());
str.Append("\r\n Request Host: " + Request.UserHostAddress.ToString());
str.Append("\r\n Host Name: " + Request.UserHostName.ToString());
str.Append("\r\n User Agent: " + Request.UserAgent.ToString());
str.Append("\r\n URL Referrer: " + Request.UrlReferrer.ToString());
str.Append("\r\n UserName: " + Request.LogonUserIdentity.Name.ToString());
str.Append("\r\n Method: " + exception.TargetSite.ToString());
str.Append("\r\n Source: " + exception.Source.ToString());

// Compose Email
MailMessage msg = new MailMessage();

msg.From = new MailAddress("email automatico do sistema");
msg.To.Add("seu-email");
msg.Subject = "Error occurred in personal website application";
msg.IsBodyHtml = true;
msg.Body = str.ToString();

SmtpClient smtp = new SmtpClient();
smtp.Send(msg);

String LogName = "Application";
if (!EventLog.SourceExists(LogName))
{
EventLog.CreateEventSource(LogName, LogName);
}

// Insert into Event Log
EventLog Log = new EventLog();
Log.Source = LogName;
Log.WriteEntry(str.ToString(), EventLogEntryType.Error);

ctx.Server.ClearError();

}

Code 1.2

Mas lembre-se de uma coisa, qualquer tipo de erro o sistema vai pegar e mandar a você, dependendo da forma que fizer.

A primeira coisa que fiz foi pegar todos os erros da aplicação:

HttpContext ctx = HttpContext.Current;

Exception exception = ctx.Server.GetLastError();

Code 1.3

O próximo passo foi dividir os erros para enviar ao administrador ou desenvolver, ou seja, você:

 StringBuilder str = new StringBuilder();
str.Append("Error: "+exception.Message.ToString());
str.Append("\r\n Details: "+ exception.InnerException.Message.ToString());
str.Append("\r\n URL: " + Request.Url.AbsoluteUri.ToString());
str.Append("\r\n Stack Trace: " + exception.InnerException.StackTrace.ToString());
str.Append("\r\n Request Host: " + Request.UserHostAddress.ToString());
str.Append("\r\n Host Name: " + Request.UserHostName.ToString());
str.Append("\r\n User Agent: " + Request.UserAgent.ToString());
str.Append("\r\n URL Referrer: " + Request.UrlReferrer.ToString());
str.Append("\r\n UserName: " + Request.LogonUserIdentity.Name.ToString());
str.Append("\r\n Method: " + exception.TargetSite.ToString());
str.Append("\r\n Source: " + exception.Source.ToString());

Code 1.4

Nesse código eu peguei Erro, Detalhes do erro, Stack Trace, Request Host (de onde veio), usuário, url referente, método que ocorreu o problema e fonte. Depois de separar todos os erros possíveis, é necessário enviar e-mail ou gravar em eventview.

    MailMessage msg = new MailMessage();
msg.From = new MailAddress("email automatico do sistema");
msg.To.Add("seu-email");
msg.Subject = "Error occurred in personal website application";
msg.IsBodyHtml = true;
msg.Body = str.ToString();

SmtpClient smtp = new SmtpClient();
smtp.Send(msg);

String LogName = "Application";
if (!EventLog.SourceExists(LogName))
{
EventLog.CreateEventSource(LogName, LogName);
}
EventLog Log = new EventLog();
Log.Source = LogName;
Log.WriteEntry(str.ToString(), EventLogEntryType.Error);

Code 1.5

Na referência 1.5 eu envio e-mail e gravo no eventview do sistema operacional.

Para finalizar, apago o erro do servidor:

ctx.Server.ClearError();

Code 1.6

 

Espero que tenha ficado claro. Qualquer coisa, entre em contato.

23 comentários

 Vinicius Cunha Alves
19/02/2010 11h34

gravar erro no bd

Estou tentando instanciar uma classe e para gravar o erro no banco de dados. Mas quando faço isso, ele não execute esse evento.

Sabe me dizer o que acontece?

 Mauricio Junior
19/02/2010 16h48

Vinícius, mas se der erro no banco de dados, estiver fora ou coisa parecida? O melhor mesmo é mandar e-mail.

 Vinicius Cunha Alves
19/02/2010 17h02

Mauricio, é que eu já tenho uma rotina que eu chamo nos catchs, que faz a gravação no eventlog, no banco de dados, e faz o envio do email. Então, pra mim, o mais conveniente era só fazer a chamada pra essa rotina. O problema é que quando eu chamo essa rotina, este evento não é acionado.

Eu percebi que se eu instancio qualquer classe do meu projeto neste evento, ele não é acionado. Não consigo achar uma explicação lógica e nem achei documentação.

 Mauricio Junior
19/02/2010 17h14

Vinicius, esse método é para pegar qualquer tipo de erro que der na aplicação, usando catch ou não, entendeu? Pode continuar na sua aplicação a chamada normal para o seu evento ... mas tem método que não tem try e pode dar erro, quando der vai passar por esse código no global. Entendeu?

 Vinicius Cunha Alves
19/02/2010 17h51

Entendi sim. Justamente o que eu quero é isso, quando der algum erro que não tenha try, cair nesse código no global, e ai, fazer uma chamada pra rotina de gravação de log que eu criei. Só que quando faço a chamada pra essa rotina no Application_Error, parece que ele ignora o Application_Error.

 Mauricio Junior
19/02/2010 17h53

Vincius, acho que voce nao entendeu ainda.
Nao precisa chamar esse método Application_Error, mesmo não chamando ele passa por ele quando der erro, entendeu?

 Vinicius Cunha Alves
22/02/2010 10h24

Entendi sim. O que quero dizer, é que quando eu coloco uma chamada para outro método, dentro deste método Application_error, ele acaba não executando. Mas tudo bem, vou deixar fazendo gravação apenas no eventviewer mesmo.

 Fabio Omachi
19/02/2010 12h19

Chamar sua função

Achei interessante a forma como você criou este envio de erro, mas eu não entendi como que você chama esta função, no except do try?

 Mauricio Junior
19/02/2010 16h49

Fabio, não é chamado em nenhum evento. Mas se você coloca try e catch, a qualquer momento na aplicação acontecer um erro, ele passa por esse método automaticamente, entendeu? Não precisa chamar.

 Rogerio Segovia
19/02/2010 16h38

Cara, muito bom, no inicio da matéria, até pensei q era eu mesmo, estou na mesma situação que você... complicado trabalhar assim sem nenhum doc

 Mauricio Junior
19/02/2010 16h49

Rogerio, não é chamado em nenhum evento. Mas se você coloca try e catch, a qualquer momento na aplicação acontecer um erro, ele passa por esse método automaticamente, entendeu? Não precisa chamar.

 Gabriel Santana
19/02/2010 21h24

Excelente artigo Maurício, um problema comum a todos so desenvolvedores. Entendi que o método é chamado automaticamente, mas onde devemos coloca-lo? No global.asax? Em todos os code-behind da aplicação? Valeu.

 Mauricio Junior
22/02/2010 09h23

Isso mesmo Gabriel, coloca no Global.asax.cs.

 Rodrigo Francisquini
20/02/2010 23h43

Maurício,
Muito bom e muito útil esse artigo. Você poderia dar um exemplo, ou explicar mais ou menos como posso fazer um exemplo desse tipo para aplicações Windows Forms?
Obrigado.

 Mauricio Junior
22/02/2010 09h23

Rodrigo,
Esse exemplo foi baseado apenas para a Web

 willian
21/02/2010 19h53

Mauricio entendi que o método é chamado automaticamente, mas onde devemos coloca-lo? No global.asax? Em todos os code-behind da aplicação? Acho que falto esse detalhe no artigo, mas mesmo assim ele é muito util.

 Mauricio Junior
22/02/2010 09h24

Willian,
Sim, dentro do Global.asax.cs

 Leandro Barral
22/02/2010 09h30

Tenho a mesma duvida que o Fabio Omachi.

At.,
Leandro Barral.

 Mauricio Gonzatto
22/02/2010 09h46

Não é mais prático utilizar Health Monitoring?

 Mauricio Junior
22/02/2010 09h53

Faça o teste você mesmo! risos

 willian
23/02/2010 11h08

O post está incompleto, faltam as configurações de SMTP para enviar o email, e não estou querendo acusar ninguém de copia mas me parece que algumas coisas foram retiradas desse site aqui http://www.experts-exchange.com/Programming/Languages/.NET/ASP.NET/Q_24528348.html sem citar a revida referencia.

 Mauricio Junior
23/02/2010 11h17

Willian,
O objetivo do artigo não é mostrar como mandar e-mail, é mostrar como pegar erro no software a qualquer custo.

 willian
23/02/2010 12h03

Ok Mauricio Junior, mas você poderia dar a explicação completa pois ajudaria quem está aprendendo, ou você acha que quem está começando e viu seu POST tem que saber tudo sobre ASP.NET ou C#? Ou melhor podeira colocar no seu inicio, um disclaimer ou algo do tipo avisando do conhecimento necessário para implementar a sua "dica".
Sem falar na citação da referencia certo?
Abraço e sucesso.

Cancelar resposta

Qual a sua opinião?

Se você já possui conta iMasters, o login será feito abaixo.

Atenção: comentários considerados spams e/ou ofensivos serão moderados.
Sobre o Autor
Mauricio Junior formado pela Faculdade Anhanguera, Especialista pela FGV (Fundação Getúlio Vargas), Pós-Graduação em Docência Superior e mestrando na UNB, linha de pesquisa Desenvolvimento de Aplicativos para TV Digital. Com 26 anos, possui cinco livros publicados pela editora Ciência Moderna no ano de 2007. É certificado Microsoft MCP e MCAD. Trabalho como Consultor de TI na Brasil Telecom. Blog: blog.mauriciojunior.org, site pessoal www.mauriciojunior.org

2001 - iMasters FFPA Informática Ltda - Todos os direitos reservados.