Skip to content
Snippets Groups Projects
log.h 4.99 KiB
Newer Older
Mark Woolrich's avatar
Mark Woolrich committed
/*  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