Решил тут логгинг переделать.Старый был неудобен и основывался на макросах.
Кое-что получилось . Хочу послушать мнения по поводу пригодности.
#pragma once
#include <Windows.h>
#include <atlstr.h>
#include <iosfwd>
#include <string>
#include <memory>
namespace Logging
{
enum LogLevel
{
LogAll = 0,
LogInfo,
LogWarning,
LogError,
LogNo
};
std::ostream& operator<<( std::ostream& stream, LogLevel level )
{
LPCTSTR lpszPrefix = NULL;
switch( level )
{
case LogAll:
lpszPrefix = _T("Debug: ");
break;
case LogInfo:
lpszPrefix = _T("Info: ");
break;
case LogWarning:
lpszPrefix = _T("Warning: ");
break;
case LogError:
lpszPrefix = _T("Error: ");
break;
default:
return stream;
}
return stream<<lpszPrefix;
}
class ILogger
{
protected:
virtual void WriteEntry_( LogLevel level, LPCTSTR lpszMessage ) = 0;
~ILogger(){}
public:
void WriteEntry(LogLevel level, LPCTSTR lpszMessage )
{
WriteEntry_(level, lpszMessage);
}
};
class LogEntry
{
protected:
typedef ATL::CString String;
ILogger* pLogger_;
std::auto_ptr<String> pBuffer_;
LogLevel Level_;
protected:
LogEntry( LogLevel level, ILogger* pLogger )
: Level_(level), pLogger_(pLogger), pBuffer_( new String() )
{}
LogEntry& operator =( const LogEntry& );
template <typename T>
void AppendRecord( const T& record )
{
pBuffer_->Append(record);
pBuffer_->Append(_T(". "));
}
public:
LogEntry( LogEntry& entry )
{
Level_ = entry.Level_;
pLogger_ = entry.pLogger_;
pBuffer_ = entry.pBuffer_;
}
virtual ~LogEntry()
{
try
{
if( !pBuffer_->IsEmpty() ) pLogger_->WriteEntry( Level_, (*pBuffer_) );
}
catch(...){}
}
static LogEntry Instance( LogLevel level, ILogger* pLogger )
{
return LogEntry( level, pLogger );
}
LogEntry operator <<( int value )
{
String tmp;
tmp.Format("%d", value);
AppendRecord(tmp);
return *this;
}
LogEntry operator <<( HRESULT value )
{
String tmp;
tmp.Format("Error 0x%08x", value);
AppendRecord(tmp);
return *this;
}
template <typename T>
LogEntry operator <<( const T& value )
{
AppendRecord(value);
return *this;
}
};
class ConsoleLogger : public ILogger
{
protected:
void WriteEntry_( LogLevel level, LPCTSTR lpszMessage )
{
// if( level > LogInfo )
{
std::cout<<level<<lpszMessage<<endl;
}
};
public:
static ConsoleLogger& Instance()
{
static ConsoleLogger logger;
return logger;
}
static LogEntry log( LogLevel level )
{
return LogEntry::Instance(level, &ConsoleLogger::Instance());
}
};
template <typename T>
LogEntry operator <<( LogLevel level, const T& value )
{
return LogEntry::Instance(level, &ConsoleLogger::Instance())<<value;
}
int main()
{
LogWarning<<_T("wow")<<10<<E_FAIL<<-10000;//красиво, но не позволяет выбирать тип логгера
ConsoleLogger::log(LogInfo)<<_T("xaxaxaxxaxaxxax..")<<_T("suxx...");//некрасиво, но позволяет...
}
}
Набросал за час, так что пинать не сильно
Из достоинств — неограниченное добавление записей в строку, можно прикрутить манипуляторы.
Идея взята
здесьАвтор: Шахтер
Дата: 16.02.06
03.04.06 20:29: Перенесено из 'C/C++'