I min sidste blogpost om Enterprise library (EL), lagde jeg ud med at næve Logging Application Block som et sted at starte med EL. Så her er mit take på logging application block. Enterprise library dokumentationen på MSDN er ret god.
Overordnet er der (mindst) to vigtige grunde til at implementere et struktureret logging. For det første, hvis du ikke har struktureret logging, så bliver test og udvikling af løsninger svært, eftersom det kan være svært at identificere hvor, hvornår og hvorfor fejlen opstår. Hvis alle services & komponenter som indgår i løsningen foretager struktureret logging, gøres fejlsøgning lettere. Udover udvikling og test fordelene, så skal løsningerne overgå til produktion og drift på et tidspunkt. Hvis driftafdelingen skal have en chance for at kunne agere/reagere fornuftigt og hurtig på eventuelle kritiske systemfejl, så skal alle komponenter på en begavet måde give besked om hvad fejlen er.
Hvorfor et loggingframework?
Basalt set, så implementeres loggingframeworks for kunne konfigurere sig ud af hvordan selve loggingen skal foregå. Det er vigtigt fordi, at vi ved deployment tidspunktet gerne vil kunne bestemme hvilke informationer, samt hvortil der skal logges, f.eks. til eventlog, flat file, rolling file, msmq etc. Generelt for Enterprise Library er at man selv udvide de forskellige Application Blocks så de passer til ens behov.
Hvordan virker det så?
Før vi kigger på konfigurationen, så lad os hurtigt kigge på hvad der skal til i koden for at log-enable din kode.
Ind med namespaces:
1: using Microsoft.Practices.EnterpriseLibrary.Logging;
2: using System.Diagnostics;
I det efterfølende er der fire scenarier. Linie 1 skriver en besked i debug kategorien - altså noget der bruges til udvikling. Linie 4 initierer en logentry uden kategori, men sat til Critical, altså noget vi skal fange og logge. Linie 7 logger en besked i to kategorier (General og RaiseAlert) sat til Error. Sidste logentry i linie 10 logger til to kategorier, og er blog en information.
Det som man skal ligge sig fast på her er hvordan man bruger de forskellige properties på LogEntry.
- Hvilke kategorier man bruger (sæt selv nogle ind, jeg har valgt at bruge Debug, General, RaiseAlert)
- Hvornår man bruger hvilke TraceEventTyper (Critical, Error, Warning, Information, Verbose etc)
- Hvordan man bruger priority
- Hvad man skriver i message og title - formentlig er det en god ide at have en standard, så ikke det bliver til ren lyrik, eller dårlige citater
- Desuden er det en god ide at eventid er unikt, således at man entydigt kan referere til en bestemt type fejl
1: LogEntry le = new LogEntry { Categories = new string[] { "Debug" }, Message = "Starting app", Severity = TraceEventType.Verbose, Title = "Starting app", Priority = 1000, EventId=1 }; 2: Logger.Write(le);
3:
4: le = new LogEntry { Message = "No category, but critical", Severity = TraceEventType.Critical, Title = "Easy comes, easy goes", Priority = 1, EventId=2 }; 5: Logger.Write(le);
6:
7: le = new LogEntry { Message = "Category & and criticial", Categories = new string[]{"General", "RaiseAlert"}, Severity = TraceEventType.Error, Title = "Whats up doc?", Priority = 1, EventId=3 }; 8: Logger.Write(le);
9:
10: le = new LogEntry { Categories=new string[]{"Debug", "General"}, Message = "Debugging info", Severity = TraceEventType.Information, Title = "I will be back!", Priority = 1, EventId=4}; 11: Logger.Write(le);
Efterfølgende så kan jeg (eller en anden) så tage stilling til hvor jeg have kanaliseret de forskellige fejlbeskeder hen, samt hvad der skal logges. Selv er jeg fan er logfiler ;-) Men når først man går i produktion, så er der formentlig nogle processer og værktøjer man skal tilpasse sig, således driften kan holde enderne samme på systemet.

Jeg har valgt en konfiguration som ser ud som følende, hvis man bruger "enterprise library designeren". Jeg starter med at vise designeren. Selve App.config konfigurationen er inkluderet forneden.
Formatters
Her specificerer man hvad man vil have logget, samt hvilket format det skal have: Timestamp: {timestamp(local)}
Hvis ikke du har (local) med, så rammer du ikke den rigtige tidszone.
Trace Listeners
Jeg har konfigureret 4 trace listeners. 1 TraceListener der logger til Console. 2 TraceListener der logger til filer, Error FlatFile TraceListener skriver til c:\temp\myapp\error.log, og Debug FlatFile TraceListener skriver til c:\temp\myapp\debug.log. Desuden er der en Formatted Eventlog Tracelistener der skriver windows eventloggen.
Special Sources
Her kan du vælge at binde dine forskellige trace listeners op imod nogle predefinerede kilder. Eksempelvis skriver jeg alle logentries som ikke har en kendt kategori til min Error FlatFile TraceListener. Alle fejl ryger i samme TraceListener.
Category Sources
Lidt mere interessant bliver det i Category sources. Her kan du specificere hvilke TraceListeners der skal bruges til hver kategori. Her har jeg kun 3 kategorier. En logentry kan godt have mere end en kategori (se linie 7 i eksemplet ovenfor), hvilket betyder beskeden bliver logget til flere tracelisteners.
Filters
Sidst har man helt overordnet mulighed for at sætte filtre op for hvad man ønsker logget.
Resultatet af ovenstående er følgende App.Config fil.
1: <?xml version="1.0" encoding="utf-8"?>
2: <configuration>
3: <configSections>
4: <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
5: </configSections>
6: <loggingConfiguration name="Logging Application Block" tracingEnabled="true"
7: defaultCategory=" " logWarningsWhenNoCategoriesMatch="true">
8: <listeners>