Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CTracerST v1.0

0.00/5 (No votes)
17 Jun 2000 1  
A flexible trace class for consistent application debug traces.
  • Download demo project - 148 Kb
  • Download source files - 8 Kb
  • Sample Image - CTracerST.jpg

    SoftechSoftware homepage
    SoftechSoftware Email

    If you write commercial or real-time applications you are familiar with trace strings. These traces are those cryptic strings sent to screen or disk that help the programmer during the debug phase of his work.

    If you write more than one application that needs traces you will look for a standard, simple to integrate and easy to use trace system.

    CTracerST presents a consistent way to implement and use a trace system inside your applications.

    Features of this class are:

    • Supports up to 10 different trace levels (can be increased to infinite)

    • Buffers trace strings
    • Trace strings can be automatically saved on disk
    • Automatically writes files of predefined size
    • Trace strings can be displayed in any way desired (up to the programmer)
    • Full UNICODE support
    • Writes a plain text file (UNICODE compatible)

    This class has been tested on:

    • Visual C++ 6.0 sp3

    • Windows NT Workstation 4.0 sp6a
    • Windows 2000

    Terms of use

    You can use CTracerST anywhere you want, without limitations.

    You can include this software in DLLs, libriaries, CD-ROM collections etc. You are only asked to give credits to SoftechSoftware for this portion of code.

    If you use this class a screenshot of your application or a download link (if shareware/freeware) is welcome.

    If you find bugs or make improvements please let SoftechSoftware know it!

    Abstract

    Basically CTracerST accepts a string and a trace level. If the level is enabled the string is stored internally else it is discarded. Also, if save-to-disk is enabled, the string is immediately saved.

    Why trace levels?

    Your application can produce a lot of trace strings. If you assign a particular type of information (info/errors/fatal errors ...) to each string then you will have the ability to programmatically select which type of traces produce. For example if you trace all information at level 0 then all information can be toggled on and off by disabling level 0 traces.

    Trace strings are stored internally in the form of a STRUCT_TRACERST structure:

    typedef struct _STRUCT_TRACERST
    {
    DWORDdwLevel;
    TCHARszText[256];
    SYSTEMTIMEcsTime;
    } STRUCT_TRACERST;

    You will need to play with this structure only if your application needs to display the trace strings.

    CTracerST saves strings on disk in a plain text file. If your application is built for UNICODE then these text files will be UNICODE, that is, the characters 0xFFFE are written at the top of file. This marker seems to be a standard mode to recognize an UNICODE text file (Notepad does this).

    The filename of the produced files is in the form ddmmyyyy_Tracexxx.txt where xxx is a number starting from 000 to 255. CTracerST has the ability to produce files more or less of a predefined size; eachtime a new file is created it will be numbered sequentially from 0 to 255. The numeration starts by default from 0.
    Example: 07062000_Trace000.txt

    Trace strings are written in the form hh:mm:ss:ms [level] < trace string>
    Example: 09:26:03:0214 [0] Database started (Size = 32672 bytes)

    CSharedQueueST

    CTracerST stores trace strings using a queue implemented through a class called CSharedQueueST.
    When an element is added to the queue this class has the ability to:

    • Send a message to a window

    • Set an event
    • Resume a thread

    Using one of this ways an application that needs to display trace strings can detect when a new string is available.

    The correct steps required to get a trace string from CTracerST are:

    • Wait for a message, an event or a thread-resume

    • Read the first available trace string (a STRUCT_TRACERST structure)
    • Prepare the string as needed by the application
    • Do whatever you want with the string

    The following example shows how to display trace strings using a listbox:

    STRUCT_TRACERST    csTracer;
    TCHAR szText[512];
    int nIndex;

    // Get the first string trace available
    COLOR="BLUE">if (m_Tracer.GetItem((char*)&csTracer) == TRACERST_OK)
    {
    // Prepare a human-readable version of the string
    ::wsprintf(szText, _T("%02d:%02d:%02d:%04d [%lu] %s"), csTracer.csTime.wHour,
    csTracer.csTime.wMinute,
    csTracer.csTime.wSecond,
    csTracer.csTime.wMilliseconds,
    csTracer.dwLevel,
    csTracer.szText);
    COLOR="GREEN"> // Add the string to our listbox
    nIndex = m_lbxTrace.AddString(szText);
    COLOR="GREEN"> // Hilight the just added string
    COLOR="BLUE">if (nIndex != LB_ERR && nIndex != LB_ERRSPACE)
    m_lbxTrace.SetCurSel(nIndex);
    } // if

    How to integrate CTracerST in your application

    Include in your application's project the following files:

      <LI
           CLASS="mvd-PRE">TracerST.h
      <LI CLASS="mvd-PRE">TracerST.cpp
      <LI CLASS="mvd-PRE">SharedQueueST.h
      <LI CLASS="mvd-PRE">SharedQueueST.cpp
      <LI CLASS="mvd-PRE">Macros.h

    declare a CTracerST object:

    CTracerST    m_Tracer;

    initialize your object:

    m_Tracer.Create(250, 64, FALSE, this->m_hWnd, WM_APP + 1);

    That's all! To use your tracer:

    m_Tracer.Trace(0, _T("Trace string"));

    CTracerST methods

    Constructor

    CTracerST();

    Standard constructor. It does nothing.

    Create

    DWORD Create(DWORD dwMaxItems,
    DWORD dwMaxFilesize,
    BOOL bUseAlternateDateFormat,
    HWND hWndParent = NULL,
    UINT nMsgParent = NULL,
    HANDLE hEventParent = NULL,
    HANDLE hThreadHandle = NULL);

    Initializes a CTracerST object.

    Parameters:

    • dwMaxItems

      [IN] Maximum number of trace strings the object can hold.

    • dwMaxFilesize

      [IN] Maximum size (in KBytes) of the saved files.

    • bUseAlternateDateFormat

      [IN] Indicates if an alternate date-format convention must be used.
      If TRUE files will be saved in the form mmddyyyy_Tracexxx.txt
      If FALSE files will be saved in the form ddmmyyyy_Tracexxx.txt

    • hWndParent

      [IN] Handle of the window that will receive a message every time a string is traced.

    • nMsgParent

      [IN] Message to send every time a string is traced.

    • hEventParent

      [IN] Handle of the event to set every time a string is traced.

    • hThreadParent

      [IN] Handle of the thread to resume every time a string is traced.

    Return value:

    • TRACERST_OK

      Object initialized successfully.

    • TRACERST_QUEUEERROR

      An error occured while initializing the queue.

    Example:

    DWORD    dwRetValue;
    dwRetValue = m_Tracer.Create(250, 64, FALSE, this->m_hWnd, WM_APP + 1);
    ASSERT(dwRetValue == TRACERST_OK);

    Trace

    DWORD Trace(BYTE byLevelNumber, LPCTSTR lpszText);

    Traces a string.

    Parameters:

    • byLevelNumber

      [IN] The zero-based trace level number.

    • lpszText

      [IN] String to trace. Maximum 256 TCHARs are allowed.

    Remarks:

    If the trace level is disabled the string will be ignored and discarded. Also no message/event/thread will be sent/set/resumed. If the trace level is outside the limits the string will be processed. You can use SetTraceLevels to enable/disable trace levels.

    If the save flag is set then the string will be written to disk in the specified directory. You can use SetFlags to set/reset flags and SetTraceDirectory to set the directory in which to save trace files.

    CTracerST comes with a default of 10 trace levels. If you need more levels just change the TRACERST_MAX_LEVELS define located in the TracerST.h file.

    #defineTRACERST_MAX_LEVELS  10

    Return value:

    • TRACERST_OK

      String traced successfully.

    • TRACERST_QUEUEERROR

      An error is reported by the queue.

    Example:

    DWORD    dwRetValue; 
    // This string will be traced only if level 2 is enabled
    dwRetValue = m_Tracer.Trace(2, _T("Trace string"));
    ASSERT(dwRetValue == TRACERST_OK);
    COLOR="GREEN">// This string will always traced
    dwRetValue = m_Tracer.Trace(99, _T("Trace string 2"));

    GetItem

    DWORD GetItem(char* szpBuffer,
    BOOL bRemove = TRUE,
    LPDWORD lpdwNumBytesCopied = NULL);

    Gets the first available trace data from the CTracerST's queue.

    Parameters:

    • szpBuffer

      [IN] Points to a STRUCT_TRACERST structure that will receive the trace data.
      It must be cast as char*.

    • bRemove

      [IN] Indicates if the trace data must be removed from the queue.
      If TRUE the trace data will be removed from the queue.
      If FALSE the trace data will remain in the queue. A second call to GetItem will return the same trace data.
      This value should be always TRUE.

    • lpdwNumBytesCopied

      [OUT] Returns the number of bytes copied in szpBuffer.
      This value is always SIZE_STRUCT_TRACERST.

    Return value:

    • TRACERST_OK

      Function executed successfully.

    • TRACERST_QUEUEERROR

      An error is reported by the queue.
      This value also indicates that the queue is empty (no trace data available).

    Example:

    STRUCT_TRACERST    csTracer;
    TCHAR szText[512];
    int nIndex;

    // Get the first string trace available
    COLOR="BLUE">if (m_Tracer.GetItem((char*)&csTracer) == TRACERST_OK)
    {
    // Prepare a human-readable version of the string
    ::wsprintf(szText, _T("%02d:%02d:%02d:%04d [%lu] %s"), csTracer.csTime.wHour,
    csTracer.csTime.wMinute,
    csTracer.csTime.wSecond,
    csTracer.csTime.wMilliseconds,
    csTracer.dwLevel,
    csTracer.szText);
    COLOR="GREEN">// Add the string to our listbox
    nIndex = m_lbxTrace.AddString(szText);
    COLOR="GREEN">// Hilight the just added string
    COLOR="BLUE">if (nIndex != LB_ERR && nIndex != LB_ERRSPACE)
    m_lbxTrace.SetCurSel(nIndex);
    } // if

    SetTraceDirectory

    void SetTraceDirectory(LPCTSTR lpszTraceDir);

    Sets the directory where trace files are to be saved.

    Parameters:

    • lpszTraceDir

      [IN] Pointer to a null-terminated string that specifies the directory where save trace files.
      This directory must exists and must be backslash terminated.
      Maximum _MAX_PATH TCHARs are allowed.

    Remarks:

    By default trace files are saved in the directory from which the application loaded.

    Example:

    m_Tracer.SetTraceDirectory(_T("c:\\traces\\"));

    GetTraceLevels

    void GetTraceLevels(LPBYTE lpbyTraceLevels);

    Retrieves the state (enabled/disabled) of all trace levels.

    Parameters:

    • lpbyTraceLevels

      [OUT] Pointer to an array of bytes that will receive the trace levels state.

    Remarks:

    The specified byte array must be large enough to receive the state of all available trace levels.
    A state set to 1 means enabled, while set to 0 means disabled.

        byArray[0]                          ---   Trace level 0 state
    .
    .
    .
    byArray[TRACERST_MAX_LEVELS - 1] --- Trace level TRACERST_MAX_LEVELS - 1 state

    Example:
    the following example tests the state of the trace level number 0.

    BYTE    byTraceLevels[TRACERST_MAX_LEVELS];

    m_Tracer.GetTraceLevels(byTraceLevels);
    if (byTraceLevels[0] == 1) // Enabled
    {
    }
    COLOR="BLUE">else // Disabled
    {
    }

    SetTraceLevels

    void SetTraceLevels(LPBYTE lpbyTraceLevels);

    Sets the state (enabled/disabled) of all trace levels.

    Parameters:

    • lpbyTraceLevels

      [IN] Pointer to an array of bytes that specifies the state of all trace levels.

    Remarks:

    The specified byte array must hold the state of all available trace levels.
    A state set to 1 means enabled, while set to 0 means disabled.

    Example:
    the following example sets to enabled all trace levels.

    BYTE    byTraceLevels[TRACERST_MAX_LEVELS];

    ::FillMemory(&byTraceLevels, sizeof(byTraceLevels), 1);
    m_Tracer.SetTraceLevels(byTraceLevels);

    GetFlags

    void GetFlags(LPBYTE lpbyFlags);

    Get CTracerST flags.

    Parameters:

    • lpbyFlags

      [OUT] Pointer to a byte that will receive the flags.

    Example:

    BYTE    byFlags;
    m_Tracer.GetFlags(&byFlags);

    SetFlags

    void SetFlags(LPBYTE lpbyFlags);

    Set CTracerST flags.

    Parameters:

    • lpbyFlags

      [IN] Pointer to a byte that specifies the new flags.

    Remarks:

    Each bit of the byte specifies a single flag.

    Currently only one flag is supported:

    • TRACERST_FLAG_SAVE

      Save traces to disk.

    Example:
    the following example sets the save-to-disk flag.

    BYTE    byFlags;

    m_Tracer.GetFlags(&byFlags);
    byFlags |= TRACERST_FLAG_SAVE;
    m_Tracer.SetFlags(&byFlags);

    GetVersionI

    short GetVersionI();

    Returns the CTracerST version as a short number.
    Divide by 10 to get actual version.

    GetVersionC

    LPCTSTR GetVersionC();

    Returns the CTracerST version as a string.

    Example:

    TCHAR    szText[128];

    ::wsprintf(szText, _T("Version is: %s"), CTracerST::GetVersionC());
    ::MessageBox(NULL, szText, NULL, MB_OK);

    Remarks

    CTracerST is Critical-Section protected. This makes it callable from different threads at the same time without problems (thread-safe). It's currently used in two industrial application without problems of any type.

    The only area where an application must take care is to not fill the trace queue. This queue has a limited number of trace strings that can buffered, as specified in the Create function (dwMaxItems parameters). Trace data are not removed from the queue by CTracerST. Even if an application doesn't need to display traces it should remove trace datas from the queue. It can be done with the following example:

    // The application handles the WM_APP + 1 message with the following function
    LRESULT MyApp::On_RM_TRACE(WPARAM wParam, LPARAM lParam)
    {
    m_Tracer.GetItem(NULL);
    COLOR="BLUE">return 0;
    } // End of On_RM_TRACE

    Want to include CTracerST in a DLL ?

    CTracerST is ready to be used from inside a DLL. You need to export from your DLL CTracerST and also CSharedQueueST. Include in your DLL's project the following files:

      <LI
           CLASS="mvd-PRE">TracerST.h
      <LI CLASS="mvd-PRE">TracerST.cpp
      <LI CLASS="mvd-PRE">SharedQueueST.h
      <LI CLASS="mvd-PRE">SharedQueueST.cpp
      <LI CLASS="mvd-PRE">Macros.h

    Add to your DLL's project settings the following defines:

      <LI
           CLASS="mvd-PRE">_CMLHTDLL_NOLIB_
      <LI CLASS="mvd-PRE">_CMLHTDLL_BUILDDLL_

    From TracerST.h comment the following line:

    #define _TRACERST_NODLL_

    then update the various #pragma comment(lib, "???") according to your DLL produced .lib files.

    From SharedQueueST.h comment the following line:

    #define _SHAREDQUEUEST_NODLL_

    then update the various #pragma comment(lib, "???") according to your DLL produced .lib files.

    History

    • CTracerST v1.0

      First release

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here