Back to index

nordugrid-arc-nox  1.1.0~rc6
Logger.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 #include <sstream>
00008 #include <fstream>
00009 
00010 #include <unistd.h>
00011 
00012 #include "Logger.h"
00013 #include "DateTime.h"
00014 #include "StringConv.h"
00015 
00016 #include <unistd.h>
00017 #ifdef WIN32
00018 #include <process.h>
00019 #endif
00020 
00021 #undef rootLogger
00022 
00023 namespace Arc {
00024 
00025   std::ostream& operator<<(std::ostream& os, LogLevel level) {
00026     if (level == DEBUG)
00027       os << "DEBUG";
00028     else if (level == VERBOSE)
00029       os << "VERBOSE";
00030     else if (level == INFO)
00031       os << "INFO";
00032     else if (level == WARNING)
00033       os << "WARNING";
00034     else if (level == ERROR)
00035       os << "ERROR";
00036     else if (level == FATAL)
00037       os << "FATAL";
00038     // There should be no more alternative!
00039     return os;
00040   }
00041 
00042   LogLevel string_to_level(const std::string& str) {
00043     if (str == "DEBUG")
00044       return DEBUG;
00045     else if (str == "VERBOSE")
00046       return VERBOSE;
00047     else if (str == "INFO")
00048       return INFO;
00049     else if (str == "WARNING")
00050       return WARNING;
00051     else if (str == "ERROR")
00052       return ERROR;
00053     else if (str == "FATAL")
00054       return FATAL;
00055     else  // should not happen...
00056       return FATAL;
00057   }
00058 
00059   bool string_to_level(const std::string& str, LogLevel& ll) {
00060     if (str == "DEBUG")
00061       ll = DEBUG;
00062     else if (str == "VERBOSE")
00063       ll = VERBOSE;
00064     else if (str == "INFO")
00065       ll = INFO;
00066     else if (str == "WARNING")
00067       ll = WARNING;
00068     else if (str == "ERROR")
00069       ll = ERROR;
00070     else if (str == "FATAL")
00071       ll = FATAL;
00072     else  // should not happen...
00073       return false;
00074 
00075     return true;
00076   }
00077 
00078   bool istring_to_level(const std::string& llStr, LogLevel& ll) {
00079     const std::string str = upper(llStr);
00080     if (str == "DEBUG")
00081       ll = DEBUG;
00082     else if (str == "VERBOSE")
00083       ll = VERBOSE;
00084     else if (str == "INFO")
00085       ll = INFO;
00086     else if (str == "WARNING")
00087       ll = WARNING;
00088     else if (str == "ERROR")
00089       ll = ERROR;
00090     else if (str == "FATAL")
00091       ll = FATAL;
00092     else
00093       return false;
00094 
00095     return true;
00096   }
00097 
00098   std::string level_to_string(const LogLevel& level) {
00099     switch (level) {
00100       case DEBUG:
00101         return "DEBUG";
00102       case VERBOSE:
00103         return "VERBOSE";
00104       case INFO:
00105         return "INFO";
00106       case WARNING:
00107         return "WARNING";
00108       case ERROR:
00109         return "ERROR";
00110       case FATAL:
00111         return "FATAL";
00112       default:  // should not happen...
00113         return "";
00114     }
00115   }
00116 
00117   LogMessage::LogMessage(LogLevel level,
00118                          const IString& message)
00119     : time(TimeStamp()),
00120       level(level),
00121       domain("---"),
00122       identifier(getDefaultIdentifier()),
00123       message(message) {}
00124 
00125   LogMessage::LogMessage(LogLevel level,
00126                          const IString& message,
00127                          const std::string& identifier)
00128     : time(TimeStamp()),
00129       level(level),
00130       domain("---"),
00131       identifier(identifier),
00132       message(message) {}
00133 
00134   LogLevel LogMessage::getLevel() const {
00135     return level;
00136   }
00137 
00138   void LogMessage::setIdentifier(std::string identifier) {
00139     this->identifier = identifier;
00140   }
00141 
00142   std::string LogMessage::getDefaultIdentifier() {
00143     std::ostringstream sout;
00144 #ifdef HAVE_GETPID
00145     sout << getpid() << "/"
00146          << (unsigned long int)(void*)Glib::Thread::self();
00147 #else
00148     sout << (unsigned long int)(void*)Glib::Thread::self();
00149 #endif
00150     return sout.str();
00151   }
00152 
00153   void LogMessage::setDomain(std::string domain) {
00154     this->domain = domain;
00155   }
00156 
00157   static const int formatindex = std::ios_base::xalloc();
00158 
00159   std::ostream& operator<<(std::ostream& os, const LoggerFormat& format) {
00160     os.iword(formatindex) = format.format;
00161     return os;
00162   }
00163 
00164   std::ostream& operator<<(std::ostream& os, const LogMessage& message) {
00165     switch (os.iword(formatindex)) {
00166     case LongFormat:
00167       os << "[" << message.time << "] "
00168          << "[" << message.domain << "] "
00169          << "[" << message.level << "] "
00170          << "[" << message.identifier << "] "
00171          << message.message;
00172       break;
00173     case ShortFormat:
00174       os << message.level << ": " << message.message;
00175       break;
00176     }
00177     return os;
00178   }
00179 
00180   LogDestination::LogDestination()
00181     : format(LongFormat) {}
00182 
00183   LogDestination::LogDestination(const std::string& locale)
00184     : locale(locale),
00185       format(LongFormat) {}
00186 
00187   LogDestination::LogDestination(const LogDestination&) {
00188     // Executing this code should be impossible!
00189     exit(EXIT_FAILURE);
00190   }
00191 
00192   void LogDestination::operator=(const LogDestination&) {
00193     // Executing this code should be impossible!
00194     exit(EXIT_FAILURE);
00195   }
00196 
00197   void LogDestination::setFormat(const LogFormat& newformat) {
00198     format = newformat;
00199   }
00200 
00201   LogStream::LogStream(std::ostream& destination)
00202     : destination(destination) {}
00203 
00204   LogStream::LogStream(std::ostream& destination,
00205                        const std::string& locale)
00206     : LogDestination(locale),
00207       destination(destination) {}
00208 
00209   void LogStream::log(const LogMessage& message) {
00210     Glib::Mutex::Lock lock(mutex);
00211     const char *loc = NULL;
00212     if (!locale.empty()) {
00213       loc = setlocale(LC_ALL, NULL);
00214       setlocale(LC_ALL, locale.c_str());
00215     }
00216     destination << LoggerFormat(format) << message << std::endl;
00217     if (!locale.empty()) setlocale(LC_ALL, loc);
00218   }
00219 
00220   LogStream::LogStream(const LogStream&)
00221     : LogDestination(),
00222       destination(std::cerr) {
00223     // Executing this code should be impossible!
00224     exit(EXIT_FAILURE);
00225   }
00226 
00227   void LogStream::operator=(const LogStream&) {
00228     // Executing this code should be impossible!
00229     exit(EXIT_FAILURE);
00230   }
00231 
00232   LogFile::LogFile(const std::string& path)
00233     : LogDestination(),
00234       path(path),
00235       destination(),
00236       maxsize(-1),
00237       backups(-1) {
00238     if(path.empty()) {
00239       //logger.msg(Arc::ERROR,"Log file path is not specified");
00240       return;
00241     }
00242     destination.open(path.c_str(), std::fstream::out | std::fstream::app);
00243     if(!destination.is_open()) {
00244       //logger.msg(Arc::ERROR,"Failed to open log file: %s",path);
00245       return;
00246     }
00247   }
00248 
00249   LogFile::LogFile(const std::string& path, const std::string& locale)
00250     : LogDestination(locale),
00251       path(path),
00252       destination(),
00253       maxsize(-1),
00254       backups(-1) {
00255     if(path.empty()) {
00256       //logger.msg(Arc::ERROR,"Log file path is not specified");
00257       return;
00258     }
00259     destination.open(path.c_str(), std::fstream::out | std::fstream::app);
00260     if(!destination.is_open()) {
00261       //logger.msg(Arc::ERROR,"Failed to open log file: %s",path);
00262       return;
00263     }
00264   }
00265 
00266   void LogFile::setMaxSize(int newsize) {
00267     maxsize = newsize;
00268   }
00269 
00270   void LogFile::setBackups(int newbackups) {
00271     backups = newbackups;
00272   }
00273 
00274   LogFile::LogFile(void)
00275     : LogDestination(), maxsize(-1), backups(-1) {
00276     // Executing this code should be impossible!
00277     exit(EXIT_FAILURE);
00278   }
00279 
00280   LogFile::LogFile(const LogFile&)
00281     : LogDestination(), maxsize(-1), backups(-1) {
00282     // Executing this code should be impossible!
00283     exit(EXIT_FAILURE);
00284   }
00285 
00286   void LogFile::operator=(const LogFile&) {
00287     // Executing this code should be impossible!
00288     exit(EXIT_FAILURE);
00289   }
00290   LogFile::operator bool(void) {
00291     Glib::Mutex::Lock lock(mutex);
00292     return destination.is_open();
00293   }
00294 
00295   bool LogFile::operator!(void) {
00296     Glib::Mutex::Lock lock(mutex);
00297     return !destination.is_open();
00298   }
00299 
00300   void LogFile::log(const LogMessage& message) {
00301     Glib::Mutex::Lock lock(mutex);
00302     if(!destination.is_open()) return;
00303     const char *loc = NULL;
00304     if (!locale.empty()) {
00305       loc = setlocale(LC_ALL, NULL);
00306       setlocale(LC_ALL, locale.c_str());
00307     }
00308     destination << LoggerFormat(format) << message << std::endl;
00309     if (!locale.empty()) setlocale(LC_ALL, loc);
00310     backup();
00311   }
00312 
00313   void LogFile::backup(void) {
00314     if(maxsize <= 0) return;
00315     if(destination.tellp() < maxsize) return;
00316     bool backup_done = true;
00317     // Not sure if this will work on windows, but glibmm
00318     // has no functions for removing and renaming files
00319     if(backups > 0) {
00320       std::string backup_path = path+"."+tostring(backups);
00321       ::unlink(backup_path.c_str());
00322       for(int n = backups;n>0;--n) {
00323         std::string old_backup_path = (n>1)?(path+"."+tostring(n-1)):path;
00324         if(::rename(old_backup_path.c_str(),backup_path.c_str()) != 0) {
00325           if(n == 1) backup_done=false;
00326         }
00327         backup_path = old_backup_path;
00328       }
00329     } else {
00330       if(::unlink(path.c_str()) != 0) backup_done=false;
00331     }
00332     if(backup_done) {
00333       destination.close();
00334       destination.open(path.c_str(), std::fstream::out | std::fstream::app);
00335     }
00336   }
00337 
00338   Logger*Logger::rootLogger = NULL;
00339   unsigned int Logger::rootLoggerMark = ~rootLoggerMagic;
00340 
00341   Logger& Logger::getRootLogger(void) {
00342     if ((rootLogger == NULL) || (rootLoggerMark != rootLoggerMagic)) {
00343       rootLogger = new Logger();
00344       rootLoggerMark = rootLoggerMagic;
00345     }
00346     return *rootLogger;
00347   }
00348 
00349   // LogStream Logger::cerr(std::cerr);
00350 
00351   Logger::Logger(Logger& parent,
00352                  const std::string& subdomain)
00353     : parent(&parent),
00354       domain(parent.getDomain() + "." + subdomain),
00355       threshold(parent.getThreshold()) {
00356     // Nothing else needs to be done.
00357   }
00358 
00359   Logger::Logger(Logger& parent,
00360                  const std::string& subdomain,
00361                  LogLevel threshold)
00362     : parent(&parent),
00363       domain(parent.getDomain() + "." + subdomain),
00364       threshold(threshold) {
00365     // Nothing else needs to be done.
00366   }
00367 
00368   Logger::~Logger() {
00369   }
00370 
00371   void Logger::addDestination(LogDestination& destination) {
00372     destinations.push_back(&destination);
00373   }
00374 
00375   void Logger::removeDestinations(void) {
00376     destinations.clear();
00377   }
00378 
00379   void Logger::setThreshold(LogLevel threshold) {
00380     this->threshold = threshold;
00381   }
00382 
00383   LogLevel Logger::getThreshold() const {
00384     return threshold;
00385   }
00386 
00387   void Logger::msg(LogMessage message) {
00388     message.setDomain(domain);
00389     log(message);
00390   }
00391 
00392   Logger::Logger()
00393     : parent(0),
00394       domain("Arc"),
00395       threshold(DEBUG) {
00396     // addDestination(cerr);
00397   }
00398 
00399   Logger::Logger(const Logger&) {
00400     // Executing this code should be impossible!
00401     exit(EXIT_FAILURE);
00402   }
00403 
00404   void Logger::operator=(const Logger&) {
00405     // Executing this code should be impossible!
00406     exit(EXIT_FAILURE);
00407   }
00408 
00409   std::string Logger::getDomain() {
00410     return domain;
00411   }
00412 
00413   void Logger::log(const LogMessage& message) {
00414     if (message.getLevel() >= threshold) {
00415       std::list<LogDestination*>::iterator dest;
00416       std::list<LogDestination*>::iterator begin = destinations.begin();
00417       std::list<LogDestination*>::iterator end = destinations.end();
00418       for (dest = begin; dest != end; ++dest)
00419         (*dest)->log(message);
00420       if (parent != 0)
00421         parent->log(message);
00422     }
00423   }
00424 
00425 }