Реализация логгера, заслуживающая рассмотрения.
http://www.gamedev.net/community/forums/vi....asp?ID=2834700На всякий случай помещу здесь код:
#include <streambuf>
#include <string>
namespace Bregma
{
/**
* The DebugStreambuf provides a concrete basic_streambuf that appends a
* timestamp and process ID (or thread ID) at the start of each new line.
*
* This streambuf is an unbuffered streambuf. It is not capable of input.
*/
template<typename Char, typename Traits = std::char_traits<Char> >
class DebugStreambuf
: public std::basic_streambuf<Char, Traits>
{
public:
typedef typename std::basic_streambuf<Char, Traits>::traits_type traits_type;
typedef typename std::basic_streambuf<Char, Traits>::int_type int_type;
public:
/**
* Buffer construction.
*/
DebugStreambuf(std::basic_streambuf<Char, Traits> *pRealBuf);
void setLogLevel(const LogLevel &logLevel)
{ m_logLevel = logLevel; }
void setFacility(const std::string &facility)
{ m_facility = facility; }
protected:
/**
* Function called by an ostream when it's time to send something out.
*
* @param c The value to be written out (generally a single character).
*
* @returns A value equal to traits_type::eof() on failure,
* traits_type::not_eof() on success.
*/
int_type
overflow(int_type c = traits_type::eof());
private:
DebugStreambuf(const DebugStreambuf&);
DebugStreambuf& operator=(const DebugStreambuf&);
private:
std::basic_streambuf<Char, Traits> *m_pRealBuf;
bool m_bAtBeginningOfLine;
LogLevel m_logLevel;
std::string m_facility;
};
} // namespace Bregma
#include "debugstreambuf.h"
#include <sstream>
using namespace std;
/**
* Constructs a basic DebugStream.
*/
template<typename C, typename T>
Bregma::DebugStreambuf<C,T>::
DebugStreambuf(basic_streambuf<C,T>* pRealBuf)
: m_pRealBuf(pRealBuf)
, m_bAtBeginningOfLine(true)
, m_logLevel(kLOG_INFO)
{
}
/**
* Actual function to move bytes to the logging stream if appropriate.
*/
template<typename C, typename T>
typename Bregma::DebugStreambuf<C,T>::int_type Bregma::DebugStreambuf<C,T>::
overflow(int_type c)
{
int_type retval = traits_type::not_eof(c);
if (!traits_type::eq_int_type(c, traits_type::eof()))
{
if (m_bAtBeginningOfLine)
{
m_bAtBeginningOfLine = false;
basic_ostringstream<C,T> ostr;
// Format and display the level tag.
char tag = '?';
switch (m_logLevel)
{
case kLOG_FATAL:
tag = 'F';
break;
case kLOG_ERROR:
tag = 'E';
break;
case kLOG_WARNING:
tag = 'W';
break;
case kLOG_INFO:
tag = 'I';
break;
case kLOG_VERBOSE:
tag = 'V';
break;
case kLOG_DEBUG:
tag = 'D';
break;
default:
tag = '?';
}
ostr << '-' << tag << '-';
// Format and display the time stamp.
time_t curTime = std::time(NULL);
char timestamp[32];
std::strftime(timestamp,
sizeof(timestamp),
"%Y.%m.%dT%H:%M:%S",
localtime(&curTime));
ostr << timestamp;
// Format and display the facility.
if (!m_facility.empty())
{
ostr << '[' << m_facility << ']';
}
if (!ostr.str().empty())
{
ostr << ": ";
}
// Send the prefix string out.
const basic_string<C,T>& str = ostr.str();
streamsize sz = m_pRealBuf->sputn(str.c_str(), str.length());
if (sz != str.length())
{
return traits_type::eof();
}
}
// Send the real character out.
retval = m_pRealBuf->sputc(c);
}
// If the end-of-line was seen, reset the beginning-of-line indicator and
// the default log level.
if (traits_type::eq_int_type(c, traits_type::to_int_type('\n')))
{
m_bAtBeginningOfLine = true;
m_logLevel = kLOG_INFO;
}
return retval;
}
namespace Bregma
{
enum LogLevel
{
kLOG_FATAL,
kLOG_ERROR,
kLOG_WARNING,
kLOG_INFO,
kLOG_VERBOSE,
kLOG_DEBUG
};
/**
* Convert an IOStream to a Bregma logging stream.
*
* This can be used to convert, for example, std::cerr into a Bregma logging
* stream.
*
* @param ostr [IN] The IOStream to convert.
* @param level [IN] The default loglevel cutoff (default is INFO).
* @param flags [IN] Flags to toggle various output fields.
*/
void convertToBregmaLogger(std::ostream &ostr);
/**
* Setter for the log level cutoff.
*
* @param ostr [IN] The IOStream for which the log cutoff is to be set.
* @param level [IN] The new log level cutoff.
*/
void setLogCutoff(std::ostream &ostr, const LogLevel &level);
/**
* Manipulator helper for setting the current log level on a debug stream.
*/
class LogLevelSetting
{
public:
LogLevel level() const { return m_level; }
private:
explicit LogLevelSetting(LogLevel level): m_level(level) {}
friend const LogLevelSetting logLevel(LogLevel);
private:
LogLevel m_level;
};
/**
* Ostream manipulator for setting the current log level.
*/
inline const LogLevelSetting logLevel(LogLevel level)
{
return LogLevelSetting(level);
}
/**
* Ostream inserter for the log level manipulator.
*
* @param ostr [IN] The output stream.
* @param ls [IN] The log level setting.
*/
std::ostream& operator<<(std::ostream& ostr, const LogLevelSetting ls);
/**
* A manipulator helper for seeting the facility.
*/
class LogFacilitySetter
{
public:
const std::string &facility() const { return m_facility; }
private:
LogFacilitySetter(const std::string &facility): m_facility(facility) {}
friend const LogFacilitySetter logFacility(const std::string &facility);
private:
const std::string& m_facility;
};
/**
* An ostream manipulator for setting the current facility in the log stream.
*/
inline const LogFacilitySetter logFacility(const std::string &facility)
{
return LogFacilitySetter(facility);
}
/**
* Ostream inserter for the facility manipulator.
*
* @param ostr [IN] The output stream.
* @param ls [IN] The log facility setter manipulator helper..
*/
std::ostream& operator<<(std::ostream& ostr, const LogFacilitySetter ls);
/**
* A handy stream to mark the entry and exit of a scope.
*
* @param ostr [IN] The output stream.
* @param ls [IN] A string.
*/
class ScopeMarker
{
public:
ScopeMarker(std::ostream &ostr, const std::string &what)
: m_ostr(ostr)
, m_what(what)
{
m_ostr << m_what << " begins\n";
}
~ScopeMarker()
{
m_ostr << m_what << " ends\n";
}
private:
std::ostream &m_ostr;
std::string m_what;
};
} // namespace Bregma
void Bregma::convertToBregmaLogger(ostream &ostr)
{
ostr.rdbuf(new DebugStreambuf<char>(ostr.rdbuf()));
}
ostream &Bregma::operator<<(ostream& ostr, const Bregma::LogLevelSetting ls)
{
typedef DebugStreambuf<char> Dstr;
Dstr *pDstr = dynamic_cast<Dstr*>(ostr.rdbuf());
if (pDstr)
{
pDstr->setLogLevel(ls.level());
}
return ostr;
}
ostream &Bregma::operator<<(ostream& ostr, const Bregma::LogFacilitySetter ls)
{
typedef DebugStreambuf<char> Dstr;
Dstr *pDstr = dynamic_cast<Dstr*>(ostr.rdbuf());
if (pDstr)
{
pDstr->setFacility(ls.facility());
}
return ostr;
}
Пример использования#include "bregmalogger.h"
#include <iostream>
using namespace std;
using namespace Bregma;
int main(int, char*[])
{
convertToBregmaLogger(cerr);
cerr << logFacility("TEST") << logLevel(kLOG_WARNING) << "This is a demo.\n";
}