/* log.h Mark Woolrich, FMRIB Image Analysis Group Copyright (C) 1999-2000 University of Oxford */ /* CCOPYRIGHT */ #if !defined(log_h) #define log_h #include <iostream> #include <fstream> #include <string> #include <strstream> #include "newmatap.h" #include "newmatio.h" // for the Exception class: using namespace NEWMAT; namespace Utilities{ template<class t> string tostring(const t obj) { char strc[100]; ostrstream str(strc,100); str << obj << '\0'; return string(strc); } class Logger; template<class t> Logger& operator<<(Logger& log, const t& obj) { if(log.stream_to_logfile) log.logfileout << obj; if(log.stream_to_cout) cout << obj; return log; } class Logger { public: Logger():logEstablished(false) {} Logger(const string& pdirname, const string& plogfilename = "logfile", bool pstream_to_logfile = true, bool pstream_to_cout = false, bool makedir = true):logEstablished(false) { if(makedir) makeDir(pdirname, plogfilename, pstream_to_logfile, pstream_to_cout); else setDir(pdirname, plogfilename, pstream_to_logfile, pstream_to_cout); } ~Logger() { logfileout.close(); } /** Need to call makeDir or setDir before Logger can be used */ /** Makes a directory to place results into: keeps adding "+" to pdirname until unique directory is made. */ /** The stream_to* variables define the streaming behaviour */ void makeDir(const string& pdirname, const string& plogfilename = "logfile", bool pstream_to_logfile = true, bool pstream_to_cout = false); /** Sets an existing directory to place results into. */ /** The stream_to* variables define the streaming behaviour */ void setDir(const string& pdirname, const string& plogfilename = "logfile", bool pstream_to_logfile = true, bool pstream_to_cout = false); /** Closes old logfile buffer and attempts to open new one with name specified and sets streaming to logfile on */ void setLogFile(const string& plogfilename); const string& getDir() const { if(!logEstablished)throw Exception("Log not setup");return dir; } const string& getLogFileName() const { if(!logEstablished)throw Exception("Log not setup");return logfilename; } /** returns passed in filename appended onto the end of the dir name */ const string appendDir(const string& filename) const; /** allows streaming into cout and/or logfile depending upon the */ /** stream_to_cout and stream_to_logfile respectively */ /** use like a normal ostream, e.g. log.str() << "hello" << endl */ /** NOTE: can simply stream straight to Log instead, e.g. log << "hello" << endl */ Logger& str(); /** sets whether or not you stream to cout */ void set_stream_to_cout(bool in = true) { stream_to_cout = in; } /** sets whether or not you stream to logfile */ void set_stream_to_logfile(bool in = true) { if(!stream_to_logfile && in) { if(logfileout.bad()) { cerr << "Warning: Unable to stream to logfile " << logfilename << ". Need to have called log.setLogFile. Therefore, no streaming to logfile will be performed" << endl; } } else stream_to_logfile = in; } private: const Logger& operator=(Logger&); Logger(Logger&); string dir; ofstream logfileout; string logfilename; bool logEstablished; bool stream_to_logfile; bool stream_to_cout; template<class t> friend Logger& operator<<(Logger& log, const t& obj); }; class LogSingleton { public: static Logger& getInstance(); ~LogSingleton() { delete logger; } /** hacked in utility provides a global counter for general use: */ static int counter() { return count++; } private: LogSingleton() {} const LogSingleton& operator=(LogSingleton&); LogSingleton(LogSingleton&); static Logger* logger; static int count; }; typedef LogSingleton Log; inline Logger& LogSingleton::getInstance(){ if(logger == NULL) logger = new Logger(); return *logger; } inline void Logger::setLogFile(const string& plogfilename) { if(!logEstablished) { throw Exception("Log not setup"); } logfileout.close(); logfilename = plogfilename; // setup logfile logfileout.open((dir + "/" + logfilename).c_str(), ios::out); if(logfileout.bad()) { throw Exception(string(string("Unable to setup logfile ")+logfilename+string(" in directory ")+dir).c_str()); } stream_to_logfile = true; logEstablished = true; } inline Logger& Logger::str() { if(!logEstablished) { throw Exception("Log not setup"); } return *this; } inline const string Logger::appendDir(const string& filename) const { if(!logEstablished) { throw Exception("Log not setup"); } return dir + "/" + filename; } } #endif