Logging and Debugging using the Event Viewer and DebugView
From Dolphin Map
This tutorial explains how to use Dolphin Smalltalk to create Events shown in the Windows Event Viewer. In additon Dolphin's capability of using generic Windows Debug APIs is shown.
Contents |
Windows Event Viewer
The Windows Event Viewer knows four types of events:
- General (Success)
- Information
- Warning
- Error
Dolphin Smalltalk allows you to generate such events from your application. SessionManager implements four methods to achieve this:
-
SessionManager>>logSuccessEvent: -
SessionMananer>>logInformationEvent: -
SessionManager>>logWarningEvent: -
SessionManager>>logErrorEvent:
Using these four methods your application is able to create Event entries. For example:
SessionManager current logErrorEvent: 'An Error'. SessionManager current logInformationEvent: 'Information'. SessionManager current logSuccessEvent: 'Success'. SessionManager current logWarningEvent: 'Warning'.
Windows Debug Output
Windows offers various APIs for applications to generate debug output. One of these functions is OutputDebugString.
DebugTraceStream and Trace
Dolphin Smalltalk provides a nice wrapper around this function in class DebugTraceStream. As the name suggests the interface use to create debug messages is that of a Stream. So you can use most of the Stream methods for DebugTraceStream as well. The sole instance of DebugTraceStream is Trace. There is no need to instantiate another DebugTraceStream
DebugView
Although there are many ways of viewing Debug Output my preferred way to do so is DebugView from sysinternals.com.
DebugView shows Debug Output from various sources (applications, kernelrneven remote machines) and provides powerful featues like filtering and highlighting to not get lost in Debug Date.
Dolphin Integration
Generating Debug output is simple. Just use stream methods on Trace. For example:
Trace nextPutAll: 'Simple Debug Output';flush.
Please note that a message will not be sent until you send #flush or #cr (#cr is sending #flush behind the scenes).
Making it nice
You may notice that - unlike the event viewer - Debug Output does not contain application names (PIDs are possible though). You have to provide them on your own. For example:
Trace nextPutAll: SessionManager current applicationName; nextPut: $:; space; nextPutAll: 'Verbose Debug Output'; flush
Encapsulate
If we use this once this maybe allright. If we use the same code over and over again we are "violating" Kent Beck's Once and Only Once Law.
So we have to encapsulate the code above. I'm using a method #verboseLog: in DebugTraceStream to do so:
DebugTraceStream>>verboseLog: aString self nextPutAll: SessionManager current applicationName; nextPut: $:; space; nextPutAll: aString; flush
This allows you to simply use Trace>>verboseLog: within your code:
Trace verboseLog: 'Encapsulated verbose Debug Output'.
Conditional Debugging
The "C"-way of defining something like "#define TRACE(x)" to output the debug string in a debug build and to do nothing in other builds is not possible in Smalltalk.
Smalltalk does not offer something like "conditional" compiling of a method. This means there will always be a reference to Trace in the method.
However you can replace Tracewith a different object: You could implement something like NullTraceStream which has the same methods as DebugTraceStream(at least the methods you are using in your app) ...but these methods do nothing (just return self).
Replace the Trace instance with your own (Trace := NullTraceStream new) and you're done. You could even do this conditionally during runtime/startup (e.g. only replace if no commandline parameter "-d" was found).
