diff --git a/base/Makefile.am b/base/Makefile.am index d93337638..56580af66 100644 --- a/base/Makefile.am +++ b/base/Makefile.am @@ -11,8 +11,6 @@ libbase_la_SOURCES = \ component.h \ configobject.cpp \ configobject.h \ - consolelogger.cpp \ - consolelogger.h \ dictionary.cpp \ dictionary.h \ event.cpp \ @@ -34,6 +32,8 @@ libbase_la_SOURCES = \ ringbuffer.h \ socket.cpp \ socket.h \ + streamlogger.cpp \ + streamlogger.h \ sysloglogger.cpp \ sysloglogger.h \ tcpclient.cpp \ diff --git a/base/application.cpp b/base/application.cpp index 7d2d4c636..c373b0c25 100644 --- a/base/application.cpp +++ b/base/application.cpp @@ -396,7 +396,7 @@ int Application::Run(int argc, char **argv) } else { try { result = Main(m_Arguments); - } catch (const std::exception& ex) { + } catch (const exception& ex) { Application::m_Instance.reset(); Logger::Write(LogCritical, "base", "---"); diff --git a/base/consolelogger.cpp b/base/consolelogger.cpp deleted file mode 100644 index bd89b3a85..000000000 --- a/base/consolelogger.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "i2-base.h" - -using namespace icinga; - -/** - * Constructor for the ConsoleLogger class. - * - * @param minSeverity Minimum severity for log messages. - */ -ConsoleLogger::ConsoleLogger(LogSeverity minSeverity) - : Logger(minSeverity) -{ } - -/** - * Processes a log entry and outputs it to standard out. - * - * @param entry The log entry. - */ -void ConsoleLogger::ProcessLogEntry(const LogEntry& entry) -{ - char timestamp[100]; - - string severityStr; - switch (entry.Severity) { - case LogDebug: - severityStr = "debug"; - break; - case LogInformation: - severityStr = "info"; - break; - case LogWarning: - severityStr = "warning"; - break; - case LogCritical: - severityStr = "critical"; - break; - default: - assert(!"Invalid severity specified."); - } - - tm tmnow = *localtime(&entry.Timestamp); - - strftime(timestamp, sizeof(timestamp), "%Y/%m/%d %H:%M:%S", &tmnow); - - std::cout << "[" << timestamp << "] " - << severityStr << "/" << entry.Facility << ": " - << entry.Message << std::endl; -} diff --git a/base/consolelogger.h b/base/consolelogger.h deleted file mode 100644 index 22b5e06ae..000000000 --- a/base/consolelogger.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CONSOLELOGGER_H -#define CONSOLELOGGER_H - -namespace icinga -{ - -/** - * A logger that logs to stdout. - */ -class ConsoleLogger : public Logger -{ -public: - ConsoleLogger(LogSeverity minSeverity); - -protected: - virtual void ProcessLogEntry(const LogEntry& entry); -}; - -} - -#endif /* CONSOLELOGGER_H */ diff --git a/base/exception.h b/base/exception.h index d614eb7cb..8d041560a 100644 --- a/base/exception.h +++ b/base/exception.h @@ -28,7 +28,7 @@ namespace icinga * * @ingroup base */ -class I2_BASE_API Exception : public virtual std::exception +class I2_BASE_API Exception : public virtual exception { public: Exception(void) diff --git a/base/i2-base.h b/base/i2-base.h index 2732a7df8..eddb501d8 100644 --- a/base/i2-base.h +++ b/base/i2-base.h @@ -86,6 +86,7 @@ #include #include #include +#include #include #include #include @@ -103,7 +104,10 @@ using std::pair; using std::deque; using std::stringstream; +using std::ostream; +using std::ofstream; +using std::exception; using std::runtime_error; using std::logic_error; using std::invalid_argument; @@ -169,7 +173,7 @@ using boost::system_time; #include "component.h" #include "threadpool.h" #include "logger.h" -#include "consolelogger.h" +#include "streamlogger.h" #include "sysloglogger.h" #endif /* I2BASE_H */ diff --git a/base/logger.cpp b/base/logger.cpp index 7d7588587..3e90f3a37 100644 --- a/base/logger.cpp +++ b/base/logger.cpp @@ -21,7 +21,7 @@ using namespace icinga; -vector Logger::m_Loggers; +set Logger::m_Loggers; /** * Constructor for the logger class. @@ -63,7 +63,19 @@ void Logger::RegisterLogger(const Logger::Ptr& logger) { assert(Application::IsMainThread()); - m_Loggers.push_back(logger); + m_Loggers.insert(logger); +} + +/** + * Unregisters a logger. + * + * @param logger The logger. + */ +void Logger::UnregisterLogger(const Logger::Ptr& logger) +{ + assert(Application::IsMainThread()); + + m_Loggers.erase(logger); } /** @@ -83,7 +95,7 @@ LogSeverity Logger::GetMinSeverity(void) const */ void Logger::ForwardLogEntry(const LogEntry& entry) { - vector::iterator it; + set::iterator it; for (it = m_Loggers.begin(); it != m_Loggers.end(); it++) { Logger::Ptr logger = *it; diff --git a/base/logger.h b/base/logger.h index f3614d6f2..2fbfe0f4c 100644 --- a/base/logger.h +++ b/base/logger.h @@ -57,12 +57,13 @@ public: typedef shared_ptr Ptr; typedef weak_ptr WeakPtr; - Logger(LogSeverity minSeverity = LogDebug); + Logger(LogSeverity minSeverity); static void Write(LogSeverity severity, const string& facility, const string& message); static void RegisterLogger(const Logger::Ptr& logger); + static void UnregisterLogger(const Logger::Ptr& logger); protected: virtual void ProcessLogEntry(const LogEntry& entry) = 0; @@ -72,7 +73,7 @@ protected: private: LogSeverity m_MinSeverity; - static vector m_Loggers; + static set m_Loggers; static void ForwardLogEntry(const LogEntry& entry); }; diff --git a/base/socket.cpp b/base/socket.cpp index bdc2561eb..32a2c45ef 100644 --- a/base/socket.cpp +++ b/base/socket.cpp @@ -156,7 +156,7 @@ int Socket::GetLastSocketError(void) * * @param ex An exception. */ -void Socket::HandleSocketError(const std::exception& ex) +void Socket::HandleSocketError(const exception& ex) { if (!OnError.empty()) { Event::Ptr ev = boost::make_shared(); diff --git a/base/socket.h b/base/socket.h index 7878a8ddb..5b437f253 100644 --- a/base/socket.h +++ b/base/socket.h @@ -35,7 +35,7 @@ public: ~Socket(void); - boost::signal OnError; + boost::signal OnError; boost::signal OnClosed; virtual void Start(void); @@ -55,7 +55,7 @@ protected: int GetError(void) const; static int GetLastSocketError(void); - void HandleSocketError(const std::exception& ex); + void HandleSocketError(const exception& ex); virtual bool WantsToRead(void) const; virtual bool WantsToWrite(void) const; diff --git a/base/streamlogger.cpp b/base/streamlogger.cpp new file mode 100644 index 000000000..b1824a4b5 --- /dev/null +++ b/base/streamlogger.cpp @@ -0,0 +1,85 @@ +#include "i2-base.h" + +using namespace icinga; + +/** + * Constructor for the StreamLogger class. + * + * @param minSeverity Minimum severity for log messages. + */ +StreamLogger::StreamLogger(LogSeverity minSeverity) + : Logger(minSeverity), m_Stream(NULL), m_OwnsStream(false) +{ } + +/** + * Constructor for the StreamLogger class. + * + * @param stream The stream. + * @param minSeverity Minimum severity for log messages. + */ +StreamLogger::StreamLogger(ostream *stream, LogSeverity minSeverity) + : Logger(minSeverity), m_Stream(stream), m_OwnsStream(false) +{ } + +/** + * Destructor for the StreamLogger class. + */ +StreamLogger::~StreamLogger(void) +{ + if (m_OwnsStream) + delete m_Stream; +} + +void StreamLogger::OpenFile(const string& filename) +{ + ofstream *stream = new ofstream(); + + try { + stream->open(filename.c_str(), ofstream::out | ofstream::trunc); + + if (!stream->good()) + throw runtime_error("Could not open logfile '" + filename + "'"); + } catch (const exception&) { + delete stream; + throw; + } + + m_Stream = stream; + m_OwnsStream = true; +} + +/** + * Processes a log entry and outputs it to a stream. + * + * @param entry The log entry. + */ +void StreamLogger::ProcessLogEntry(const LogEntry& entry) +{ + char timestamp[100]; + + string severityStr; + switch (entry.Severity) { + case LogDebug: + severityStr = "debug"; + break; + case LogInformation: + severityStr = "info"; + break; + case LogWarning: + severityStr = "warning"; + break; + case LogCritical: + severityStr = "critical"; + break; + default: + assert(!"Invalid severity specified."); + } + + tm tmnow = *localtime(&entry.Timestamp); + + strftime(timestamp, sizeof(timestamp), "%Y/%m/%d %H:%M:%S", &tmnow); + + *m_Stream << "[" << timestamp << "] " + << severityStr << "/" << entry.Facility << ": " + << entry.Message << std::endl; +} diff --git a/base/streamlogger.h b/base/streamlogger.h new file mode 100644 index 000000000..8da1a6bca --- /dev/null +++ b/base/streamlogger.h @@ -0,0 +1,31 @@ +#ifndef STREAMLOGGER_H +#define STREAMLOGGER_H + +namespace icinga +{ + +/** + * A logger that logs to stdout. + */ +class StreamLogger : public Logger +{ +public: + typedef shared_ptr Ptr; + typedef weak_ptr WeakPtr; + + StreamLogger(LogSeverity minSeverity); + StreamLogger(std::ostream *stream, LogSeverity minSeverity); + ~StreamLogger(void); + + void OpenFile(const string& filename); +protected: + virtual void ProcessLogEntry(const LogEntry& entry); + +private: + ostream *m_Stream; + bool m_OwnsStream; +}; + +} + +#endif /* STREAMLOGGER_H */ diff --git a/base/sysloglogger.h b/base/sysloglogger.h index f7676e36f..0c9b64821 100644 --- a/base/sysloglogger.h +++ b/base/sysloglogger.h @@ -10,6 +10,9 @@ namespace icinga class SyslogLogger : public Logger { public: + typedef shared_ptr Ptr; + typedef weak_ptr WeakPtr; + SyslogLogger(LogSeverity minSeverity); protected: diff --git a/components/cibsync/cibsynccomponent.cpp b/components/cibsync/cibsynccomponent.cpp index a962fec15..7c0d27c47 100644 --- a/components/cibsync/cibsynccomponent.cpp +++ b/components/cibsync/cibsynccomponent.cpp @@ -263,7 +263,7 @@ void CIBSyncComponent::RemoteObjectCommittedHandler(const Endpoint::Ptr& sender, m_SyncingConfig = true; object->Commit(); m_SyncingConfig = false; - } catch (const std::exception&) { + } catch (const exception&) { m_SyncingConfig = false; throw; } @@ -293,7 +293,7 @@ void CIBSyncComponent::RemoteObjectRemovedHandler(const RequestMessage& request) m_SyncingConfig = true; object->Unregister(); m_SyncingConfig = false; - } catch (const std::exception&) { + } catch (const exception&) { m_SyncingConfig = false; throw; } diff --git a/components/discovery/discoverycomponent.cpp b/components/discovery/discoverycomponent.cpp index be68e2b91..f240d28bc 100644 --- a/components/discovery/discoverycomponent.cpp +++ b/components/discovery/discoverycomponent.cpp @@ -518,7 +518,7 @@ void DiscoveryComponent::DiscoveryTimerHandler(void) try { if (!info->Node.empty() && !info->Service.empty()) endpointManager->AddConnection(info->Node, info->Service); - } catch (const std::exception& ex) { + } catch (const exception& ex) { stringstream msgbuf; msgbuf << "Exception while trying to reconnect to endpoint '" << endpoint->GetIdentity() << "': " << ex.what();; Logger::Write(LogInformation, "discovery", msgbuf.str()); diff --git a/icinga/icingaapplication.cpp b/icinga/icingaapplication.cpp index 248cdeae4..7bc829b85 100644 --- a/icinga/icingaapplication.cpp +++ b/icinga/icingaapplication.cpp @@ -36,12 +36,9 @@ using namespace icinga; */ int IcingaApplication::Main(const vector& args) { - ConsoleLogger::Ptr consoleLogger = boost::make_shared(LogInformation); + StreamLogger::Ptr consoleLogger = boost::make_shared(&std::cout, LogInformation); Logger::RegisterLogger(consoleLogger); - SyslogLogger::Ptr syslogLogger = boost::make_shared(LogInformation); - Logger::RegisterLogger(syslogLogger); - #ifdef _WIN32 Logger::Write(LogInformation, "icinga", "Icinga component loader"); #else /* _WIN32 */ @@ -52,11 +49,64 @@ int IcingaApplication::Main(const vector& args) if (args.size() < 2) { stringstream msgbuf; - msgbuf << "Syntax: " << args[0] << " "; + msgbuf << "Syntax: " << args[0] << " [-S] [-L logfile] [-d] [--] "; Logger::Write(LogInformation, "icinga", msgbuf.str()); return EXIT_FAILURE; } + bool enableSyslog = false; + bool daemonize = false; + bool parseOpts = true; + string configFile; + + /* TODO: clean up this mess; for now it will just have to do */ + vector::const_iterator it; + for (it = args.begin() + 1 ; it != args.end(); it++) { + string arg = *it; + + /* ignore empty arguments */ + if (arg.empty()) + continue; + + if (arg == "--") { + parseOpts = false; + continue; + } + + if (parseOpts && arg[0] == '-') { + if (arg == "-S") { + enableSyslog = true; + continue; + } else if (arg == "-L") { + if (it + 1 == args.end()) + throw invalid_argument("Option -L requires a parameter"); + + StreamLogger::Ptr fileLogger = boost::make_shared(LogInformation); + fileLogger->OpenFile(*(it + 1)); + Logger::RegisterLogger(fileLogger); + + it++; + + continue; + } else { + throw invalid_argument("Unknown option: " + arg); + } + } + + configFile = arg; + + if (it + 1 != args.end()) + throw invalid_argument("Trailing command line arguments after config filename."); + } + + if (configFile.empty()) + throw invalid_argument("No config file was specified on the command line."); + + if (enableSyslog) { + SyslogLogger::Ptr syslogLogger = boost::make_shared(LogInformation); + Logger::RegisterLogger(syslogLogger); + } + string componentDirectory = Utility::DirName(GetExePath()) + "/../lib/icinga2"; AddComponentSearchDir(componentDirectory); @@ -79,7 +129,7 @@ int IcingaApplication::Main(const vector& args) fileComponentConfig->SetType("component"); fileComponentConfig->SetName("configfile"); fileComponentConfig->SetLocal(true); - fileComponentConfig->AddExpression("configFilename", OperatorSet, args[1]); + fileComponentConfig->AddExpression("configFilename", OperatorSet, configFile); fileComponentConfig->Compile()->Commit(); ConfigObject::Ptr icingaConfig = ConfigObject::GetObject("application", "icinga"); @@ -111,6 +161,12 @@ int IcingaApplication::Main(const vector& args) if (!service.empty()) EndpointManager::GetInstance()->AddListener(service); + if (daemonize) { + Logger::Write(LogInformation, "icinga", "Daemonizing."); + Utility::Daemonize(); + Logger::UnregisterLogger(consoleLogger); + } + RunEventLoop(); return EXIT_SUCCESS; diff --git a/icinga/jsonrpcendpoint.cpp b/icinga/jsonrpcendpoint.cpp index 687ef863c..a1acc3c7b 100644 --- a/icinga/jsonrpcendpoint.cpp +++ b/icinga/jsonrpcendpoint.cpp @@ -127,7 +127,7 @@ void JsonRpcEndpoint::ClientClosedHandler(void) // TODO: persist events, etc., for now we just disable the endpoint } -void JsonRpcEndpoint::ClientErrorHandler(const std::exception& ex) +void JsonRpcEndpoint::ClientErrorHandler(const exception& ex) { stringstream message; message << "Error occured for JSON-RPC socket: Message=" << ex.what(); diff --git a/jsonrpc/jsonrpcclient.cpp b/jsonrpc/jsonrpcclient.cpp index 2d88ed336..e0bd2602c 100644 --- a/jsonrpc/jsonrpcclient.cpp +++ b/jsonrpc/jsonrpcclient.cpp @@ -64,7 +64,7 @@ void JsonRpcClient::DataAvailableHandler(void) try { message = MessagePart(jsonString); OnNewMessage(GetSelf(), message); - } catch (const std::exception& ex) { + } catch (const exception& ex) { Logger::Write(LogCritical, "jsonrpc", "Exception while processing message from JSON-RPC client: " + string(ex.what())); } }