Documentation ACoreLib.Tracer
Tracing a messageTracing startup of applicationSetting up TracingAccessing traced messagesDealing with exceptionsExtending trace processing & GUI integration
Tracing a message
The idea of tracing is to write (debugging) messages to a trace. The trace can then be used to investigate why a certain problem happened, or, more precisely, what the application did just before the problem happened.
Tracer differentiates 4 kinds of tracing messages, depending on which tracing method is called:
- Tracer.TraceLine()
- Tracer.WarningLine()
- Tracer.ErrorLine()
- Tracer.Exception()
It is up to the application what the difference between just a trace, warning or error is.
Tracer writes them all in the same way into the trace, marking them accordingly. Additionally, the application can for example configure that all messages get stored in RAM, only warning and errors written to a trace file and errors emailed to a development account.
One message can be composed by calling several times
Tracer.Trace() and a message closing
Tracer.TraceLine(). If several threads call Tracer.Trace() at the same time, for each thread its own trace message gets created.
Tacer.TraceLineWithFilter() takes additionally to the trace message a text, which later can be used for filtering.
Tracer.Exception() should be used whenever an exception got caught. They are treated by the
Tracer like any other messages, although all exception details get shown in the trace and if a debugger is attached, it might execute a Break().
Tracing startup of application
To use full tracing functionality from the very first line of code executed,
Tracer is made a static class .
It might be useful to trace the starting of the application like this:
Tracer.TraceLine("Application started");
Configurration configuration;
Tracer.TraceLine("Read Configuration started");
try {
configuration = ReadConfiguration();
} catch (Exception ex) {
Tracer.Exception(ex, "Read Configuration failed, used default configuration");
configuration = Configuration .Default;
}
Tracer.TraceLine(configuration.ToString());
Tracer.TraceLine("Read Configuration completed");
Tracer.TraceLine("Start Connect DB");
try {
ConnectDB();
Tracer.TraceLine("DB connected");
} catch (Exception ex) {
Tracer.Exception(ex, "Connect DB failed");
}
Comments
- Very first line writes to trace. Among other things this is useful to show in the trace when exactly the trace has started.
- For every step needed to setup the application, use it's own try statement. If there is an exception, do something else so that the application still can start and display some (error) information
Setting up Tracing
The application can configure some tracing functionality:
Tracer.IsTracing = true;
Tracer.IsWarningTracing = true;
Tracer.IsErrorTracing = true;
Tracer.IsExceptionTracing = true;
Tracer.IsBreakOnWarning = false;
Tracer.IsBreakOnError = true;
Tracer.IsBreakOnException = true;
//setup tracing file
TraceLogFileWriter =new TraceLogFileWriter(
directoryPath: Environment.CurrentDirectory + @"\LogFiles",
fileName: "FinanceLog",
maxFileByteCount: 10*1000*1000,
maxFileCount: 5,
logFileWriterTimerInitialDelay: 1000, //msec
logFileWriterTimerInterval: 10*1000); //msec
This code does not need to be right at the beginning of the application, since
Tracer can work with its default settings without losing any messages. It's possible to read some (tracing) configuration and trace if there goes anything wrong, even
Tracer has not been set up already and then setting up
Tracer with the read configuration data.
The
IsXxxTracing flags control if a normal message, Warning, Error or Exception gets written in the
Tracer RAM buffer or immediately discarded.
The
IsBreakOnXxx controls if the debugger should break in an attached debugger if a Xxx type of message gets traced. The developer can change the values of these flags using the debugger, allowing him to control easily how often the debugger will break.
The constructor of
TraceLogFileWriter automatically registers its instance with
Tracer and the already traced messages will be written to the indicated log file. Once the log file size is bigger than
maxFileByteCount, a new file gets created. If more than
maxFileCount exist, the oldest files get deleted, to prevent tracing using up all disk space. Setting one of these parameters to 0 will prevent that the corresponding
max value gets checked.
Accessing traced messages
To get all stored trace messages, just call
Tracer.GetTrace(). It returns an array of
TraceMessage, sorted by their creation time. During the execution of
GetTrace(), no new trace messages get added to guarantee a consistent result.
Use
TraceMessage.ToString() for a simple way to display the trace messages.
Dealing with exceptions
Throwing exceptions
It would be good if the debugger would break if the code has detected an illegal condition and throws a new exception. This could be achieved through some VS settings or by setting manually a breakpoint at every
throw statement, which is rather cumbersome.
A better solution is not to use
throw statements, but to call
Tracer.Thow(new Exception()), which will throw the exception instead. If a debugger is attached and
IsBreakOnException is true, the debugger breaks and the exception to be thrown is displayed in the debugger output window. This has the big advantage that the variable content of the throwing method is still available, which makes it much easier to investigate what was the problem. When investigating exceptions only once they are thrown, this data is lost.
Catching exceptions
Some exceptions might be expected to occur sometimes. If the program should react to the exception by doing something else, the exception should be caught in a
try catch statement. The rest of the exceptions should be caught in a central place which is done differently in different ,NET technologies:
Technology | |
Console Application | try catch statement |
Windows Form Application | Application.ThreadException |
WPF Application | Application.DispatcherUnhandledException |
ASP.NET | Global.asax: ApplicationError_ |
multi threading | each thread needs its own try catch statement |
Whether an exception is caught locally or globally, it is in both cases a good idea to trace it with
Tracer.Exception(exception). This writes the exception with all the exception details to the trace. If a debugger is attached and
IsBreakOnException is true, the details get also displayed in the debugger output window.
Extending trace processing & GUI integration
Often an application needs further processing of trace messages, like displaying warnings, errors and exceptions to the user (GUI), collecting all errors and exceptions in a central database or emailing exceptions to developers. This can be easily done by registering to the event
Tracer.MessagesTraced.
Applications with a user interface could provide the following functionality:
- Display and editing of Tracer settings
- Displaying of errors and exceptions to the user. It should be easy to copy the trace information so that it can be sent to support.
- Display of presently stored trace