Implemented logging to files and made logging configurable.

This commit is contained in:
Gunnar Beutner 2012-07-10 15:14:45 +02:00
parent 86ae6579ed
commit a64c99c176
18 changed files with 216 additions and 93 deletions

View File

@ -11,8 +11,6 @@ libbase_la_SOURCES = \
component.h \ component.h \
configobject.cpp \ configobject.cpp \
configobject.h \ configobject.h \
consolelogger.cpp \
consolelogger.h \
dictionary.cpp \ dictionary.cpp \
dictionary.h \ dictionary.h \
event.cpp \ event.cpp \
@ -34,6 +32,8 @@ libbase_la_SOURCES = \
ringbuffer.h \ ringbuffer.h \
socket.cpp \ socket.cpp \
socket.h \ socket.h \
streamlogger.cpp \
streamlogger.h \
sysloglogger.cpp \ sysloglogger.cpp \
sysloglogger.h \ sysloglogger.h \
tcpclient.cpp \ tcpclient.cpp \

View File

@ -396,7 +396,7 @@ int Application::Run(int argc, char **argv)
} else { } else {
try { try {
result = Main(m_Arguments); result = Main(m_Arguments);
} catch (const std::exception& ex) { } catch (const exception& ex) {
Application::m_Instance.reset(); Application::m_Instance.reset();
Logger::Write(LogCritical, "base", "---"); Logger::Write(LogCritical, "base", "---");

View File

@ -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;
}

View File

@ -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 */

View File

@ -28,7 +28,7 @@ namespace icinga
* *
* @ingroup base * @ingroup base
*/ */
class I2_BASE_API Exception : public virtual std::exception class I2_BASE_API Exception : public virtual exception
{ {
public: public:
Exception(void) Exception(void)

View File

@ -86,6 +86,7 @@
#include <vector> #include <vector>
#include <set> #include <set>
#include <iostream> #include <iostream>
#include <fstream>
#include <list> #include <list>
#include <typeinfo> #include <typeinfo>
#include <map> #include <map>
@ -103,7 +104,10 @@ using std::pair;
using std::deque; using std::deque;
using std::stringstream; using std::stringstream;
using std::ostream;
using std::ofstream;
using std::exception;
using std::runtime_error; using std::runtime_error;
using std::logic_error; using std::logic_error;
using std::invalid_argument; using std::invalid_argument;
@ -169,7 +173,7 @@ using boost::system_time;
#include "component.h" #include "component.h"
#include "threadpool.h" #include "threadpool.h"
#include "logger.h" #include "logger.h"
#include "consolelogger.h" #include "streamlogger.h"
#include "sysloglogger.h" #include "sysloglogger.h"
#endif /* I2BASE_H */ #endif /* I2BASE_H */

View File

@ -21,7 +21,7 @@
using namespace icinga; using namespace icinga;
vector<Logger::Ptr> Logger::m_Loggers; set<Logger::Ptr> Logger::m_Loggers;
/** /**
* Constructor for the logger class. * Constructor for the logger class.
@ -63,7 +63,19 @@ void Logger::RegisterLogger(const Logger::Ptr& logger)
{ {
assert(Application::IsMainThread()); 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) void Logger::ForwardLogEntry(const LogEntry& entry)
{ {
vector<Logger::Ptr>::iterator it; set<Logger::Ptr>::iterator it;
for (it = m_Loggers.begin(); it != m_Loggers.end(); it++) { for (it = m_Loggers.begin(); it != m_Loggers.end(); it++) {
Logger::Ptr logger = *it; Logger::Ptr logger = *it;

View File

@ -57,12 +57,13 @@ public:
typedef shared_ptr<Logger> Ptr; typedef shared_ptr<Logger> Ptr;
typedef weak_ptr<Logger> WeakPtr; typedef weak_ptr<Logger> WeakPtr;
Logger(LogSeverity minSeverity = LogDebug); Logger(LogSeverity minSeverity);
static void Write(LogSeverity severity, const string& facility, static void Write(LogSeverity severity, const string& facility,
const string& message); const string& message);
static void RegisterLogger(const Logger::Ptr& logger); static void RegisterLogger(const Logger::Ptr& logger);
static void UnregisterLogger(const Logger::Ptr& logger);
protected: protected:
virtual void ProcessLogEntry(const LogEntry& entry) = 0; virtual void ProcessLogEntry(const LogEntry& entry) = 0;
@ -72,7 +73,7 @@ protected:
private: private:
LogSeverity m_MinSeverity; LogSeverity m_MinSeverity;
static vector<Logger::Ptr> m_Loggers; static set<Logger::Ptr> m_Loggers;
static void ForwardLogEntry(const LogEntry& entry); static void ForwardLogEntry(const LogEntry& entry);
}; };

View File

@ -156,7 +156,7 @@ int Socket::GetLastSocketError(void)
* *
* @param ex An exception. * @param ex An exception.
*/ */
void Socket::HandleSocketError(const std::exception& ex) void Socket::HandleSocketError(const exception& ex)
{ {
if (!OnError.empty()) { if (!OnError.empty()) {
Event::Ptr ev = boost::make_shared<Event>(); Event::Ptr ev = boost::make_shared<Event>();

View File

@ -35,7 +35,7 @@ public:
~Socket(void); ~Socket(void);
boost::signal<void (const Socket::Ptr&, const std::exception&)> OnError; boost::signal<void (const Socket::Ptr&, const exception&)> OnError;
boost::signal<void (const Socket::Ptr&)> OnClosed; boost::signal<void (const Socket::Ptr&)> OnClosed;
virtual void Start(void); virtual void Start(void);
@ -55,7 +55,7 @@ protected:
int GetError(void) const; int GetError(void) const;
static int GetLastSocketError(void); static int GetLastSocketError(void);
void HandleSocketError(const std::exception& ex); void HandleSocketError(const exception& ex);
virtual bool WantsToRead(void) const; virtual bool WantsToRead(void) const;
virtual bool WantsToWrite(void) const; virtual bool WantsToWrite(void) const;

85
base/streamlogger.cpp Normal file
View File

@ -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;
}

31
base/streamlogger.h Normal file
View File

@ -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<StreamLogger> Ptr;
typedef weak_ptr<StreamLogger> 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 */

View File

@ -10,6 +10,9 @@ namespace icinga
class SyslogLogger : public Logger class SyslogLogger : public Logger
{ {
public: public:
typedef shared_ptr<SyslogLogger> Ptr;
typedef weak_ptr<SyslogLogger> WeakPtr;
SyslogLogger(LogSeverity minSeverity); SyslogLogger(LogSeverity minSeverity);
protected: protected:

View File

@ -263,7 +263,7 @@ void CIBSyncComponent::RemoteObjectCommittedHandler(const Endpoint::Ptr& sender,
m_SyncingConfig = true; m_SyncingConfig = true;
object->Commit(); object->Commit();
m_SyncingConfig = false; m_SyncingConfig = false;
} catch (const std::exception&) { } catch (const exception&) {
m_SyncingConfig = false; m_SyncingConfig = false;
throw; throw;
} }
@ -293,7 +293,7 @@ void CIBSyncComponent::RemoteObjectRemovedHandler(const RequestMessage& request)
m_SyncingConfig = true; m_SyncingConfig = true;
object->Unregister(); object->Unregister();
m_SyncingConfig = false; m_SyncingConfig = false;
} catch (const std::exception&) { } catch (const exception&) {
m_SyncingConfig = false; m_SyncingConfig = false;
throw; throw;
} }

View File

@ -518,7 +518,7 @@ void DiscoveryComponent::DiscoveryTimerHandler(void)
try { try {
if (!info->Node.empty() && !info->Service.empty()) if (!info->Node.empty() && !info->Service.empty())
endpointManager->AddConnection(info->Node, info->Service); endpointManager->AddConnection(info->Node, info->Service);
} catch (const std::exception& ex) { } catch (const exception& ex) {
stringstream msgbuf; stringstream msgbuf;
msgbuf << "Exception while trying to reconnect to endpoint '" << endpoint->GetIdentity() << "': " << ex.what();; msgbuf << "Exception while trying to reconnect to endpoint '" << endpoint->GetIdentity() << "': " << ex.what();;
Logger::Write(LogInformation, "discovery", msgbuf.str()); Logger::Write(LogInformation, "discovery", msgbuf.str());

View File

@ -36,12 +36,9 @@ using namespace icinga;
*/ */
int IcingaApplication::Main(const vector<string>& args) int IcingaApplication::Main(const vector<string>& args)
{ {
ConsoleLogger::Ptr consoleLogger = boost::make_shared<ConsoleLogger>(LogInformation); StreamLogger::Ptr consoleLogger = boost::make_shared<StreamLogger>(&std::cout, LogInformation);
Logger::RegisterLogger(consoleLogger); Logger::RegisterLogger(consoleLogger);
SyslogLogger::Ptr syslogLogger = boost::make_shared<SyslogLogger>(LogInformation);
Logger::RegisterLogger(syslogLogger);
#ifdef _WIN32 #ifdef _WIN32
Logger::Write(LogInformation, "icinga", "Icinga component loader"); Logger::Write(LogInformation, "icinga", "Icinga component loader");
#else /* _WIN32 */ #else /* _WIN32 */
@ -52,11 +49,64 @@ int IcingaApplication::Main(const vector<string>& args)
if (args.size() < 2) { if (args.size() < 2) {
stringstream msgbuf; stringstream msgbuf;
msgbuf << "Syntax: " << args[0] << " <config-file>"; msgbuf << "Syntax: " << args[0] << " [-S] [-L logfile] [-d] [--] <config-file>";
Logger::Write(LogInformation, "icinga", msgbuf.str()); Logger::Write(LogInformation, "icinga", msgbuf.str());
return EXIT_FAILURE; 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<string>::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<StreamLogger>(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<SyslogLogger>(LogInformation);
Logger::RegisterLogger(syslogLogger);
}
string componentDirectory = Utility::DirName(GetExePath()) + "/../lib/icinga2"; string componentDirectory = Utility::DirName(GetExePath()) + "/../lib/icinga2";
AddComponentSearchDir(componentDirectory); AddComponentSearchDir(componentDirectory);
@ -79,7 +129,7 @@ int IcingaApplication::Main(const vector<string>& args)
fileComponentConfig->SetType("component"); fileComponentConfig->SetType("component");
fileComponentConfig->SetName("configfile"); fileComponentConfig->SetName("configfile");
fileComponentConfig->SetLocal(true); fileComponentConfig->SetLocal(true);
fileComponentConfig->AddExpression("configFilename", OperatorSet, args[1]); fileComponentConfig->AddExpression("configFilename", OperatorSet, configFile);
fileComponentConfig->Compile()->Commit(); fileComponentConfig->Compile()->Commit();
ConfigObject::Ptr icingaConfig = ConfigObject::GetObject("application", "icinga"); ConfigObject::Ptr icingaConfig = ConfigObject::GetObject("application", "icinga");
@ -111,6 +161,12 @@ int IcingaApplication::Main(const vector<string>& args)
if (!service.empty()) if (!service.empty())
EndpointManager::GetInstance()->AddListener(service); EndpointManager::GetInstance()->AddListener(service);
if (daemonize) {
Logger::Write(LogInformation, "icinga", "Daemonizing.");
Utility::Daemonize();
Logger::UnregisterLogger(consoleLogger);
}
RunEventLoop(); RunEventLoop();
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -127,7 +127,7 @@ void JsonRpcEndpoint::ClientClosedHandler(void)
// TODO: persist events, etc., for now we just disable the endpoint // 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; stringstream message;
message << "Error occured for JSON-RPC socket: Message=" << ex.what(); message << "Error occured for JSON-RPC socket: Message=" << ex.what();

View File

@ -64,7 +64,7 @@ void JsonRpcClient::DataAvailableHandler(void)
try { try {
message = MessagePart(jsonString); message = MessagePart(jsonString);
OnNewMessage(GetSelf(), message); 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())); Logger::Write(LogCritical, "jsonrpc", "Exception while processing message from JSON-RPC client: " + string(ex.what()));
} }
} }