This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  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.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.