STLogFile - easy way to trace debug info
By Nicholas Tsipanov, September 02, 2002.
Introduction
There are several problems connected with Smartphone 2002 applications debugging. First of all,
there is a class of programs that cannot be debugged at all since you cannot attach to a process
under Windows CE. For example, consider a today plug-in or a device driver. Another problem is that debugging through a serial or USB cable is really slow.
An application log solves those problems. Also it helps to diagnose customer side problems.
This article explains using log files and gives a powerful free log file library for Windows CE.
Download
Preface
TRACE(..), TRACE(..), TRACE(..).. How often do you write these statements in
your MFC application? And how much time did you spend running your program under
debugger? It gets really boring to wait while this program starts, "synchronized
exception information" (hey, I don't use exceptions in my program!), and finally
starts.... Yes, buying a network CF card would eliminate this waiting, but what
would you do if your application fails only on your customer site (well, what's
he doing to my program?) and you cannot find out the solution until you run your
program under debugger in the conditions your program has on customer's site?
The answer is as simple as programming (kidding) and as old as programming
(kidding again). Logging!
STLogFile
Here we present you a simple solution which enables you to easily add logging
to your project. It has some additional features, which make this piece of code
not only a logging tool but a debugging and a profiling one. To make a long
story short here we will shortly describe its usage and it is for you to decide
if this code is worth anything or not.
Installation
What? I n s t a l l a t i o n??? No, no installation. Simply put your copy of
STLogFile.h into a directory where you code can reach it via #include and that's
it. Working directory is a the perfect place to put it but you may have a kind
of shared include directory for you project and then it would be better to put
the STLogFile.h there. After that add the #include "stlogfile.h" line into the
sources where you are going to use it and you're ready. As to me, I prefer to
include it into the "stdafx.h" since it is guaranteed that it will be defined
already in any .cpp file where I want to use it (unless you don't use
precompiled headers, but in this case you know what to do).
Logging macros
STLOG_WRITE
This is the main macro, which caused this article to be written. It has TRACE
usage semantics (or printf if you know what does it mean):
STLOG_WRITE(_T("the line to be logged, string: %s, number: %d"), szString, nNumber);
STLOG is the synonym for STLOG_WRITE for short. There is an option
(STLOG_USE_FOR_TRACE - see below) for the log file to use it instead of TRACE
macros.
STLOG_MARKER
If you want to mark every enter and exit of the code block you can use STLOG_MARKER macro:
{
STLOG(_T("Statistics calculations"));
...your code here...
}
This will print >>>[Statistics calculations] and
<<<[Statistics calculations] every time the execution reaches this
piece of code. More common using of this macro is marking function executions:
int MyClass::MyFunction() {
STLOG_MARKER(_T("MyClass::MyFunction"));
if (moon_phase == moon_full)
return 1;
if (moon_phase == moon_new)
return 2;
return 3;
}
This will print entering markings for this function on enter and exit
wherever the execution leaves this code.
STLOG_WRITE_DATA
char Buffer[435];
FillTheBuffer(Buffer, 435);
STLOG_WRITE_DATA(Buffer, 435);
What can be more simple?
Debugging macros
At the moment we have only one macro that could fit this section, if you have
any ideas, please share them with us.
STLOG_LASTERROR
Whenever you call a system function that can fail you can print out what
caused the problem:
HANDLE hFile = CreateFile(....);
if (INVALID_HANDLE == hFile)
{
STLOG_WRITE("Cannot open file");
STLOG_LASTERROR;
}
And you will have a textual description of the problem in the log file.
Profiling macros
Before describing the log file profiling features it would be appropriate to
say that all measured timing include time for file operation, which slightly
increases execution time, therefore this method could only help to *estimate*
and compare execution times to find bottlenecks of your code.
STLOG_PROFILE_FUNCTION
...
STLOG_PROFILE_FUNCTION(Calculate());
...
This code will estimate the time needed for function execution. Simple. When
the logging is turned off this will be transformed to straight call to
Calculate().
STLOG_PROFILE_BLOCK
{
STLOG_PROFILE_BLOCK;
.. code here ...
}
This sample of code prints to log file the time when the execution entered to
the profiled block, when the execution leaves it and the time interval between
the two points. When your program finishes, this macro will print profiling
statistics, like how many times this code has been executed, how much time did
it take in total, in average, maximium and minimum timings.
STLOG_PROFILE_CHECKPOINT
Sometimes you want to have intermediate timings and STLogFile has a solution
for this case:
{
STLOG_PROFILE_BLOCK;
Phase0();
STLOG_PROFILE_CHECKPOINT
Phase1();
STLOG_PROFILE_CHECKPOINT
Phase2();
}
This will print timings between the check points and the time from beginning
of the block every time execution reaches any check point.
Options
To make the logfile flexible (different projects have different requirements
for logging) we made some kind of fine tuning preferences.
STLOG_DEBUG
This is the first and the main option for the log file. To turn the logging
off put comment markings to the line that defines it, and your logging will be
turned off.
STLOG_CREATE_NEW
If you want every start to create a new log file then use this define. New
log files will have names like <executable>XX_log.txt, where XX is some
number. Otherwise it will always use the name <executable>_log.txt for log
files.
STLOG_CREATE_FILE_IN_THE_SAME_DIRECTORY
If you want to have a log file in the same directory where your executable is
then leave this define. Otherwise the log file will be created in the root
folder. For desktop systems this means the root directory of the disk where your
executable is located.
STLOG_PRINT_COMPILE_INFO
This will print in log file the file name and a line number where STLOG_WRITE
macro has been encountered. I didn't find this macro useful and it's commented
by default.
STLOG_USE_FOR_TRACE
TRACEs will be printed to the log file.
Conclusion
Occasionally log files are the only way to debug the code and every developer
reinvents the wheel for this task. It might be useful to have a common way to do
it. I hope this article would help Windows developers to save some time on it.
Discuss
Discuss this article.
Here you can write your comments and read comments of other developers.
|