S
Stephen Torri
I am trying to produce a singleton class that I can use throughout my
library to write tracing information to a file. My intent was to design
such that someone using the library in its debug mode would be able to
see what was happening without having to use a debugger to step through
each instruction. What they would do is run their program and view the
tracing file output. If there was something wrong then they would use the
debugger of their choosing.
What I am running into is a segfault when I run a test program that uses
on part of the library rather than through the main api interface. The
segfault is coming from the std::num_put as a part of the STL. Since that
is so well tested I am assuming my problem lies in my design of the
singleton class. I modeled it after the GoF singleton pattern.
I would appreciate any helps on the design:
#include <boost/format.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <sstream>
#include <fstream>
#ifndef WIN32
#include <unistd.h>
#else
#include <windows.h>
#endif /* WIN32 */
namespace libreverse { namespace api {
class TraceLevel {
public:
static boost::uint32_t TraceNone; // No trace
static boost::uint32_t TraceWarn; // Only trace warning
static boost::uint32_t TraceError; // Only trace error
static boost::uint32_t TraceInfo; // Some extra information
static boost::uint32_t TraceDebug; // Debugging information
static boost::uint32_t TraceDetail; // Detailed debugging
information
static boost::uint32_t TraceData; // Output data
};
boost::uint32_t TraceLevel::TraceNone = 0;
boost::uint32_t TraceLevel::TraceWarn = 10;
boost::uint32_t TraceLevel::TraceError = 20;
boost::uint32_t TraceLevel::TraceInfo = 30;
boost::uint32_t TraceLevel::TraceDebug = 40;
boost::uint32_t TraceLevel::TraceDetail = 50;
boost::uint32_t TraceLevel::TraceData = 60;
} /* namespace api */
} /* namespace libreverse */
namespace libreverse { namespace trace {
class Trace_State {
public:
typedef boost::shared_ptr<Trace_State> ptr_t;
static Trace_State& Instance()
{
if ( m_instance == 0 )
{
m_instance = new Trace_State();
}
return *m_instance;
}
void set_Trace_File_Prefix ( std::string name )
{
assert ( ! name.empty() );
// Lock the resource
// Close the present file
m_file_prefix = name;
// Unlock the resource
}
void set_Trace_Level ( boost::uint32_t level )
{
// Lock the resource
// Change level
m_trace_level = level;
// Unlock the resource
}
void open_Trace_File ( void )
{
if ( ! m_log_stream.is_open() )
{
// Create file name
std::stringstream name;
name << boost::format("%s_%s.txt")
% m_file_prefix
% this->get_ID_String();
m_log_stream.open ( (name.str()).c_str() );
}
}
std::string get_ID_String ( void )
{
// Create id string
std::stringstream name;
// Get current time
boost:osix_time:time now =
boost:osix_time::second_clock::local_time();
std::tm tm_ref = boost:osix_time::to_tm ( now );
boost::gregorian::date today = now.date();
name << boost::format ( "%s_%02d:%02d:%02d" )
% boost::gregorian::to_iso_extended_string ( today )
% tm_ref.tm_hour
% tm_ref.tm_min
% tm_ref.tm_sec;
return name.str();
}
void close_Trace_File ( void )
{
if ( m_log_stream.is_open() )
{
m_log_stream.close();
}
}
boost::uint32_t get_Trace_Level ( void ) const
{
boost::uint32_t level = 0;
// Lock the resource
// get the level
level = m_trace_level;
// unlock the resource
// return the level
return level;
}
void write_Message ( boost::uint32_t level, std::string msg )
{
// Write ID
m_log_stream << boost::format("%s_%d: " )
% this->get_ID_String()
#ifndef WIN32
% getpid()
#else
% GetCurrentProcessId()
#endif /* WIN32 */
<< std::flush;
// Write message prefix
if ( level == libreverse::api::TraceLevel::TraceWarn )
{
m_log_stream << "(WW) ";
}
else if ( level == libreverse::api::TraceLevel::TraceError )
{
m_log_stream << "(EE) ";
}
else if ( level == libreverse::api::TraceLevel::TraceInfo )
{
m_log_stream << "(II) ";
}
else if ( level == libreverse::api::TraceLevel::TraceDebug )
{
m_log_stream << "(DEBUG) ";
}
else if ( level == libreverse::api::TraceLevel::TraceDetail )
{
m_log_stream << "(DETAIL) ";
}
else if ( level == libreverse::api::TraceLevel::TraceData )
{
m_log_stream << "(DATA) ";
}
else
{
// We should not be here
abort();
}
// Write to the file
m_log_stream << msg << std::endl << std::flush;
// Unlock the resource
}
private:
Trace_State()
: m_file_prefix ( "Trace" ),
m_trace_level ( libreverse::api::TraceLevel::TraceNone )
{}
~Trace_State()
{
delete m_instance;
this->close_Trace_File();
}
static Trace_State* m_instance;
std::string m_file_prefix;
boost::uint32_t m_trace_level;
std:fstream m_log_stream;
};
class Trace {
public:
#ifdef LIBREVERSE_DEBUG
bool write_Trace ( boost::uint32_t level,
std::string message )
{
// If the level is equal to or greater than the present
// level we record out message.
if ( ( Trace_State::Instance().get_Trace_Level() != 0 ) &&
( level <= Trace_State::Instance().get_Trace_Level() ) )
{
Trace_State::Instance().write_Message ( level,
message );
}
return true;
}
#else
bool write_Trace ( boost::uint32_t,
std::string )
{
return true;
}
#endif
};
Trace_State* Trace_State::m_instance = 0;
} /* namespace trace */
} /* namespace libreverse */
using namespace libreverse::trace;
using namespace libreverse::api;
int main ( int, char** )
{
Trace_State::Instance().set_Trace_Level ( TraceLevel::TraceDetail );
Trace_State::Instance().open_Trace_File ();
Trace_State::Instance().close_Trace_File ();
return 0;
}
library to write tracing information to a file. My intent was to design
such that someone using the library in its debug mode would be able to
see what was happening without having to use a debugger to step through
each instruction. What they would do is run their program and view the
tracing file output. If there was something wrong then they would use the
debugger of their choosing.
What I am running into is a segfault when I run a test program that uses
on part of the library rather than through the main api interface. The
segfault is coming from the std::num_put as a part of the STL. Since that
is so well tested I am assuming my problem lies in my design of the
singleton class. I modeled it after the GoF singleton pattern.
I would appreciate any helps on the design:
#include <boost/format.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <sstream>
#include <fstream>
#ifndef WIN32
#include <unistd.h>
#else
#include <windows.h>
#endif /* WIN32 */
namespace libreverse { namespace api {
class TraceLevel {
public:
static boost::uint32_t TraceNone; // No trace
static boost::uint32_t TraceWarn; // Only trace warning
static boost::uint32_t TraceError; // Only trace error
static boost::uint32_t TraceInfo; // Some extra information
static boost::uint32_t TraceDebug; // Debugging information
static boost::uint32_t TraceDetail; // Detailed debugging
information
static boost::uint32_t TraceData; // Output data
};
boost::uint32_t TraceLevel::TraceNone = 0;
boost::uint32_t TraceLevel::TraceWarn = 10;
boost::uint32_t TraceLevel::TraceError = 20;
boost::uint32_t TraceLevel::TraceInfo = 30;
boost::uint32_t TraceLevel::TraceDebug = 40;
boost::uint32_t TraceLevel::TraceDetail = 50;
boost::uint32_t TraceLevel::TraceData = 60;
} /* namespace api */
} /* namespace libreverse */
namespace libreverse { namespace trace {
class Trace_State {
public:
typedef boost::shared_ptr<Trace_State> ptr_t;
static Trace_State& Instance()
{
if ( m_instance == 0 )
{
m_instance = new Trace_State();
}
return *m_instance;
}
void set_Trace_File_Prefix ( std::string name )
{
assert ( ! name.empty() );
// Lock the resource
// Close the present file
m_file_prefix = name;
// Unlock the resource
}
void set_Trace_Level ( boost::uint32_t level )
{
// Lock the resource
// Change level
m_trace_level = level;
// Unlock the resource
}
void open_Trace_File ( void )
{
if ( ! m_log_stream.is_open() )
{
// Create file name
std::stringstream name;
name << boost::format("%s_%s.txt")
% m_file_prefix
% this->get_ID_String();
m_log_stream.open ( (name.str()).c_str() );
}
}
std::string get_ID_String ( void )
{
// Create id string
std::stringstream name;
// Get current time
boost:osix_time:time now =
boost:osix_time::second_clock::local_time();
std::tm tm_ref = boost:osix_time::to_tm ( now );
boost::gregorian::date today = now.date();
name << boost::format ( "%s_%02d:%02d:%02d" )
% boost::gregorian::to_iso_extended_string ( today )
% tm_ref.tm_hour
% tm_ref.tm_min
% tm_ref.tm_sec;
return name.str();
}
void close_Trace_File ( void )
{
if ( m_log_stream.is_open() )
{
m_log_stream.close();
}
}
boost::uint32_t get_Trace_Level ( void ) const
{
boost::uint32_t level = 0;
// Lock the resource
// get the level
level = m_trace_level;
// unlock the resource
// return the level
return level;
}
void write_Message ( boost::uint32_t level, std::string msg )
{
// Write ID
m_log_stream << boost::format("%s_%d: " )
% this->get_ID_String()
#ifndef WIN32
% getpid()
#else
% GetCurrentProcessId()
#endif /* WIN32 */
<< std::flush;
// Write message prefix
if ( level == libreverse::api::TraceLevel::TraceWarn )
{
m_log_stream << "(WW) ";
}
else if ( level == libreverse::api::TraceLevel::TraceError )
{
m_log_stream << "(EE) ";
}
else if ( level == libreverse::api::TraceLevel::TraceInfo )
{
m_log_stream << "(II) ";
}
else if ( level == libreverse::api::TraceLevel::TraceDebug )
{
m_log_stream << "(DEBUG) ";
}
else if ( level == libreverse::api::TraceLevel::TraceDetail )
{
m_log_stream << "(DETAIL) ";
}
else if ( level == libreverse::api::TraceLevel::TraceData )
{
m_log_stream << "(DATA) ";
}
else
{
// We should not be here
abort();
}
// Write to the file
m_log_stream << msg << std::endl << std::flush;
// Unlock the resource
}
private:
Trace_State()
: m_file_prefix ( "Trace" ),
m_trace_level ( libreverse::api::TraceLevel::TraceNone )
{}
~Trace_State()
{
delete m_instance;
this->close_Trace_File();
}
static Trace_State* m_instance;
std::string m_file_prefix;
boost::uint32_t m_trace_level;
std:fstream m_log_stream;
};
class Trace {
public:
#ifdef LIBREVERSE_DEBUG
bool write_Trace ( boost::uint32_t level,
std::string message )
{
// If the level is equal to or greater than the present
// level we record out message.
if ( ( Trace_State::Instance().get_Trace_Level() != 0 ) &&
( level <= Trace_State::Instance().get_Trace_Level() ) )
{
Trace_State::Instance().write_Message ( level,
message );
}
return true;
}
#else
bool write_Trace ( boost::uint32_t,
std::string )
{
return true;
}
#endif
};
Trace_State* Trace_State::m_instance = 0;
} /* namespace trace */
} /* namespace libreverse */
using namespace libreverse::trace;
using namespace libreverse::api;
int main ( int, char** )
{
Trace_State::Instance().set_Trace_Level ( TraceLevel::TraceDetail );
Trace_State::Instance().open_Trace_File ();
Trace_State::Instance().close_Trace_File ();
return 0;
}