![]() |
General Programming »
Macros and Add-ins »
General
Intermediate
SS_Log, *easily* implement logging in code, then double-click on log message to jump to code.By Steve SchanevilleThis is a logging class that outputs to a file or log window, provides filtering of messages without re-compile, and allows double-clicking on log message to jump straight to code location. |
VC6, VC7Win2K, WinXP, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
This link is no longer kept up-to-date. See this article instead.
Often times we want to create a log of what steps a program takes during run-time. Maybe our program works fine during a debug build but crashes during a release build. Or maybe we are developing on WinNT, but testing on Win98 without a development environment on the Win98 machine. Since we can't debug in these cases, it would be nice to have a log of all the steps a program took before it crashed.
This is a set of small projects (all working together) that can ease creating a log of your program�s code path at run-time. Some features include:
sprintf-style messages with variable length parameter lists.
_SS_LOG_INACTIVE in the pre-compiler (NOTE: this removes only the global log code, but support for removal of local logs is note entirely complete). SS_Log class.
SS_Log logging class. It uses a global log and 2 local logs, and demonstrates a few of the features available.
To install the projects, simply place the SS_Log_Window.exe and SS_Log_AddIn.dll files in your %SYSTEMROOT% folder (e.g.: c:\winnt or c:\windows). Don't worry about installing the add-in, as the first time you double-click on a log entry in the SS_Log_Window.exe application, it will ask you if you want to install the add-in.
To integrate the log into your projects, follow these three steps:
#include "SS_Log_Include.h" in any file you would like to produce logs from (do not include SS_Log.h).
If you would like, you can add the SS_Log_Include.cpp, SS_Log.cpp, and SS_RegistryKey.cpp files to your project instead of adding SS_Log.lib and SS_LogD.lib as in step 2.
We will talk about 2 different log types:
By #include-ing "SS_Log_Include.h" in your project, a global log is created for you (assuming you don't have _SS_LOG_INACTIVE #defined). To use the global log, all you have to do is enter a line as follows:
Log("some message here, %d, %s", nValue, szText, ... );
This line will use the global log�s defaults, sending the message to the global log with a "CRITICAL" level. The message goes to a Log Window in debug builds and to the file \SS_Log.log during release builds by default. To override the global log�s defaults, use these calls:
LogFilter( DWORD dwFilter ); LogRemoveFilters( DWORD dwFilter ); LogAddFilters( DWORD dwFilter ); LogFilename( TCHAR* szFilename ); LogWindowName( TCHAR* szWindowName ); LogEraseLog() Log( TCHAR* pMessage, ... ); Log( DWORD dwFilter, TCHAR* pMessage, ... );
When the above global log functions are used, all messages in all threads will go to the same place (specified file, specified log window, or both). If you want to send some messages to a different location, you may create multiple simultaneous logs by defining "local logs" with the following code:
SS_Log myLog;
The following calls can be used for local logs:
myLog.Filter( DWORD dwFilter ); myLog.RemoveFilters( DWORD dwFilter ); myLog.AddFilters( DWORD dwFilter ); myLog.Filename( TCHAR* szFilename ); myLog.WindowName( TCHAR* szWindowName ); myLog.EraseLog() Log( SS_Log* pLog, TCHAR* pMessage, ... ); Log( SS_Log* pLog, DWORD dwFilter, TCHAR* pMessage, ... );
Note that if you don't call the myLog.Filename(...) and myLog.WindowName(...) functions, the local log will default to the same window and file that the global log defaults to, and hence, all messages from both logs will go to the same file/window. An example for a complete local log would be:
SS_Log myLog; myLog.Filename("\\MyLog.log"); myLog.WindowName("My Local Log"); Log( &myLog, "message to local log here, %d, %s", nValue1, szText1 ); Log( "message to global log here, %s, %s", szText2, szText3 );
The first Log(...) call above will send its message to the local log, while the second one will send its message to the global log.
Filters are assigned to each log individually by default, but each log�s default values can be overridden. In addition, every message sent to a log can contain filters that override the log�s default filters. You may then turn each filter type "on" and "off" by setting registry values (created automatically by the SS_Log class). Any message with a filter type that is turned off in the registry will not get sent to the log. This allows you to turn on and off the filters without re-compiling.
(Registry key: "HKEY_CURRENT_USER\Software\SS_Log". For all values, 1=on and 0=off. You can also set the default log file here.)
You set log filters with the LogAddFilters(...), LogRemoveFilters(...), and LogFilter(...) global calls. The following filters are pre-defined (the code includes instructions for adding your own filter types):
LOGTYPE_DEBUG LOGTYPE_RELEASE
LOGTYPE_LOGTOWINDOW LOGTYPE_LOGTOFILE
LOGTYPE_CRITICAL level. Note that unlike the Builds and Outputs types, the Levels types �combine�. That is, if a log or individual message has the LOGTYPE_WARNING and the LOGTYPE_TRACE types specified, then BOTH types must be turned on in the registry for the message to be sent. LOGTYPE_CRITICAL LOGTYPE_WARNING LOGTYPE_NORMAL LOGTYPE_TRACE
While the LogAddFilters(...) and LogRemoveFilters(...) calls work as you'd expect, the LogFilter(...) call does not. The LogFilter(...) does not "set" a log�s filter exactly as specified in the parameter list. Instead, the function is "smart" and tries to figure out what type of filter (Builds, Outputs, Levels, or some combination thereof) the user is trying to set. For example, if the user calls LogFilter( LOGTYPE_TRACE ), the function will set only the Levels type, ignoring the Builds and Outputs types currently set in the filter. Specifically, the function would remove the LOGTYPE_CRITICAL filter (which was there by default), add the LOGTYPE_TRACE filter, and leave the Builds and Outputs types alone. Note the difference if the user had called LogAddFilters( LOGTYPE_TRACE ) instead, where the function would have added the LOGTYPE_TRACE filter and kept the LOGTYPE_CRITICAL filter.
For more examples and detail, see the example project "SS_Log_Test".
A few problems that should be mentioned:
LogEraseLog() at the beginning of every program in order to ensure that your files remain small. I will consider adding a set-able max file size if enough people request it.
#define-ing _SS_LOG_INACTIVE will remove any code that accesses the global log from your project. However, it does not remove 100% of the code used by the local logs. The actual logging (file writing and windowing) gets removed, but the local logs will still create some variables on your stack even when _SS_LOG_INACTIVE is defined.
LogFilter(), LogFilename(), and LogWindowName()). These functions return the associated value that the global log currently holds. Just be aware that if you use these three functions in your code, they will cause a compile error if _SS_LOG_INACTIVE is ever #defined.
SS_Log logging class can significantly reduce your program�s performance (speed). The up-side is, you should regain 100% of your program�s efficiency by #declare-ing "_SS_LOG_INACTIVE" for the pre-compiler (Note: this works 100% on the global log, but the code for the local logs is not 100% removed. The actual logging of messages is removed, but some local log objects and variables will still be created when _SS_LOG_INACTIVE is defined).
Try it out for yourself... by the end of this 11 step tutorial, you will have seen several of the SS_Log class' features, and just how quick and easy it is to integrate into your projects.
OnPaint() method to the CTestView class with the class wizard (press CTRL-W, under "class name", select "CTestView", then double-click on the "WM_PAINT" entry under "messages").
#include "SS_Log_Include.h" to the top of the file, and add Log("We are painting now!!"); and Log(LOGTYPE_NORMAL, "We are painting now!!"); in the CTestView::OnPaint() function. The Log() calls each send a log message, the first with a "Critical" level (by default), and the second with a "Normal" level (overriding the default);
OnPaint function. Drag the "Untitled - test" window around on the screen (making sure that you make a portion of it move off the sides of the screen) and it will send numerous messages to the Log Window, two for each time the OnPaint function is called.
This tutorial showed a few of the features found in the SS_Log class. Experiment will local logs and different combinations of filters.
Steve Schaneville appdev@hotmail.com
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 29 Apr 2002 Editor: Smitha Vijayan |
Copyright 2001 by Steve Schaneville Everything else Copyright © CodeProject, 1999-2009 Web17 | Advertise on the Code Project |