Click here to Skip to main content
Click here to Skip to main content
Go to top

XHtmlLog - Convert text log files to HTML

, 30 May 2003
Rate this:
Please Sign up or sign in to vote.
XHtmlLog converts delimited text log files to HTML for display by a browser. Callback functions allow the output to be customized prior to HTML generation.

Introduction

CXHtmlLog provides a flexible, MFC-free way to format selected fields from a text log file into HTML that can be displayed in any browser. The requirements to use CXHtmlLog are simple: the log file that serves as input to CXHtmlLog must be a text file, and there must be delimiters between each of the fields in the log records. When these two conditions are met, it is easy to set up the CXHtmlLog column properties with headers, color coding, and column order. It is also possible to map input fields to columns in any order you wish - which means that the output column order is independent of the order of the fields in the input log file. Finally, by means of a callback function, it is possible to override any display parameter - including what data is displayed - for each column separately.

CXHtmlLog: What It Does

An example may be the best way to illustrate what CXHtmlLog does. The following screenshot shows sample output of the demo app:

XHtmlLog screenshot

This screenshot was generated from the following input lines:

 0, 2389.3, C:\\apps\\Shuttle.exe, C:\\src\\Shuttle.cpp, 342, Captain!  
A shuttle craft is approaching.
 3, 2403.7, C:\\apps\\Battle.exe, C:\\src\\Battle.cpp, 474, Captain!  
We have been hit.  Shields are at 80%.
 2, 2581.4, C:\\apps\\Crystalline.exe, C:\\src\\Crystalline.cpp, 1870, 
Captain!  The Crystalline entity is approaching the ship.
 1, 2641.1, C:\\apps\\Dead.exe, C:\\src\\Dead.cpp, 922, Jim!  For God's sake 
man! He's dead!
 4, 2890.1, C:\\apps\\WarpCore.exe, C:\\src\\WarpCore.cpp, 556, Captain!  
The warp core containment field has failed.  Warp breach imminent.
The screenshot shows that the first field (the priority) in the input file is the second column in the HTML output, and the second field (the stardate) is the first column in the output. This happens because of the field mapping that is possible with CXHtmlLog. Here is the code:
    CXHtmlLog log;

    XHTMLLOG_COLUMN_PROPERTIES props;

    props.lpPropFunc = PropCallback;

    props.nField = 1;
    _tcscpy(props.szHeader, _T("Stardate"));
    log.SetColumnProperties(0, &props);

    props.nField = 0;
    _tcscpy(props.szHeader, _T("Priority"));
    log.SetColumnProperties(1, &props); 
Also note that the fourth and fifth input fields have been combined into the fourth output column (the "Module" column). This happens because a callback function has been specified, which provides an opportunity to customize the data that is displayed.
BOOL PropCallback(int nColumn,              // column number being processed
                  void * props,             // pointer to property structure
                  LPTSTR * lppszValueArray, // pointer to array of field values
                  BOOL bHeader)             // TRUE = column header being 
                                            // processed, FALSE = column data
{
    XHTMLLOG_COLUMN_PROPERTIES * pprops =
            (XHTMLLOG_COLUMN_PROPERTIES *) props;

    if (nColumn == 3 && !bHeader)
    {
        _stprintf(pprops->szData, _T("%s(%s)"),
                  lppszValueArray[pprops->nField],
                  lppszValueArray[4]);
    } 
The callback function allows the appearance of the columns (e.g., colors) to be customized. In the demo app, the color of the message column (the bottom row of each displayed log entry) is set according to the value of the priority field:
    if (nColumn == 4)
    {
        COLORREF rgbBackground = RGB(0,0,0);
        int nPriority = _ttoi(lppszValueArray[0]);
        switch (nPriority)
        {
            case 0:    rgbBackground = green;  break;
            case 1:    rgbBackground = blue;   break;
            case 2:    rgbBackground = yellow; break;
            case 3:    rgbBackground = orange; break;
            case 4:    rgbBackground = red;    break;
        }

        pprops->rgbDataBackground = rgbBackground;
        pprops->rgbDataText = RGB(255,255,255);
        if (nPriority == 2 || nPriority == 3)
            pprops->rgbDataText = RGB(0,0,0);
    } 

CXHtmlLog Functions

  • GenerateHtml() - Generate HTML output from log file
    ////////////////////////////////////////////////////////////////////////////
    // GenerateHtml()
    //
    // Purpose:     Read log records from lpszInFile and write HTML output to
    //              lpszOutFile.
    //
    // Parameters:  lpszInFile  - name of input log file
    //              lpszOutFile - name of output HTML file; contents of
    //                            existing file will be destroyed
    //
    // Returns:     BOOL - TRUE = success
    // 
  • CXHtmlLog Callback Function (Implemented by caller)
    ///////////////////////////////////////////////////////////////////////////
    //
    // CXHtmlLog Callback Function
    //
    // Purpose:     Optional function that is called prior to emitting HTML for
    //              the column specified by nColumn.  This function will be 
    //              called twice:  once for the column header (bHeader = TRUE),
    //              and once for the data.
    //
    // Parameters:  nColumn          - column number being processed
    //              props            - pointer to column property struct for
    //                                 nColumn
    //              lppszValueArray  - pointer to array of strings parsed from 
    //                                 fields;
    //                                 lppszValueArray[0] = first field, etc.
    //              bHeader          - TRUE = column header is being processed
    //
    // Returns:     BOOL - return TRUE to continue processing the current record;
    //                     return FALSE to discard the current record.
    //                     Note:  returning FALSE assumes that the entire output
    //                     from the current record will fit in the XFile write 
    //                     buffer. The XFile write buffer size may be increased 
    //                     if necessary.
    // 
  • SetBodyColors() - Set colors for BODY tag.
    //////////////////////////////////////////////////////////////////////////
    //
    // SetBodyColors()
    //
    // Purpose:     Set colors for BODY tag
    //
    // Parameters:  rgbText       - BODY text color
    //              rgbBackground - BODY background color
    //
    // Returns:     None
    // 
  • SetColumnProperties() - Set properties for column nColumn.
    ///////////////////////////////////////////////////////////////////////////
    //
    // SetColumnProperties()
    //
    // Purpose:     Set properties for column nColumn
    //
    // Parameters:  nColumn - column number
    //              props   - pointer to column property struct
    //
    // Returns:     BOOL - TRUE = success
    // 
  • SetInputFieldDelimiter() - Set delimiter string for input fields.
    //////////////////////////////////////////////////////////////////////////
    //
    // SetInputFieldDelimiter()
    //
    // Purpose:     Set delimiter string for input fields.
    //
    // Parameters:  lpszDelimiter  - pointer to string containing delimiter
    //                               characters.  Similar to strtok().  Each
    //                               character in lpszDelimiter is checked for
    //                               in the input field, and if found is 
    //                               accepted as the field delimiter.
    //
    // Returns:     None
    // 
  • SetInputRecordDelimiter() - Set delimiter string for records.
    ///////////////////////////////////////////////////////////////////////////
    //
    // SetInputRecordDelimiter()
    //
    // Purpose:     Set delimiter string for records.
    //
    // Parameters:  lpszDelimiter  - pointer to string containing delimiter.
    //                               The delimiter is used to extract records 
    //                               from the input file.
    //
    // Returns:     None
    // 
  • SetTitle - Set title string for HTML TITLE tag.
    ///////////////////////////////////////////////////////////////////////////
    //
    // SetTitle()
    //
    // Purpose:     Set title string for HTML TITLE tag.
    //
    // Parameters:  lpszTitle  - pointer to title string
    //
    // Returns:     None
    // 
  • SetTopHeader - Set top header string.
    ///////////////////////////////////////////////////////////////////////////
    //
    // SetTopHeader()
    //
    // Purpose:     Set top header string
    //
    // Parameters:  lpszHeader  - pointer to top header string
    //
    // Returns:     None
    // 
  • SetTopHeaderColor - Set text color for top header.
    ///////////////////////////////////////////////////////////////////////////
    //
    // SetTopHeaderColor()
    //
    // Purpose:     Set text color for top header
    //
    // Parameters:  rgbText - top header text color
    //
    // Returns:     None
    // 
  • SetTopHeaderFontFace - Set top header font face.
    ///////////////////////////////////////////////////////////////////////////
    //
    // SetTopHeaderFontFace()
    //
    // Purpose:     Set top header font face
    //
    // Parameters:  lpszFontFace  - pointer to font face name
    //
    // Returns:     None
    // 
  • SetTopHeaderFontSize - Set top header font size.
    ///////////////////////////////////////////////////////////////////////////
    //
    // SetTopHeaderFontSize()
    //
    // Purpose:     Set top header font size
    //
    // Parameters:  nFontSize  - font size for top header;  this is relative 
    //                           size - e.g., +3, -1
    //
    // Returns:     None
    // 

How To Use

To integrate CXHtmlLog class into your app, you first need to add following files to your project:

  • XHtmlLog.cpp
  • XHtmlLog.h
  • XFile.cpp
  • XFile.h
  • XTrace.h

The XTrace.h file is optional, and can be excluded. If you exclude it, comment out #include "XTrace.h" line from XFile.cpp and XHtmlLog.cpp, and uncomment #define TRACE ((void)0) and #define TRACEERROR ((void)0) lines.

If you include CXHtmlLog in project that uses precompiled headers, you must change C/C++ Precompiled Headers settings to Not using precompiled headers for XHtmlLog.cpp and XFile.cpp.

Next, include the header file XHtmlLog.h in appropriate project files. Now you are ready to start using CXHtmlLog. There are many notes concerning usage of various functions in XHtmlLog.cpp. Please read all function header for each function you wish to use.

Then construct CXHtmlLog object and define the columns:

    CXHtmlLog log(10);

    log.SetTitle(_T("Captain's Log"));
    log.SetTopHeader(_T("Captain's Log"));
    log.SetTopHeaderColor(RGB(0,0,255));
    log.SetBodyColors(RGB(0,0,0), RGB(255,250,240));

    XHTMLLOG_COLUMN_PROPERTIES props;

    props.lpPropFunc = PropCallback;
    props.rgbDataBackground = RGB(255,250,240);

    props.nField = 1;
    props.nWidth = 15;
    _tcscpy(props.szHeader, _T("Stardate"));
    log.SetColumnProperties(0, &props);

    props.nField = 0;
    props.nWidth = 15;
    _tcscpy(props.szHeader, _T("Priority"));
    log.SetColumnProperties(1, &props);

    props.nField = 2;
    props.nWidth = 30;
    _tcscpy(props.szHeader, _T("Component"));
    log.SetColumnProperties(2, &props);

    props.nField = 3;
    props.nWidth = 40;
    _tcscpy(props.szHeader, _T("Module"));
    log.SetColumnProperties(3, &props);

    props.nField = 5;
    props.bMessage = TRUE;
    _tcscpy(props.szHeader, _T("message"));
    log.SetColumnProperties(4, &props); 
And finally generate the HTML:
    log.GenerateHtml(_T("log.txt"), _T("log.html"));

Known Limitations

  • By design, CXHtmlLog expects one of the output columns to be designated as the "message" column, which contains the text of the log entry - i.e., the primary information being conveyed by the log entry.
  • The fields of the input file records must be delimited in a deterministic manner - i.e., if fields are delimited by tabs, then a tab character must not appear within a field.
  • The records of the input file must have a fixed delimiter - the same delimiter must be used for all records.

Frequently Asked Questions

  1. Can I use XHtmlLog in non-MFC apps?
    Yes. It has been implemented to compile with any Win32 program.

  2. When I try to include XHtmlLog.cpp in my MFC project, I get the compiler error XHtmlLog.cpp(754) : fatal error C1010: unexpected end of file while looking for precompiled header directive. How can I fix this?
    When using XHtmlLog in project that uses precompiled headers, you must change C/C++ Precompiled Headers settings to Not using precompiled headers for XHtmlLog.cpp and XFile.cpp. Be sure to do this for All Configurations.

    XHtmlLog screenshot

  3. When I try to build the demo app, I get the linker error LINK : fatal error LNK1104: cannot open file "mfc42u.lib" Error executing link.exe. How can I fix this?
    The default installation options of Visual C++ v6.0 don't install the Unicode libraries of MFC, so you might get an error that mfc42u.lib or mfc42ud.lib cannot be found. You can fix this either by installing the Unicode libs from the VC++ install CD, or by going to Build | Set Active Configuration and selecting one of the non-Unicode configurations.

    XHtmlLog screenshot

    You can configure the Visual Studio toolbars to include the Select Active Configuration combobox. This lets you see at a glance what configuration you are working with.

  4. Can we use XHtmlLog in our (shareware/commercial) app?
    Yes, you can use XHtmlLog without charge or license fee. It would be nice to acknowledge my Copyright in your About box or splash screen, but this is up to you.

Acknowledgments

Revision History

Version 1.0 - 2003 May 16

  • Initial public release

Usage

This software is released into the public domain. You are free to use it in any way you like. If you modify it or extend it, please to consider posting new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Hans Dietrich
Software Developer (Senior) Hans Dietrich Software
United States United States
I attended St. Michael's College of the University of Toronto, with the intention of becoming a priest. A friend in the University's Computer Science Department got me interested in programming, and I have been hooked ever since.
 
Recently, I have moved to Los Angeles where I am doing consulting and development work.
 
For consulting and custom software development, please see www.hdsoft.org.






Comments and Discussions

 
GeneralDetail Help Pinmemberhuzaifanawaz24-Sep-03 17:12 
AnswerRe: Detail Help PinmentorHans Dietrich25-Apr-11 3:56 
GeneralCompile Error: Can't find DWORD, BOOL, LPTSTR, ... PinmemberJohan Vanroose11-Jun-03 22:34 
GeneralRe: Compile Error: Can't find DWORD, BOOL, LPTSTR, ... PinmemberHans Dietrich11-Jun-03 22:49 
Generalcompiling errors Pinmembersp305-Jun-03 22:48 
GeneralRe: compiling errors PinmemberHans Dietrich6-Jun-03 5:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140926.1 | Last Updated 30 May 2003
Article Copyright 2003 by Hans Dietrich
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid