Fejlhåndtering

Tags:    kodedesign arkitektur

God morgen med-udviklere

Sidder og er ved at rette noget forfærdelig kode med noget fejllogning i en applikation. Der er lavet en LogError metode med en fejlkode, og en fejlmessage - begge som strings.
Problemet her bliver at man aner ikke hvad der er af fejlkoder, om du bruger en der allerede er brugt, folk opfinder deres egne tallerkener på kryds og tværs så meddelelser og fejlkoder ser voldsomt forskellige ud alt efter hvem der har lavet den del.

Min ide er så at centralisere det for at skabe overblik.
En enum med alle fejlkoder.
Denne fejlkode sendes så en metode der returnerer brugerens besked (den pæne til noget han forstår), og errormessage er den besked der er udviklerens tekniske beskrivelse vi skal have stående i loggen for at forstå fejlen.

Tanken var så at alle opdatere funktionen til at bruge min enum som input, og derved tvinge alle udviklere til at skulle følge samme procedure og ensarte det - så de laver deres egen enum-værdi til hver af deres fejl, så man ikke genbruger samme fejl, og får standardiseret tingene lidt mere.

Vil meget gerne høre for og imod - det kan nok sagtens gøres bedre endnu.



4 svar postet i denne tråd vises herunder
1 indlæg har modtaget i alt 2 karma
Sorter efter stemmer Sorter efter dato
Mon ikke der allerede findes et logging API med velbeskrevne best practices?

Jeg selv foretrækker systemer hvor man logger med fire argumenter:
* Subsystem
* Severity
* Statisk tekst
* Data

Til subsystem angiver man typisk en klasse, således at man kan enable debug beskeder for en lille del af koden uden at man skal overvældes af horder af beskeder, og den angives typisk når man opretter et logger objekt.

Severity er noget ala INFO, WARNING, DEBUG, ERROR eller FATAL. Så kan man konfigurere at man vil have alt højere end eller lig med ERROR.

Statisk tekst er den typiske log besked, men må ikke være dynamisk...f.eks. ikke:

log(ERROR, "Could not open " + someFile);

Den skal være statisk så den er let at søge på og gruppere efter.

Filnavnet skal med i det sidste argument, som er 'data'. Det kunne også være en exception eller IP, som man ikke kunne forbinde til...den dynamiske del af loggen.





Mon ikke der allerede findes et logging API med velbeskrevne best practices?

Jeg selv foretrækker systemer hvor man logger med fire argumenter:
* Subsystem
* Severity
* Statisk tekst
* Data

Til subsystem angiver man typisk en klasse, således at man kan enable debug beskeder for en lille del af koden uden at man skal overvældes af horder af beskeder, og den angives typisk når man opretter et logger objekt.

Severity er noget ala INFO, WARNING, DEBUG, ERROR eller FATAL. Så kan man konfigurere at man vil have alt højere end eller lig med ERROR.

Statisk tekst er den typiske log besked, men må ikke være dynamisk...f.eks. ikke:

log(ERROR, "Could not open " + someFile);

Den skal være statisk så den er let at søge på og gruppere efter.

Filnavnet skal med i det sidste argument, som er 'data'. Det kunne også være en exception eller IP, som man ikke kunne forbinde til...den dynamiske del af loggen.



Spændende!

Tror jeg skal have forklaret lidt nærmere omkring subsystem. Ville du så lave en logger til hver klasse, som du så kan enable/disable?

Er rigtigt glad for din pointe med statisk tekst og er noget jeg arbejder med at få kollegaer til at forstå, fordi når man laver fejlhåndtering er det ikke specielt godt hvis du har noget kode der går ned imens den er ved at lave fejlhåndtering.

Hvordan laver du så Data? Gætter på du laver det som objekt, så ser på type og laver noget logning ud fra det?

Fx log(ERROR, "Could not open file", FileOpenException)

Hvordan ville du så logge det?

Could not open file
Exception detail
File access denied
at FileReader.ReadFile() [Line X]
at SuperReader.FindLinesWith() [Line X]
at DataProvider.BuildModel() [Line X]
at RenderEngine.PreparePresentation() [Line X]
at PresentUserLines() [Line X]



Det ligner Java, så brug denne: http://docs.oracle.com/javase/7/docs/api/java/util/logging/Logger.html

En bette artikel om det: http://www.vogella.com/tutorials/Logging/article.html

De skriver: "It is common practice to use the fully qualified name of each class whose activity is being logged as a message category, because this allows developers to fine-tune log settings for each class.

Using the fully qualified class name of your class as the name of your Logger is the approach recommended by the Logging API documentation."

Og et kort eksempel (hvor jeg så ikke følger ovennævnte best practice):
Fold kodeboks ind/udJava kode 


Og en test:
Fold kodeboks ind/udKode 


En lidt længere artikel om logging, som også beskriver, hvordan man kan konfigurere sin logging: http://tutorials.jenkov.com/java-logging/configuration.html



Jeg ville bruge log4net til at logge til disk med. Der kan du opsætte alt det du vil.

Så ville jeg også skelne mellem fejl. Det vil sige at exceptions fanges så højt oppe som muligt, i en perfekt verden er der kun eet sted hvor alle exceptions fanges og du smider dem så i din logfil, med hele stacktrace osv.

De logiske fejl ville jeg logge som DEBUG beskeder, noget hvor du som udvikler lige slår DEBUG logging til (med log4net gør du det bare i app.config), så komme dine debug fejl ud. Hvis du kan fange en logisk fejl runtime og RETTE den runtime, så gør du det og evt. logger en debug fejl. Hvis der sker en fejl og du ikke kan rette den - så smider du den videre som en exception. Det er bedre at fange uvendtede fejl og så få dem rettet end at skjule det hele i koden for brugerne.




t