|
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.
|