Tratar todos os erros não tratados - Object Pascal - Delphi & Lazarus - Projeto ACBr
Tratar todos os erros não tratados
September 12, 2019 in Object Pascal - Delphi & Lazarus
Olá queridos companheiros, pesquisei muito sobre uma forma de tratar erros inesperados que causam o fechamento da aplicação e acabei descobrindo (ou inventando kkk), um modo de tratar todos os erros que não foram tratados, vi uma postagem de mais de um ano aq no forum mas não puder dar sequencia nela por estar fechada.
Nesse post vi a sugestão do componente TApplicationProperties, para usar seu evento OnException, mas ao tentar usar ele, disparava 3 vezes, sem contar que ao colocar um componente em um form e herda-lo, ele componente fica aparecendo em todos os forms e eu só meio xarope e isso me incomoda.
Seguinte.... Eu uso um FormPadrao no qual estão todas procedures (ferramentas) criadas por mim e algumas outras facilidades como mudar de campo com Enter, fechar as janelas com Esc, etc. E derivo todos os meus outros forms desse para herdarem essas funções e propriedades. Nele eu criei o seguinte procedimento.
//================================== Inicio do Procedimento ==================================\\
procedure TFormPadrao.OnException(Sender: TObject; E: Exception);
auxLog: TextFile;
AssignFile(auxLog, 'Log_Exceptions.txt');
if (FileExists('Log_Exceptions.txt')) then
Append(auxLog);
Rewrite(auxLog);
WriteLn(auxLog, 'Log de Erros!');
WriteLn(auxLog, '');
WriteLn(auxLog, FormatDateTime('dd/MM/yyyy - hh:mm:ss',now) +
' => Origem: ' + Sender.ToString + ' => Erro: ' + E.Message);
CloseFile(auxLog);
Riba.Aviso('Origem: ' + Sender.ToString + ' => Erro: ' + E.Message);
if(Sender is TForm)then
(Sender as TForm).Close;
//================================== Fim do Procedimento ==================================\\
E no evento onCreate eu digitei essa linha que associa um procedimento ao um evento
Application.OnException := @OnException;
Agora todo erro não tratado é mostrado na tela, fecha só o form que deu o erro e faz um log dos erros.
obs. Esse Riba.Aviso é pra mostrar mensagens na tela do meu jeito.
Se eu fiz algo errado no post me corrijam por favor pois é meu primeiro post compartilhando informação.
Edited September 12, 2019 by RibaSoft
Obrigada por compartilhar sua solução.
Eu particularmente gosto de analisar sugestões criativas como a sua. Acho que nos acrescenta muito. Dito isso, tenho os seguintes comentários:
hmm... talvez o seu problema esteja em colocar o TApplicationproperties no seu FormPadrao. Você deve ter apenas uma instância do TApplicationProperties na sua aplicação. Geralmente coloca-se num DataModule que não vai ser criado e destruído mais de uma vez.
O problema ao fazer isso é que cada form criado sobrepõe o Application.OnException do Form anterior. Isso pode levar a uma inconsistência.
Acredito que se você criar um dois forms em sequência, o segundo for destruído e então o primeiro gerar uma exception você terá um AccessViolation.
Boa noite fico muito contente pelas suas explicações, vou tentar coloca-las em prática.
Só para entender melhor, meu form padrão nunca é criado (instanciado), ele serve apenas para que os forms herdeiros herdem seus eventos e propriedades, o meu form que é instanciado junto com o sistema é o formPrincipal que também é herdeiro do form padrão, minha duvida é:
Se esse evento o Application.OnException que é herdado pode dar problemas, o meus outros eventos herdados tambem podem dar problemas? tipo o onKeyPress que uso para fechar todos os forms com o ESC?
Sou autodidata por isso não tenho tanta experiência, acho que não venho usando corretamente a herança de classes. Preciso estudar mais.
36 minutos atrás, RibaSoft disse:
Não quis dizer que o "form padrão" fosse criado, mas sim os forms que herdam dele que possuem o mesmo evento onCreate que você descreveu acima. Dito isso:
38 minutos atrás, RibaSoft disse:
Creio que não, porque esses outros eventos são de cada form. Mas o evento Application.OnException é da aplicação (Application).
Application é na verdade uma variável global da aplicação. Por isso, toda vez que você faz:
7 horas atrás, RibaSoft disse:
Você está na verdade sobrescrevendo o mesmo evento com uma procedure do form que foi criado agora.
Show a explicação, só uma ultima pergunta se não for abusar, eu usando o componente mencionado no datamodulo ele pegara as exception de toda a aplicação? pela logica acho que sim né pois vc falou que se trata de um evento da aplicação e não do form.
Arrumei conforme vc falou, testei no DataModulo e no FormPrincipal, o ruim de fazer assim é que não vem o nome do Form no Sender, dai meu log não vai registrar da onde veio o erro, e nem consigo fechar aquele form especifico, mas se fica mais estável vou seguir seu conselho e deixar como está, pelo menos não aparece mais o abort que o cliente sempre clica e fecha toda a aplicação.
Em 13/09/2019 at 01:15, RibaSoft disse:
Arrumei conforme vc falou, testei no DataModulo e no FormPrincipal, o ruim de fazer assim é que não vem o nome do Form no Sender, dai meu log não vai registrar da onde veio o erro, e nem consigo fechar aquele form especifico,
Hmm... Acho que estamos com ideias diferentes. Eu não vejo o Application.onException com o objetivo de tratar erros num form específico. Eu o vejo como um modo pra tratar exceptions que fugiram todos os tratamentos nos forms.
Nesses casos, o ideal é você registrar o CallStack da exception, de modo que você vai saber exatamente não só onde aconteceu, mas também o percurso que o código fez pra gerar o erro.
mas se fica mais estável vou seguir seu conselho e deixar como está
Fica mais estável porque você estava sobrescrevendo o Application.onException. Você pode remover o código que faz isso e daí usar um TApplicationEvents para cada form como queria.
O detalhe é que nesse caso, todos os forms abertos vão receber o evento. Daí você deve usar o método CancelDispatch para impedir a propagação pros próximos forms.
Queria acrescentar que esse modelo eu nunca trabalhei... mas não me parece vantajoso.
Não devo ter me espessado direito, mas é exatamente o que preciso, tratar erros que não foram tratados e criar um log que me ajude a identificar a origem do erro, não tenho palavras pra agradecer sua ajuda em me orientar, vou pesquisar sobre o callstack pois não sei como funciona, e quanto ao segundo modo citado, realmente não parece haver vantagens. DEUS abençoe pela ajuda.
No DataModulo
//Adiciona a procedure ao evento
Application.OnException := @OnException; //Forms
//============================= ON EXCEPTION =================================\\
procedure TDataModulo.OnException(Sender: TObject; E: Exception);
'=> Erro: ' + E.ClassName + ' - ' + E.Message);
//Aqui é onde registra os detalhes do erro
DumpExceptionBackTrace(auxLog);
WriteLn(auxLog, '======================================================='+
'================================');
Riba.Aviso('Erro: ' + E.ClassName + ' - ' + E.Message);
//=============================== RESULTADO DO LOG
17/09/2019 - 00:40:48=> Erro: EConvertError - " " is an invalid integer
$00501536
$0045C6C7 TFORMCLIENTES__EDITBUSCARCHANGE, line 290 of unitClientes.pas
$005DB395 TCUSTOMEDIT__CHANGE, line 652 of ./include/customedit.inc
$005DB33A TCUSTOMEDIT__TEXTCHANGED, line 644 of ./include/customedit.inc
$005BCD6B TCONTROL__CMTEXTCHANGED, line 1203 of ./include/control.inc
$0040E828
$005B4801 TWINCONTROL__WNDPROC, line 5419 of ./include/wincontrol.inc
$005DAF03 TCUSTOMEDIT__WNDPROC, line 528 of ./include/customedit.inc
$006525CF DELIVERMESSAGE, line 112 of lclmessageglue.pas
$0059B5BD TWINDOWPROCHELPER__DOWINDOWPROC, line 2515 of win32callback.inc
$0059BC8B WINDOWPROC, line 2677 of win32callback.inc
$006491ED GROUPBOXWINDOWPROC, line 576 of win32wsstdctrls.pp
$75E96238
$75E968EA
$75E9CD1A
$75E9CD81
$72596508
//Na segunda linha mostra o nome do form, o evento, a linha do erro e o nome da unit onde ocorreu o erro.
Muito bom, brigadão EMBarbosa, perfeito!!!
Qual uses para utilizar DumpExceptionBackTrace?
É a unit System
Mas eu uso só o windows, não sei como fazer no linux
No teu caso você está programando no lazaruz, FPC, eu estou programando no Delphi, daí não encontrei, parece que não tem na verdade para o Delphi, somente solução de terceiros =/