MessageHandler.cc

00001 //Copyright 2013 Ben Loer
00002 //This file is part of the ConfigHandler library
00003 //It is released under the terms of the GNU General Public License v3
00004 
00005 #include "MessageHandler.hh"
00006 #include "Message.hh"
00007 #include <time.h>
00008 #include <cctype>
00009 #include <algorithm>
00010 #include <exception>
00011 #include <stdexcept>
00012 #ifndef SINGLETHREAD
00013 #include "boost/ref.hpp"
00014 #include "boost/thread/thread.hpp"
00015 #include "boost/thread/mutex.hpp"
00016 #include "boost/thread/condition.hpp"
00017 #endif
00018 
00019 #include "ConfigHandler.hh"
00020 #include "CommandSwitchFunctions.hh"
00021 
00022 namespace MessageLevelConversion{
00023   std::string EnumToString(MESSAGE_LEVEL level)
00024   {
00025     switch(level){
00026     case DEBUG3: return "DEBUG3";
00027     case DEBUG2: return "DEBUG2";
00028     case DEBUG:  return "DEBUG";
00029     case INFO:   return "INFO";
00030     case WARNING: return "WARNING";
00031     case ERROR:   return "ERROR";
00032     case CRITICAL: return "CRITICAL";
00033     case EXCEPTION: return "EXCEPTION";
00034     default:
00035       std::cerr<<"Unknown MESSAGE_LEVEL passed: "<<(int)(level)<<"!\n";
00036     }
00037     //only get here in case of error
00038     return "";
00039   }
00040   
00041   void convert_to_upper(char& c){ c = std::toupper(c); }
00042   
00043   MESSAGE_LEVEL StringToEnum(std::string s)
00044   {
00045     //convert the whole string to upper case
00046     std::for_each(s.begin(),s.end(),convert_to_upper);
00047     //let DEBUG1 = DEBUG
00048     if(s == "DEBUG1") s = "DEBUG";
00049     for(int i=0; i<N_MESSAGE_LEVELS; ++i){
00050       if(s == EnumToString((MESSAGE_LEVEL(i))) )
00051         return MESSAGE_LEVEL(i);
00052     }
00053     //if we got here, there was an error
00054     MESSAGE_LEVEL newlevel = 
00055       MessageHandler::GetInstance()->GetDefaultMessageThreshold();
00056     std::cerr<<"ERROR: Unknown message level "<<s
00057         <<"; setting to "<<newlevel<<"\n";
00058     return newlevel;
00059   }
00060 }
00061   
00062 
00063 //operator overloads for MESSAGE_LEVEL
00064 std::ostream& operator<<(std::ostream& out, const MESSAGE_LEVEL& level)
00065 {
00066   return out<<MessageLevelConversion::EnumToString(level);
00067 }
00068 
00069 std::istream& operator>>(std::istream& in, MESSAGE_LEVEL& level)
00070 {
00071   std::string temp;
00072   in>>temp;
00073   level = MessageLevelConversion::StringToEnum(temp);
00074   return in;
00075 }
00076 
00077 MESSAGE_LEVEL& operator++(MESSAGE_LEVEL& level)
00078 {
00079   if( level == (N_MESSAGE_LEVELS-1) )
00080     return level;
00081   else 
00082     return level = (MESSAGE_LEVEL)( (int)level + 1 );
00083 }
00084 
00085 MESSAGE_LEVEL& operator--(MESSAGE_LEVEL& level)
00086 {
00087   if( (int)level == 0 )
00088     return level;
00089   else
00090     return level = (MESSAGE_LEVEL)( (int)level - 1 );
00091 }
00092 
00093 typedef MessageHandler::PrintToStream PrintToStream;
00094 
00095 //some helpers
00096 
00097                                                 
00098 MessageHandler MessageHandler::_instance;
00099 
00100 void PrintToStream::operator()(const std::string& s, MESSAGE_LEVEL level,
00101                             time_t t)
00102 {
00103   std::string color = "", header = "";
00104   if(level <= DEBUG){
00105     header = "DEBUG: ";
00106     //color = "\x1B[33m";
00107   }  
00108   else if(level == WARNING){
00109     //color = "\x1B[1m\x1B[33m";
00110     color = "\x1B[33m";
00111     header = "WARNING: ";
00112   }
00113   else if(level >= ERROR){
00114     color = "\x1B[31m";
00115     header = MessageLevelConversion::EnumToString(level)+": ";
00116   }
00117   
00118   
00119   const char* set_norm = "\x1B[0m";
00120   
00121   struct tm * timeinfo;
00122   char timestamp[12];
00123   timeinfo = localtime( &t );
00124   strftime(timestamp,12,"%X ",timeinfo);
00125   if(_use_color) 
00126     _stream<<color;
00127   _stream << timestamp << header << s;
00128   if(_use_color)
00129     _stream<<set_norm<<std::flush;
00130 }
00131   
00132 MessageHandler::MessageHandler() : _default_threshold(INFO)
00133 {
00134   AddMessenger(INFO,PrintToStream());
00135 #ifndef SINGLETHREAD
00136   _kill_thread=false;
00137   _inbox_mutex = new boost::mutex;
00138   _message_waiting = new boost::condition_variable;
00139   _delivery_thread = new boost::thread(boost::ref(*this));
00140 #endif
00141   ConfigHandler* config = ConfigHandler::GetInstance();
00142   config->RegisterParameter("verbosity", _default_threshold,
00143                             "Threshold below which messages are suppressed");
00144   config->AddCommandSwitch('v',"verbose","increment verbosity",
00145                            CommandSwitch::Decrement<MESSAGE_LEVEL>
00146                            (_default_threshold));
00147   config->AddCommandSwitch('q',"quiet","decrement verbosity",
00148                            CommandSwitch::Increment<MESSAGE_LEVEL>
00149                            (_default_threshold));
00150   config->AddCommandSwitch(' ',"verbosity","set verbosity to <level>",
00151                            CommandSwitch::DefaultRead<MESSAGE_LEVEL>
00152                            (_default_threshold), "level");
00153 }
00154 
00155 void MessageHandler::End()
00156 {
00157 #ifndef SINGLETHREAD
00158   _kill_thread = true;
00159   _message_waiting->notify_one();
00160   //_delivery_thread->interrupt();
00161   _delivery_thread->join();
00162 #endif
00163 }  
00164 
00165 MessageHandler::~MessageHandler()
00166 {
00167   End();
00168 #ifndef SINGLETHREAD
00169   delete _delivery_thread;
00170   delete _inbox_mutex;
00171   delete _message_waiting;
00172 #endif
00173   for(std::set<VMessenger*>::iterator it = _messengers.begin();
00174       it!=_messengers.end(); ++it)
00175     delete *it;
00176   _messengers.clear();
00177 }
00178 
00179 void MessageHandler::RemoveMessenger(void* messenger)
00180 {
00181   VMessenger* m = (VMessenger*)messenger;
00182   if(_messengers.erase(m))
00183     delete m;
00184 }
00185 
00186 void MessageHandler::SetThreshold(MESSAGE_LEVEL thresh, void* messenger)
00187 {
00188   if(messenger){
00189     VMessenger* m = (VMessenger*)messenger;
00190     if(_messengers.count(m))
00191       m->SetThreshold(thresh);
00192     else
00193       std::cerr<<"No messenger known at pointer "<<messenger<<std::endl;
00194   }
00195   else{
00196     for(std::set<VMessenger*>::iterator it = _messengers.begin();
00197         it != _messengers.end();
00198         ++it){
00199       (*it)->SetThreshold(thresh);
00200     }
00201   }
00202 }
00203 
00204 void MessageHandler::Deliver(std::ostringstream* msg, MESSAGE_LEVEL level,
00205                              time_t t)
00206 {
00207   for(std::set<VMessenger*>::iterator it = _messengers.begin();
00208       it != _messengers.end(); it++){
00209     if( *it != 0)
00210       (*it)->Deliver(msg, level, t);
00211   }
00212   delete msg;
00213 }
00214   
00215 #ifndef SINGLETHREAD
00216 
00217 void MessageHandler::Post(std::ostringstream* msg, MESSAGE_LEVEL level)
00218 {
00219   boost::unique_lock<boost::mutex> lock(*_inbox_mutex);
00220   _inbox.push( MsgData(msg,level));
00221   _message_waiting->notify_one();
00222 }
00223 
00224 void MessageHandler::operator()()
00225 {
00226   //return;
00227   while(1){
00228     boost::unique_lock<boost::mutex> lock(*_inbox_mutex);
00229     while(_inbox.empty() && !_kill_thread ){
00230       _message_waiting->wait(lock);
00231       //mutex is unlocked while waiting
00232     }
00233     if( _kill_thread && _inbox.empty()) break;
00234     //mutex is locked again once the condition return
00235     MsgData next = _inbox.front();
00236     _inbox.pop();
00237     lock.unlock();
00238     Deliver(next.msg, next.level, next.t);
00239   }
00240 }
00241 
00242 #else 
00243 void MessageHandler::Post(std::ostringstream* msg, MESSAGE_LEVEL level)
00244 {
00245   Deliver(msg, level);
00246 }
00247 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on 20 Jun 2014 for daqman by  doxygen 1.6.1