Toon posts:

Errorhandling

Pagina: 1
Acties:

Verwijderd

Topicstarter
Aangezien error handling een belangrijk aspect is van een Architectuur en ik geen Errorhandling topic kan vinden betreffende mijn specifieke situatie, hoop ik op deze manier wat wijzer te worden.

De volgende situatie:

- Een aantal klassen waarin wordt gecommuniceerd met hardware.
- De klassen worden in een soort van 'monitor' applicatie gebruikt en ik wil dus het tonen van meldingen vermijden.
- Afgezien van het feit dat het niet nuttig een melding in een 'monitor' applicatie te tonen, wil ik ook een logging van gegenereerde fouten hebben zodat dit gebruikt kan worden in het debugging proces. (Zonder af te gaan op de bevindingen van de gebruiker.)

Met betrekking tot de errorhandling, heb ik de volgende werkwijze reeds geïmplementeerd:

- Tijdens het communiceren met de hardware worden, bij kritieke acties, custom errors opgegooid wanneer de communicatie mislukt. (Voorbeelden zijn: het niet kunnen openen van een COM poort of het niet kunnen versturen van een commando.)
- Er bestaat reeds een OnException Handler binnen mijn Delphi project, waarin het betreffende foutbericht wordt weggeschreven in een log.

Nu het volgende probleem. Wanneer ik de betreffende objecten aanroep, doe ik dat als volgt (pseudo code, slechts ten behoeve van het vormen van een beeld):

Delphi:
1
2
3
4
...
connect := TConnection.Create;
connect.ToCompoort( 1 );
...


Stel dat de functie ToCompoort nu de exceptie EComException opgooid, dan wordt dit in mijn situatie netjes opgevangen door de OnError Handler en weggeschreven naar een log. Perfect. Helaas dient zich nu de volgende situatie aan. Na een raise wordt de applicatie flow gedirigeerd naar de OnException Handler en wordt na het afhandelen van de fout geen code meer uitgevoerd. In mijn geval wordt tijdens (een soortgelijke) ToCompoort functie een initialisatie scherm getoond. Na de raise wordt dit scherm dus niet meer vernietigd, omdat er geen code meer wordt uitgevoerd.

Wat wil ik nu bereiken :)
Feitelijk heel simpel. Ik wil dat de applicatie normaal blijft draaien, maar in het geval er een procedure wordt gestart die een exceptie opgegooid, wil ik dat juist die execptie in een log wordt weggeschreven en de applicatie verder normaal blijft functioneren. (Denk eraan dat dit een 'monitor' applicatie is, ik wil geen meldingen tonen.)

Wat ik heb geprobeerd
Door middel van het toepassen van de volgende code, kan ik voorkomen dat de werking van de applicatie wordt gegarandeerd:

Delphi:
1
2
3
4
5
6
7
8
9
...
try
  connect := TConnection.Create;
  connect.ToCompoort( 1 );
except
  on EComException do
    // schrijf naar log
end
...


Echter, nu moet ik opnieuw de functie aanroepen die naar het log schrijft, terwijl dit juist door mijn OnExceptino Handler zou uitgevoerd moeten worden. Dit resulteert weer in meer (dezelfde) code. (Er zijn namelijk meer functies die excepties opgooien en dan zou ik voor elke functie weer opnieuw de functie aan moeten roepen die naar het log schrijft.)

Hopelijk is mijn idee duildeijk. Ik vraag dus geen implementatie o.i.d. Ik zou graag wat ideëen / aanpassingen / verbeteringen hierover willen horen of wellicht reeds bestaande concepten.

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 22-02 00:22

Janoz

Moderator Devschuur®

!litemod

In principe is het redelijk logisch dat je code neit verder gaat. Verderop in de code ga je er immers van uit dat die com poort open is. De rest van de code kan dus ook niet verder uitgevoerd worden.

Ik ben daarom ook erg benieuwd hoe de rest van je applicatie in elkaar steekt.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Verwijderd

Topicstarter
Als je het zo bekijkt heb je inderdaad een punt. Echter, dat 'verderop in de code' wordt alleen uitgevoerd na het openen van een Compoort. Misschien is mijn code iets te kort van stof. Ik probeer het iets te verduidelijken:


main.pas:

Delphi:
1
2
  connect :=  TConnection.Create;
  connect.ToCompoort( 1 )



c_connection.pas

Delphi:
1
2
3
4
5
6
7
8
9
procedure ToCompoort( 1 );
begin

  if MSComm.Open then
    // uitvoer code in normale situatie
  else
    raise EComException;

end;


Nu is het zo dat wanneer de applicatie bijvoorbeeld regelmatig kijkt of er het een Compoort kan openen, pas ook iets uitvoert wanneer dat openen lukt. In geval het niet lukt, wordt er een execeptie opgegooid die in de OnExecption Handler wordt weggeschreven in een log. Precies de gewenste situatie dus.

Wanneer het geen 'monitor' applicatie betreft, zou je hier waarschijnlijk willen dat de applicatie ook niet verder gaat met 'stand by' staan of 'idle' zijn en je gewoon een melding getoond krijgt.

Wat ik bijvoorbeeld eerder probeerde (dus voor ik iets met exception deed) was bijvoorbeeld een Errorcode retourneren:

- ERR_COM in geval van het niet kunnen openen van een Compoort;
- ERR_SEND_COMMAND in het geval van het niet kunnen sturen van een commando.

Echter, dan ben je verplicht je bij iedere aanroep middels een case statement op basis van het geretourneerde errorcode de juiste (en dus nuttige) melding naar het log te schrijven. Iets wat je dus niet wilt en wat in mijn optiek ook geen object georienteerd programmeren is.

Verwijderd

Misschien een idee om de default errorobject van Delphi aan te passen zodat ie ( en dan ook automatisch alle afgeleiden ) logt ?

  • Varienaja
  • Registratie: Februari 2001
  • Laatst online: 14-06-2025

Varienaja

Wie dit leest is gek.

Verwijderd schreef op woensdag 05 april 2006 @ 12:28:
Helaas dient zich nu de volgende situatie aan. Na een raise wordt de applicatie flow gedirigeerd naar de OnException Handler en wordt na het afhandelen van de fout geen code meer uitgevoerd. In mijn geval wordt tijdens (een soortgelijke) ToCompoort functie een initialisatie scherm getoond. Na de raise wordt dit scherm dus niet meer vernietigd, omdat er geen code meer wordt uitgevoerd.
Dan moet je een finally-blok gebruiken. Dat wordt altijd uitgevoerd, ookal is er een exception opgetreden.

Siditamentis astuentis pactum.


Verwijderd

Varienaja schreef op woensdag 05 april 2006 @ 13:34:
[...]

Dan moet je een finally-blok gebruiken. Dat wordt altijd uitgevoerd, ookal is er een exception opgetreden.
niet vergeten om "try try" te doen dan.....je kunt voor zover ik weet geen errorblok met een except EN finally blok doen, wel als je er twee nest.

Verwijderd

Topicstarter
Het probleem van het gebruik van try...excepts (of finally) is dat het opnieuw voor iedere exceptie herhaald moet worden. Dit is ook logisch, aangezien er een exceptie wordt opgegooid en die afgevangen moet worden.

Echter, wat ik wil is een generieke methode om alle excepties die worden opgegooid, in een log weg te schrijven. Dus dat ik alleen maar een methode hoef aan te roepen. (Ik hoef namelijk in mijn 'monitor' applicatie niet te weten wat zo een methode retourneert, maar ik wil periodiek wel zien wat er allemaal gebeurt is toen die methode werd gestart en het fout ging.)

Misschien is zoiets wel helemaal niet mogelijk en moet ik toch maar steeds try...excepts gebruiken. Dat wil ik graag weten. Elke exceptie wordt nu al gelogd, maar de applicatie flow wordt onderbroken. Ik vraag me af of daar een manier voor is om dat tegen te gaan. Of hoe jullie bijvoorbeeld reageren op verschillende foutmeldingen die in éénzelfde methode kunnen worden gegenereerd.

In ieder geval bedankt voor jullie snelle reacties.

Verwijderd

application.OnException ? wordt aangeroepen voor ALLE exceptions die je zelf niet afhandeld.

[ Voor 58% gewijzigd door Verwijderd op 05-04-2006 14:03 ]


Verwijderd

Topicstarter
Verwijderd schreef op woensdag 05 april 2006 @ 14:03:
application.OnException ? wordt aangeroepen voor ALLE exceptions die je zelf niet afhandeld.
Inderdaad! _/-\o_ Daar kwam ik net achter, ik had dit OnException al geïmplementeerd (zie mijn startpost) en ik kwam er zojuist achter dat ik ergens (in een ouder stuk code) een fout niet had afgevangen :o en die dus netjes in het log bestand terecht kwam. Het werktte dus al de hele tijd correct. Alleen had ik het verkeerd begrepen.

Er zijn namelijk twee situaties in mijn 'monitor' tool:
- Als de applicatie gestart, dan wordt de hardware gedetecteerd.
- Als de applicatie draait (stand by, idle), dan kunnen er commando's naar toe gestuurd worden (in mijn geval elke 30 sec.).

Hardware detectie (pseudocode):

Delphi:
1
2
3
4
5
6
7
8
9
10
...
try
  connect := TConnection.Create;
  connect.ToCompoort( 1 );
  connect.Detect;
except
  on EComException do
    ShowMessage( 'Er is een fout opgetreden tijdens het benaderen van de Compoort' );
end
...


Dit is nuttig, aangezien een gebruiker de applicatie start en er dan wel mag worden aangenomen dat die persoon achter het scherm zit en geen log bestanden wil in zien.

Commando's sturen (pseudocode):

Delphi:
1
2
3
4
5
6
procedure TTimer.OnTimer;
begin
  connect := TConnection.Create;
  connect.ToCompoort( 1 );
  connect.SendCommand( 'bla' );
end;


Dit gebeurt elke 30 sec. er wordt aangenomen dat er geen gebruiker is en dat we fouten willen loggen.

Wanneer in deze situatie een Exceptie wordt gegeneerd (bijvoorbeeld EComException) wordt deze netjes in het log geschreven. En de applicatie draait door in stand by modus.

Dus deze situatie werkt perfect. Ik heb geen moeilijke (lees: veel) code nodig om te achterhalen welke fout er is opgetreden. (Hiervoor maak ik custom exceptions.)

Er is nu alleen nog één probleem. Als ik de exceptie afvang, dan kan ik dus extra code uitvoeren om een bericht te tonen. Echter, dan wordt het niet meer naar het log geschreven. De OnException Handler wordt namelijk niet meer aangeroepen. Hier moet ik dus weer dezelfde functie aanroepen, om de gegevens naar het log te schrijven. Dit is dus weer dubbelop.

EDIT:
Voor het laatste probleem heb ik ook een oplossing. Roep raise nog een keer aan. Nogmaals:

Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
...
try
  connect := TConnection.Create;
  connect.ToCompoort( 1 );
  connect.Detect;
except
  on EComException do
  begin  
    ShowMessage( 'Er is een fout opgetreden tijdens het benaderen van de Compoort' );
    raise; // de gegenereerde exceptie wordt opnieuw opgegooid
  end;
end
...


Het is nu dus opgelost. Een generieke oplossing voor Error handling. Bedankt voor jullie hulp.

[ Voor 12% gewijzigd door Verwijderd op 05-04-2006 14:40 ]

Pagina: 1