  | 
   Log File Class 
   Submitted by  |   
  
  
Here's a COTD contribution... it's a class that handles log files with
indentation, code flow, and other stuff. It's also my first use of the
STL, so I hope I don't get hammered too badly... :)
  
 | 
 
 
 
Currently browsing [cotd-logger.zip] (6,313 bytes) - [logger.h] - (6,507 bytes)
 
 // --------------------------------------------------------------------------------------------------------------------------------
// Copyright 2000, Paul Nettle. All rights reserved.
//
// Logger.h - Log file class
//
// [NOTE] This file is best viewed in 132 column mode with 8-character tabs
//
// THIS FILE HAS BEEN ENTERED INTO THE PUBLIC DOMAIN BY THE AUTHOR
// --------------------------------------------------------------------------------------------------------------------------------
#ifndef	_H_LOGGER
#define	_H_LOGGER
  // --------------------------------------------------------------------------------------------------------------------------------
// Required includes
// --------------------------------------------------------------------------------------------------------------------------------
#include <string>
#include <iostream>
#include <fstream>
#include <stdarg.h>
using namespace std;
  // --------------------------------------------------------------------------------------------------------------------------------
// The global logger
// --------------------------------------------------------------------------------------------------------------------------------
class	Logger;
extern	Logger	logger;
  // --------------------------------------------------------------------------------------------------------------------------------
// Macros (necessary evil to take advantage of __LINE__ and __FILE__)
// --------------------------------------------------------------------------------------------------------------------------------
#define	LOG		logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.logTex
#define	HEX		logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.logHex
#define	RAW		logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.logRaw
#define	INDENT		logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.indent
#define	UNDENT		logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.undent
#define	LOGBLOCK	logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__;LogBlock __lb__
  // If you compiler supports __FUNCTION__, then replace the "#if 1" with "#if 0". Note that this will change the usage of the macro
#if 1
#define	LOGFUNC		logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__;LogFlow __lf__
#else
#define	LOGFUNC		logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__;LogFlow __lf__(__FUNCTION__)
#endif
  // --------------------------------------------------------------------------------------------------------------------------------
// The logger class: does the actual logging
// --------------------------------------------------------------------------------------------------------------------------------
class	Logger
{
public:
	// Enumerations
	enum	LogFlags
	{
				LOG_INDENT = 0x00000001,
				LOG_UNDENT = 0x00000002,
				LOG_FLOW   = 0x00000004,
				LOG_BLOK   = 0x00000008,
				LOG_DATA   = 0x00000010,
				LOG_INFO   = 0x00000012,
				LOG_WARN   = 0x00000014,
				LOG_ERR    = 0x00000018,
				LOG_CRIT   = 0x00000020,
				LOG_ALL    = 0xFFFFFFFF
	};
  	// Construction/Destruction
inline				Logger(const string &filename)
				: _logFile(filename), _sourceLine(0), _indentCount(0), _indentChars(4), _logMask(LOG_ALL),
				  _logStarted(false), _lineCharsFlag(false)
				{
					start();
				}
  inline				~Logger()
				{
					stop();
				}
  	// Operators
inline		void		operator +=(const string &s)	{logTex(s);}
  	// Accessors
inline	const	bool		&lineCharsFlag() const	{return _lineCharsFlag;}
inline		bool		&lineCharsFlag() 	{return _lineCharsFlag;}
  inline	const	unsigned int	&logMask() const	{return _logMask;}
inline		unsigned int	&logMask()		{return _logMask;}
  inline	const	string		&logFile() const	{return _logFile;}
inline		string		&logFile()		{return _logFile;}
  inline	const	unsigned int	&sourceLine() const	{return _sourceLine;}
inline		unsigned int	&sourceLine()		{return _sourceLine;}
  inline	const	string		&sourceFile() const	{return _sourceFile;}
inline		string		&sourceFile()		{return _sourceFile;}
  inline		bool		logStarted() const	{return _logStarted;}
  	// Utilitarian (public)
virtual		void		start();
virtual		void		stop();
virtual		void		logTex(const string &s, const LogFlags logBits = LOG_INFO);
virtual		void		logRaw(const string &s);
virtual		void		logHex(const char *buffer, const unsigned int count, const LogFlags logBits = LOG_INFO);
virtual		void		indent(const string &s, const LogFlags logBits = LOG_INDENT);
virtual		void		undent(const string &s, const LogFlags logBits = LOG_UNDENT);
  private:
	// Utilitarian (private)
virtual	const	string		&headerString(const LogFlags logBits) const;
  	// Data
		string		_logFile;
		string		_sourceFile;
		unsigned int	_sourceLine;
		int		_indentCount;
		int		_indentChars;
		unsigned int	_logMask;
		bool		_logStarted;
		bool		_lineCharsFlag;
};
  // ---------------------------------------------------------------------------------------------------------------------------------
// The LogBlock class: used for automatic indentation
// ---------------------------------------------------------------------------------------------------------------------------------
class	LogBlock
{
public:
inline				LogBlock(const string &s)	{str = s;logger.indent("Begin block: " + str, Logger::LOG_INDENT);}
inline				~LogBlock()			{logger.undent("End block: " + str, Logger::LOG_UNDENT);}
private:
		string		str;
};
  // ---------------------------------------------------------------------------------------------------------------------------------
// The LogFlow class: used for logging code flow
// ---------------------------------------------------------------------------------------------------------------------------------
class	LogFlow
{
public:
inline				LogFlow(const char *function)	{str = function;logger.indent("Enter function: " + str, Logger::LOG_FLOW);}
inline				~LogFlow()			{logger.undent("Exit function: " + str, Logger::LOG_FLOW);}
private:
		string		str;
};
  #endif // _H_LOGGER
// ---------------------------------------------------------------------------------------------------------------------------------
// Logger.h - End of file
// ---------------------------------------------------------------------------------------------------------------------------------
   |  
  
 | 
 
  
Currently browsing [cotd-logger.zip] (6,313 bytes) - [logger.cpp] - (7,497 bytes)
 
 // --------------------------------------------------------------------------------------------------------------------------------
// Copyright 2000, Paul Nettle. All rights reserved.
//
// Logger.cpp - Log file class
//
// [NOTE] This file is best viewed in 132 column mode with 8-character tabs
//
// THIS FILE HAS BEEN ENTERED INTO THE PUBLIC DOMAIN BY THE AUTHOR
// --------------------------------------------------------------------------------------------------------------------------------
#include <time.h>
#include <stdarg.h>
  #include "Logger.h"
  // --------------------------------------------------------------------------------------------------------------------------------
// The global logger
// --------------------------------------------------------------------------------------------------------------------------------
Logger	logger("app.log");
  // --------------------------------------------------------------------------------------------------------------------------------
void	Logger::start()
{
	if (logStarted()) return;
	_logStarted = true;
  	// Get the time
	time_t	t = time(NULL);
	string	ts = asctime(localtime(&t));
	ts[ts.length() - 1] = 0;
  	ofstream of(logFile().c_str(), ios::out|ios::app);
	if (of.is_open())
	{
		of << "---------------------------------------------- Log begins on " << ts << " ----------------------------------------------" << endl;
	}
}
  // --------------------------------------------------------------------------------------------------------------------------------
void	Logger::stop()
{
	// Automatic One time only startup
	if (!logStarted()) return;
  	// Get the time
	time_t	t = time(NULL);
	string	ts = asctime(localtime(&t));
	ts[ts.length() - 1] = 0;
  	// Start the log
	ofstream of(logFile().c_str(), ios::out|ios::app);
	if (of.is_open())
	{
		of << "----------------------------------------------- Log ends on " << ts << " -----------------------------------------------" << endl << endl << endl << endl << endl;
	}
  	_logStarted = false;
}
  // --------------------------------------------------------------------------------------------------------------------------------
void	Logger::logTex(const string &s, const LogFlags logBits)
{
	// If the bits don't match the mask, then bail
	if (!(logBits & logMask())) return;
  	// Open the file
	ofstream of(logFile().c_str(), ios::out|ios::app);
	if (!of.is_open()) return;
  	// Output to the log file
	of << headerString(logBits) << s << endl;
}
  // --------------------------------------------------------------------------------------------------------------------------------
void	Logger::logRaw(const string &s)
{
	// Open the file
	ofstream of(logFile().c_str(), ios::out|ios::app);
	if (!of.is_open()) return;
  	// Log the output
	of << s;
}
  // --------------------------------------------------------------------------------------------------------------------------------
void	Logger::logHex(const char *buffer, const unsigned int count, const LogFlags logBits)
{
	// No input? No output
	if (!buffer) return;
  	// If the bits don't match the mask, then bail
	if (!(logBits & logMask())) return;
  	// Open the file
	ofstream of(logFile().c_str(), ios::out|ios::app);
	if (!of.is_open()) return;
  	// Log the output
	unsigned int	logged = 0;
	while(logged < count)
	{
		// One line at a time...
		string		line;
  		// The number of characters per line
		unsigned int	hexLength = 20;
  		// Default the buffer
		for (unsigned int i = 0; i < hexLength; i++)
		{
			line += "-- ";
		}
  		for (i = 0; i < hexLength; i++)
		{
			line += ".";
		}
  		// Fill it in with real data
		for (i = 0; i < hexLength && logged < count; i++, logged++)
		{
			unsigned char	byte = buffer[logged];
			unsigned int	index = i * 3;
  			// The hex characters
			const char	*hexlist="0123456789ABCDEF";
			line[index+0] = hexlist[byte >> 4];
			line[index+1] = hexlist[byte & 0xf];
  			// The ascii characters
			if (byte < 0x20 || byte > 0x7f) byte = '.';
			line[(hexLength*3)+i+0] = byte;
		}
  		// Write it to the log file
		of << headerString(logBits) << line << endl;
	}
}
  // --------------------------------------------------------------------------------------------------------------------------------
void	Logger::indent(const string &s, const LogFlags logBits)
{
	// If the bits don't match the mask, then bail
	if (!(logBits & logMask())) return;
  	// Open the file
	ofstream of(logFile().c_str(), ios::out|ios::app);
	if (!of.is_open()) return;
  	// Log the output
	if (lineCharsFlag())	of << headerString(logBits) << " \xDA " << s << endl;
	else			of << headerString(logBits) << " +- " << s << endl;
  	// Indent...
	_indentCount += _indentChars;
}
  // --------------------------------------------------------------------------------------------------------------------------------
void	Logger::undent(const string &s, const LogFlags logBits)
{
	// If the bits don't match the mask, then bail
	if (!(logBits & logMask())) return;
  	// Undo the indentation
	_indentCount -= _indentChars;
	if (_indentCount < 0) _indentCount = 0;
  	// Open the file
	ofstream of(logFile().c_str(), ios::out|ios::app);
	if (!of.is_open()) return;
  	// Log the output
	if (lineCharsFlag())	of << headerString(logBits) << " \xC0 " << s << endl;
	else			of << headerString(logBits) << " +- " << s << endl;
}
  // --------------------------------------------------------------------------------------------------------------------------------
const	string	&Logger::headerString(const LogFlags logBits) const
{
	static	string	headerString;
	headerString.erase();
  	// Get the string that represents the bits
	switch(logBits)
	{
		case LOG_INDENT : headerString += "> "; break;
		case LOG_UNDENT : headerString += "< "; break;
		case LOG_ALL    : headerString += "A "; break;
		case LOG_CRIT   : headerString += "! "; break;
		case LOG_DATA   : headerString += "D "; break;
		case LOG_ERR    : headerString += "E "; break;
		case LOG_FLOW   : headerString += "F "; break;
		case LOG_INFO   : headerString += "I "; break;
		case LOG_WARN   : headerString += "W "; break;
		default:          headerString += "  "; break;
	}
  	// File string (strip out the path)
	char	temp[1024];
	int	ix = sourceFile().rfind('\\');
	ix = ix == string::npos ? 0: ix+1;
	sprintf(temp, "%12s[%04d]", sourceFile().substr(ix).c_str(), sourceLine());
	headerString += temp;
  	// Time string (specially formatted to save room)
	time_t	t = time(NULL);
	struct	tm *tme = localtime(&t);
	sprintf(temp, "%02d/%02d %02d:%02d ", tme->tm_mon + 1, tme->tm_mday, tme->tm_hour, tme->tm_min);
	headerString += temp;
  	// Spaces for indentation
	memset(temp, ' ', sizeof(temp));
	temp[_indentCount] = '\0';
  	// Add the indentation markers
	int	count = 1;
	while(count < _indentCount)
	{
		if (lineCharsFlag())	temp[count] = '\xB3';
		else			temp[count] = '|';
		count += _indentChars;
	}
	headerString += temp;
  	return headerString;
}
  // --------------------------------------------------------------------------------------------------------------------------------
// Logger - End of file
// --------------------------------------------------------------------------------------------------------------------------------
   |  
  
 | 
 
  
Currently browsing [cotd-logger.zip] (6,313 bytes) - [example.cpp] - (3,239 bytes)
 
 // --------------------------------------------------------------------------------------------------------------------------------
// example.cpp - example for using the Logger class
// --------------------------------------------------------------------------------------------------------------------------------
#include "logger.h"
  // --------------------------------------------------------------------------------------------------------------------------------
void	generateRandomNumbers()
{
	LOGFUNC("generateRandomNumbers()");
  	// Just fill in a buffer of 256 characters with random data
	char	buffer[256];
	for (unsigned int i = 0; i < 256; i++)
	{
		buffer[i] = rand() % 256;
	}
  	// Log the output
	HEX(buffer, sizeof(buffer));
}
  // --------------------------------------------------------------------------------------------------------------------------------
void	logTypes()
{
	LOGFUNC("logTypes()");
  	// Log a few different types...
	LOG("This is an [I]nfo line (notice the 'I' on the far left of the log");
	string	data("data data data");
	LOG("Here is some [D]ata: " + data, Logger::LOG_DATA);
	LOG("A log with the [W]arning flag set", Logger::LOG_WARN);
	LOG("Here we have an [E]rror entry in the log", Logger::LOG_ERR);
	LOG("And finally a [!] critical error", Logger::LOG_CRIT);
}
  // --------------------------------------------------------------------------------------------------------------------------------
void	recursion()
{
	LOGFUNC("recursion()");
  	static	int	recursionLevel;
  	if (recursionLevel == 3)
	{
		LOG("We're inside a recusive routine that has gone three levels deep");
	}
  	if (recursionLevel < 3)
	{
		recursionLevel++;
		recursion();
	}
}
  // --------------------------------------------------------------------------------------------------------------------------------
void	generateRawData()
{
	LOGFUNC("generateRawData()");
  	RAW("\nThis is a test\n  This is only a test\n    This is nothing more than a test of the RAW (unformatted) logging output.\n\n");
}
  // --------------------------------------------------------------------------------------------------------------------------------
int	main()
{
	LOGFUNC("main()");
  	// Log some various types of entries to the log
	logTypes();
  	// Log some recursive routines
	recursion();
  	// Do some indentation. We'll use braces to limit scope of temporary objects that handle the indention for us. When the
	// braces terminate, so will the scope of the temporary objects, which automatically "pops" the indention stack
	LOG("Here we have some indentation without having to call multiple routines");
  	{
		LOGBLOCK("Indention level 1");
		{
			LOGBLOCK("Indention level 2");
			LOG("Hello, from the depths of multiple indentation levels");
		}
	}
  	// Let's log some RAW data...
	generateRawData();
  	// Some random numbers, displayed in hex
	generateRandomNumbers();
  	// Spit out another line, just for fun
	logger += "Are we having fun yet? :)";
  	// Done
	return 0;
}
  // --------------------------------------------------------------------------------------------------------------------------------
   |  
  
 | 
 
 
 
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
 
 
 |