diff --git a/SConstruct b/SConstruct index 4b1b9813af..4a25c82e82 100644 --- a/SConstruct +++ b/SConstruct @@ -118,6 +118,9 @@ if mysql=='yes': else: main_env.Append(mysql='no') +# log4cpp +main_env.Append(LIBS=['pthread','log4cpp']) + # xmlrpc xmlrpc_dir=ARGUMENTS.get('xmlrpc', 'none') if xmlrpc_dir!='none': diff --git a/include/Log.h b/include/Log.h index 49d96d7ae2..8f307499bf 100644 --- a/include/Log.h +++ b/include/Log.h @@ -20,6 +20,10 @@ #include #include +#include "PoolObjectSQL.h" + +#include "log4cpp/Priority.hh" + using namespace std; /** @@ -79,7 +83,7 @@ public: const char * module, const MessageType type, const char * message); - + private: char * log_file; }; @@ -137,4 +141,77 @@ public: const char * message); }; +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +/** + * Send log messages to syslog + */ +class SysLog : public Log +{ +public: + SysLog(const MessageType level, + const string& label); + + virtual ~SysLog() {}; + + virtual void log( + const char * module, + const MessageType type, + const char * message); + + static log4cpp::Priority::PriorityLevel get_priority_level( + const MessageType level); +protected: + /** + * Specialized constructor only for derived classes that uses an initialzed + * SysLog system. + */ + SysLog(const MessageType level):Log(level){}; + + /** + * This is the root category name used by any syslog resource + * in the process + */ + static const char * CATEGORY; + + /** + * This is the daemon name+pid, used to label every message in the process + */ + static string LABEL; + +}; + +/** + * Send log messages to syslog per resource. It requires a Root Syslog + * to be initialized before using a SysLogResource + */ +class SysLogResource : public SysLog +{ +public: + SysLogResource( + int oid, + const PoolObjectSQL::ObjectType obj_type, + const MessageType clevel); + + virtual ~SysLogResource(){}; + + void log( + const char * module, + const MessageType type, + const char * message); + +protected: + /** + * This is the resource category name used by any syslog resource + * in the process + */ + static const char * CATEGORY; + + /** + * The resource log label + */ + string obj_label; +}; + #endif /* _LOG_H_ */ diff --git a/include/Nebula.h b/include/Nebula.h index aeb2dea417..9b68cb3188 100644 --- a/include/Nebula.h +++ b/include/Nebula.h @@ -172,24 +172,61 @@ public: // -------------------------------------------------------------- /** - * Returns the value of DEBUG_LEVEL in oned.conf file + * Returns the value of LOG->DEBUG_LEVEL in oned.conf file * @return the debug level, to instantiate Log'ers */ Log::MessageType get_debug_level() const { - Log::MessageType clevel = Log::ERROR; - int log_level_int; + Log::MessageType clevel = Log::ERROR; + vector logs; + int rc; + int log_level_int; - nebula_configuration->get("DEBUG_LEVEL", log_level_int); + rc = nebula_configuration->get("LOG", logs); - if (0 <= log_level_int && log_level_int <= 3 ) + if ( rc != 0 ) { - clevel = static_cast(log_level_int); + string value; + const VectorAttribute * log = static_cast + (logs[0]); + value = log->vector_value("DEBUG_LEVEL"); + + log_level_int = atoi(value.c_str()); + + if (0 <= log_level_int && log_level_int <= 3 ) + { + clevel = static_cast(log_level_int); + } } return clevel; } + /** + * Returns the value of LOG->SYSTEM in oned.conf file + * @return the logging system CERR, FILE_TS or SYSLOG + */ + NebulaLog::LogType get_log_system() const + { + vector logs; + int rc; + NebulaLog::LogType log_system = NebulaLog::UNDEFINED; + + rc = nebula_configuration->get("LOG", logs); + + if ( rc != 0 ) + { + string value; + const VectorAttribute * log = static_cast + (logs[0]); + + value = log->vector_value("SYSTEM"); + log_system = NebulaLog::str_to_type(value); + } + + return log_system; + }; + /** * Returns the value of ONE_LOCATION env variable. When this variable is * not defined the nebula location is "/". diff --git a/include/NebulaLog.h b/include/NebulaLog.h index 9eaf902606..ae39469dfd 100644 --- a/include/NebulaLog.h +++ b/include/NebulaLog.h @@ -18,7 +18,9 @@ #define _NEBULA_LOG_H_ #include "Log.h" + #include +#include using namespace std; @@ -31,7 +33,9 @@ public: enum LogType { FILE = 0, FILE_TS = 1, - CERR = 2 + CERR = 2, + SYSLOG = 3, + UNDEFINED = 4 }; // --------------------------------------------------------------- @@ -41,23 +45,47 @@ public: static void init_log_system( LogType ltype, Log::MessageType clevel, - const char * filename = 0, - ios_base::openmode mode = ios_base::trunc) + const char * filename, + ios_base::openmode mode, + const string& daemon) { switch(ltype) { case FILE: - NebulaLog::logger = new FileLog(filename,clevel,mode); - break; + NebulaLog::logger = new FileLog(filename,clevel,mode); + break; case FILE_TS: - NebulaLog::logger = new FileLogTS(filename,clevel,mode); - break; + NebulaLog::logger = new FileLogTS(filename,clevel,mode); + break; + case SYSLOG: + NebulaLog::logger = new SysLog(clevel, daemon); + break; default: - NebulaLog::logger = new CerrLog(clevel); - break; + NebulaLog::logger = new CerrLog(clevel); + break; } }; + static LogType str_to_type(string& type) + { + transform(type.begin(), type.end(), type.begin(), (int(*)(int))toupper); + + if (type == "FILE") + { + return FILE_TS; + } + else if (type == "SYSLOG") + { + return SYSLOG; + } + else if (type == "STDERR") + { + return CERR; + } + + return UNDEFINED; + } + static void finalize_log_system() { delete logger; diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index 633e186516..64a3e7fdca 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -1049,8 +1049,9 @@ private: * $ONE_LOCATION/var/$VID/vm.log * or, in case that OpenNebula is installed in root * /var/log/one/$VM_ID.log + * For the syslog... TODO */ - FileLog * _log; + Log * _log; /** * User template to store custom metadata. This template can be updated diff --git a/share/etc/oned.conf b/share/etc/oned.conf index f32a3254f0..14ee16d8d6 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -37,11 +37,21 @@ # VNC_BASE_PORT: VNC ports for VMs can be automatically set to VNC_BASE_PORT + # VMID # -# DEBUG_LEVEL: 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG +# LOG: Configuration for the logging system +# system: defines the logging system: +# file to log in the oned.log file +# syslog to use the syslog facilities +# debug_level: 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG # # VM_SUBMIT_ON_HOLD: Forces VMs to be created on hold state instead of pending. # Values: YES or NO. #******************************************************************************* +# + +LOG = [ + system = "file", + debug_level = 3 +] #MANAGER_TIMER = 30 @@ -69,8 +79,6 @@ DB = [ backend = "sqlite" ] VNC_BASE_PORT = 5900 -DEBUG_LEVEL = 3 - #VM_SUBMIT_ON_HOLD = "NO" #******************************************************************************* diff --git a/src/log/Log.cc b/src/log/Log.cc index a8a77b2126..f515bfe575 100644 --- a/src/log/Log.cc +++ b/src/log/Log.cc @@ -22,6 +22,19 @@ #include #include +#include +#include + +#include + +#include "log4cpp/Category.hh" +#include "log4cpp/CategoryStream.hh" +#include "log4cpp/Appender.hh" +#include "log4cpp/SyslogAppender.hh" +#include "log4cpp/Layout.hh" +#include "log4cpp/PatternLayout.hh" +#include "log4cpp/Priority.hh" + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -141,3 +154,162 @@ void CerrLog::log( cerr.flush(); } } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +const char * SysLog::CATEGORY = "ROOT"; +string SysLog::LABEL; + +/* -------------------------------------------------------------------------- */ + +SysLog::SysLog(const MessageType level, + const string& label):Log(level) +{ + static bool initialized = false; + + if (!initialized) //Initialize just once for all SysLog instances + { + ostringstream oss; + log4cpp::Appender *appender; + + oss << label << "[" << getpid() << "]"; + + LABEL = oss.str(); + + appender = new log4cpp::SyslogAppender(CATEGORY, LABEL, LOG_DAEMON); + appender->setLayout(new log4cpp::PatternLayout()); + + log4cpp::Category& root = log4cpp::Category::getRoot(); + + root.setPriority(SysLog::get_priority_level(level)); + root.addAppender(appender); + + initialized = true; + } +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void SysLog::log( + const char * module, + const MessageType type, + const char * message) +{ + log4cpp::Category& root = log4cpp::Category::getRoot(); + log4cpp::Priority::PriorityLevel level = get_priority_level(type); + + istringstream smessage; + string line; + + smessage.str(message); + + while ( getline(smessage, line) ) + { + root << level << "[" << module << "]" + << "[" << error_names[type] << "]: " + << line; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +log4cpp::Priority::PriorityLevel SysLog::get_priority_level( + const MessageType level) +{ + log4cpp::Priority::PriorityLevel priority_level; + + switch (level) + { + case Log::ERROR: + priority_level = log4cpp::Priority::ERROR; + break; + + case Log::WARNING: + priority_level = log4cpp::Priority::WARN; + break; + + case Log::INFO: + priority_level = log4cpp::Priority::INFO; + break; + + case Log::DEBUG: + case Log::DDEBUG: + case Log::DDDEBUG: + priority_level = log4cpp::Priority::DEBUG; + break; + + default: + priority_level = log4cpp::Priority::NOTSET; + break; + } + + return priority_level; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +const char * SysLogResource::CATEGORY = "RESOURCE"; + +/* -------------------------------------------------------------------------- */ + +SysLogResource::SysLogResource( + int oid, + const PoolObjectSQL::ObjectType obj_type, + const MessageType clevel):SysLog(clevel) +{ + static bool initialized = false; + ostringstream oss_label; + string obj_type_str; + + if (!initialized) + { + log4cpp::Appender *appender; + + appender = new log4cpp::SyslogAppender(CATEGORY, + SysLog::LABEL, + LOG_DAEMON); + + appender->setLayout(new log4cpp::PatternLayout()); + + log4cpp::Category& res = log4cpp::Category::getInstance(CATEGORY); + + res.addAppender(appender); + res.setPriority(SysLog::get_priority_level(clevel)); + + initialized = true; + } + + obj_type_str = PoolObjectSQL::type_to_str(obj_type); + + oss_label << "[" << obj_type_str << " " << oid << "]"; + obj_label = oss_label.str(); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void SysLogResource::log( + const char * module, + const MessageType type, + const char * message) +{ + log4cpp::Category& res = log4cpp::Category::getInstance(CATEGORY); + log4cpp::Priority::PriorityLevel level = get_priority_level(type); + + istringstream smessage; + string line; + + smessage.str(message); + + while ( getline(smessage, line) ) + { + res << level << obj_label + << "[" << module << "]" + << "[" << error_names[type] << "]: " + << line; + } +} diff --git a/src/nebula/Nebula.cc b/src/nebula/Nebula.cc index d69d34427a..418ad6117b 100644 --- a/src/nebula/Nebula.cc +++ b/src/nebula/Nebula.cc @@ -317,18 +317,28 @@ void Nebula::start() try { - string log_fname; - Log::MessageType clevel; + Log::MessageType clevel; + NebulaLog::LogType log_system; - log_fname = log_location + "oned.log"; - clevel = get_debug_level(); + log_system = get_log_system(); + clevel = get_debug_level(); // Initializing ONE Daemon log system + if ( log_system != NebulaLog::UNDEFINED ) + { + string log_fname; + log_fname = log_location + "oned.log"; - NebulaLog::init_log_system(NebulaLog::FILE_TS, - clevel, - log_fname.c_str(), - ios_base::trunc); + NebulaLog::init_log_system(log_system, + clevel, + log_fname.c_str(), + ios_base::trunc, + "oned"); + } + else + { + throw runtime_error("Unknown LOG_SYSTEM."); + } os << "Starting " << version() << endl; os << "----------------------------------------\n"; diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index b16af0641e..65b0df29ee 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -78,6 +78,7 @@ void OpenNebulaTemplate::set_conf_default() SingleAttribute * attribute; VectorAttribute * vattribute; string value; + map vvalue; // MANAGER_TIMER value = "15"; @@ -144,7 +145,6 @@ void OpenNebulaTemplate::set_conf_default() conf_default.insert(make_pair(attribute->name(),attribute)); //DB CONFIGURATION - map vvalue; vvalue.insert(make_pair("BACKEND","sqlite")); vattribute = new VectorAttribute("DB",vvalue); @@ -174,6 +174,13 @@ void OpenNebulaTemplate::set_conf_default() attribute = new SingleAttribute("VM_SUBMIT_ON_HOLD",value); conf_default.insert(make_pair(attribute->name(),attribute)); + // LOG CONFIGURATION + vvalue.clear(); + vvalue.insert(make_pair("SYSTEM","file")); + vvalue.insert(make_pair("DEBUG_LEVEL","3")); + + vattribute = new VectorAttribute("LOG",vvalue); + conf_default.insert(make_pair(vattribute->name(),vattribute)); /* #******************************************************************************* # Physical Networks configuration diff --git a/src/scheduler/etc/sched.conf b/src/scheduler/etc/sched.conf index 543a274078..d5be6c0d4b 100644 --- a/src/scheduler/etc/sched.conf +++ b/src/scheduler/etc/sched.conf @@ -9,31 +9,37 @@ # # SCHED_INTERVAL: Seconds between two scheduling actions # -# MAX_VM: Maximum number of Virtual Machines scheduled in each scheduling +# MAX_VM: Maximum number of Virtual Machines scheduled in each scheduling # action # # MAX_DISPATCH: Maximum number of Virtual Machines actually dispatched to a # host in each scheduling action # -# MAX_HOST: Maximum number of Virtual Machines dispatched to a given host in +# MAX_HOST: Maximum number of Virtual Machines dispatched to a given host in # each scheduling action # # LIVE_RESCHEDS: Perform live (1) or cold migrations (0) when rescheduling a VM # -# HYPERVISOR_MEM: Fraction of total MEMORY reserved for the hypervisor. +# HYPERVISOR_MEM: Fraction of total MEMORY reserved for the hypervisor. # E.g. 0.1 means that only 90% of the total MEMORY will be used # # DEFAULT_SCHED: Definition of the default scheduling algorithm -# - policy: -# 0 = Packing. Heuristic that minimizes the number of hosts in use by +# - policy: +# 0 = Packing. Heuristic that minimizes the number of hosts in use by # packing the VMs in the hosts to reduce VM fragmentation -# 1 = Striping. Heuristic that tries to maximize resources available for +# 1 = Striping. Heuristic that tries to maximize resources available for # the VMs by spreading the VMs in the hosts # 2 = Load-aware. Heuristic that tries to maximize resources available for # the VMs by usingthose nodes with less load -# 3 = Custom. +# 3 = Custom. # - rank: Custom arithmetic exprission to rank suitable hosts based in their # attributes +# +# LOG: Configuration for the logging system +# - system: defines the logging system: +# file to log in the sched.log file +# syslog to use the syslog facilities +# - debug_level: 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBU #******************************************************************************* ONED_PORT = 2633 @@ -49,10 +55,15 @@ LIVE_RESCHEDS = 0 HYPERVISOR_MEM = 0.1 DEFAULT_SCHED = [ - policy = 1 + policy = 1 ] #DEFAULT_SCHED = [ -# policy = 3, +# policy = 3, # rank = "- (RUNNING_VMS * 50 + FREE_CPU)" #] + +LOG = [ + system = "file", + debug_level = 3 +] diff --git a/src/scheduler/include/Scheduler.h b/src/scheduler/include/Scheduler.h index 52b0f32da5..c6ef296a6b 100644 --- a/src/scheduler/include/Scheduler.h +++ b/src/scheduler/include/Scheduler.h @@ -140,7 +140,6 @@ private: friend void * scheduler_action_loop(void *arg); - // --------------------------------------------------------------- // Scheduling Policies // --------------------------------------------------------------- diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 87474a7e8a..43ac4a69f9 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -77,46 +77,28 @@ void Scheduler::start() pthread_attr_t pattr; - // ----------------------------------------------------------- - // Log system & Configuration File - // ----------------------------------------------------------- - - try - { - string log_file; - const char * nl = getenv("ONE_LOCATION"); - - if (nl == 0) //OpenNebula installed under root directory - { - log_file = "/var/log/one/sched.log"; - etc_path = "/etc/one/"; - } - else - { - oss << nl << "/var/sched.log"; - - log_file = oss.str(); - - oss.str(""); - oss << nl << "/etc/"; - - etc_path = oss.str(); - } - - NebulaLog::init_log_system(NebulaLog::FILE, - Log::DEBUG, - log_file.c_str()); - - NebulaLog::log("SCHED", Log::INFO, "Init Scheduler Log system"); - } - catch(runtime_error &) - { - throw; - } - // ----------------------------------------------------------- // Configuration File // ----------------------------------------------------------- + string log_file; + const char * nl = getenv("ONE_LOCATION"); + + if (nl == 0) //OpenNebula installed under root directory + { + log_file = "/var/log/one/sched.log"; + etc_path = "/etc/one/"; + } + else + { + oss << nl << "/var/sched.log"; + + log_file = oss.str(); + + oss.str(""); + oss << nl << "/etc/"; + + etc_path = oss.str(); + } SchedulerTemplate conf(etc_path); @@ -143,6 +125,60 @@ void Scheduler::start() conf.get("HYPERVISOR_MEM", hypervisor_mem); + // ----------------------------------------------------------- + // Log system & Configuration File + // ----------------------------------------------------------- + + try + { + vector logs; + int rc; + + NebulaLog::LogType log_system = NebulaLog::UNDEFINED; + Log::MessageType clevel = Log::ERROR;; + + rc = conf.get("LOG", logs); + + if ( rc != 0 ) + { + string value; + int ilevel; + + const VectorAttribute * log = static_cast + (logs[0]); + value = log->vector_value("SYSTEM"); + log_system = NebulaLog::str_to_type(value); + + value = log->vector_value("DEBUG_LEVEL"); + ilevel = atoi(value.c_str()); + + if (0 <= ilevel && ilevel <= 3 ) + { + clevel = static_cast(ilevel); + } + } + + // Start the log system + if ( log_system != NebulaLog::UNDEFINED ) + { + NebulaLog::init_log_system(log_system, + clevel, + log_file.c_str(), + ios_base::trunc, + "mm_sched"); + } + else + { + throw runtime_error("Unknown LOG_SYSTEM."); + } + + NebulaLog::log("SCHED", Log::INFO, "Init Scheduler Log system"); + } + catch(runtime_error &) + { + throw; + } + oss.str(""); oss << "Starting Scheduler Daemon" << endl; @@ -167,7 +203,6 @@ void Scheduler::start() throw; } - xmlInitParser(); // ----------------------------------------------------------- diff --git a/src/scheduler/src/sched/SchedulerTemplate.cc b/src/scheduler/src/sched/SchedulerTemplate.cc index e8e6d1bf01..79c77ba4c9 100644 --- a/src/scheduler/src/sched/SchedulerTemplate.cc +++ b/src/scheduler/src/sched/SchedulerTemplate.cc @@ -29,6 +29,7 @@ void SchedulerTemplate::set_conf_default() SingleAttribute * attribute; VectorAttribute * vattribute; string value; + map vvalue; /* #******************************************************************************* @@ -42,6 +43,7 @@ void SchedulerTemplate::set_conf_default() # DEFAULT_SCHED # LIVE_RESCHEDS # HYPERVISOR_MEM +# LOG #------------------------------------------------------------------------------- */ // ONED_PORT @@ -81,7 +83,7 @@ void SchedulerTemplate::set_conf_default() conf_default.insert(make_pair(attribute->name(),attribute)); //DEFAULT_SCHED - map vvalue; + vvalue.clear(); vvalue.insert(make_pair("POLICY","1")); vattribute = new VectorAttribute("DEFAULT_SCHED",vvalue); @@ -92,6 +94,14 @@ void SchedulerTemplate::set_conf_default() attribute = new SingleAttribute("HYPERVISOR_MEM",value); conf_default.insert(make_pair(attribute->name(),attribute)); + + //LOG CONFIGURATION + vvalue.clear(); + vvalue.insert(make_pair("SYSTEM","file")); + vvalue.insert(make_pair("DEBUG_LEVEL","3")); + + vattribute = new VectorAttribute("LOG",vvalue); + conf_default.insert(make_pair(vattribute->name(),vattribute)); } /* -------------------------------------------------------------------------- */ diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 835e1d2bb4..4adf0b1b44 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -191,10 +191,31 @@ int VirtualMachine::select(SqlDB * db) //-------------------------------------------------------------------------- try { - Log::MessageType clevel; + Log::MessageType clevel; + NebulaLog::LogType log_system; - clevel = nd.get_debug_level(); - _log = new FileLog(nd.get_vm_log_filename(oid), clevel); + log_system = nd.get_log_system(); + clevel = nd.get_debug_level(); + + switch(log_system) + { + case NebulaLog::FILE_TS: + case NebulaLog::FILE: + _log = new FileLog(nd.get_vm_log_filename(oid), clevel); + break; + + case NebulaLog::SYSLOG: + _log = new SysLogResource(oid, obj_type, clevel); + break; + + case NebulaLog::CERR: + _log = new CerrLog(clevel); + break; + + default: + throw runtime_error("Unknown log system."); + break; + } } catch(exception &e) {