I have been working around multi threaded services for quite a while now. And as you may know, multi threading services are very hard to debug. When debugging multi threaded applications one must collect run-time information without disturbing the threads and introducing delays that would ultimately cripple the service or render the debug effort meaningless. Clearly, I needed to have the program send real-time messages.
I tried using the Windows event log as a target but found the Windows Event Viewer to be at least irritating to use. I then switched to using the Windows method OutputDebugString to send messages about the program’s state. I used Delphi’s Event Log facilities when possible to receive the messages. Otherwise, I used Sysinternals’ Debugview to receiver the messages.
This was indeed a better solution but not perfect as some of the systems that I inherited grew in complexity and services became distributed across multiple computers. I currently maintain a Windows service that has six threads that interact with as many as 132 devices over a network and stores collected data on a SQL database. This caused bugs to get trickier to resolve. I decided to change my debugging strategy to include an IP component.
I chose UDP/IP for the lower overhead and the “send it and forget it” operation – that meant that the debugged programs would not be affected by the debug message recipient not being on-line. I also chose the destination address to always be 127.0.0.1. That way I could ship products with some debugging enabled without affecting the users’ network at all.
I know, this may not seem much different that using OutputDebugString. But the twist was that I created a “forwarder service” that forwarded all the UDP/IP messages to an external computer where an UDP/IP client was up and running. That allowed me to control when debug traffic got outside the host and where it went.
The UDP/IP client is able to display messages received in real time as well as automatically store messages in text files that can be easily imported to Microsoft’s Excel or OpenOffice’s SpreadSheet where you can filter and sort messages to your heart’s content.
The UDP/Client is also able to receive messages from multiple sources and that give one the ability of seeing how different components interact and contribute to create an issue. This becomes an advantage in solving issues generated by concurrent programs running on a system.
My current solution has the following parts:
- LibEventLog.pas – This unit contains the TMsgLogger object declaration as well as an initialization section that instantiates the Object. This object is responsible for sending the messages either through OutputDebugString and/or UDP/IP. It also has the ability to redirect assertions. In order to use the the EventLog object all one has to do is to include this unit in the use clause of the units that need to send messages.
- UDPFwrdr.exe – This is a Windows service that intercepts and forwards the UDP/IP messages.
- UDPConfig.cpl – This is a Control Panel applet that allows the Forwarder’s destination address to be changed.
- UDPMonitor.exe – This is the UDP/IP client that receives messages generated by the application using LibEventLog and forwarded by UDPFwrdr. UDPMonitor receives, displays and saves all messages received.
LibEventLog is currently using Indy 10 and I tested it in Delphi 7, 2006 and 2007.
I have included the source code here so you can download it and use it. Please let me know what you think.
If you make any improvements I would ask you to submit those back to me.