
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.
Vinicius Cunha Alves
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
Vinícius, mas se der erro no banco de dados, estiver fora ou coisa parecida? O melhor mesmo é mandar e-mail.
Vinicius Cunha Alves
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
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
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
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
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
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
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
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
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
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
Isso mesmo Gabriel, coloca no Global.asax.cs.
Rodrigo Francisquini
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
Rodrigo,
Esse exemplo foi baseado apenas para a Web
willian
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
Willian,
Sim, dentro do Global.asax.cs
Leandro Barral
Tenho a mesma duvida que o Fabio Omachi.
At.,
Leandro Barral.
Mauricio Gonzatto
Não é mais prático utilizar Health Monitoring?
Mauricio Junior
Faça o teste você mesmo! risos
willian
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
Willian,
O objetivo do artigo não é mostrar como mandar e-mail, é mostrar como pegar erro no software a qualquer custo.
willian
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.
2001 - iMasters FFPA Informática Ltda - Todos os direitos reservados.