Implement the CompatLog type.

This commit is contained in:
Gunnar Beutner 2013-03-19 13:04:30 +01:00
parent 7e9a5e647d
commit a21cf21d52
12 changed files with 435 additions and 61 deletions

View File

@ -26,7 +26,7 @@ icinga2doc_DATA = \
NEWS
install-data-local:
$(MKDIR_P) ${localstatedir}/log/${PACKAGE}
$(MKDIR_P) ${localstatedir}/log/${PACKAGE}/compat/archives
$(MKDIR_P) ${localstatedir}/cache/${PACKAGE}
$(MKDIR_P) ${localstatedir}/lib/${PACKAGE}
$(MKDIR_P) ${localstatedir}/run/${PACKAGE}

View File

@ -12,6 +12,8 @@ EXTRA_DIST = \
libcompat_la_SOURCES = \
compatcomponent.cpp \
compatcomponent.h \
compatlog.cpp \
compatlog.h \
compat-type.cpp
libcompat_la_CPPFLAGS = \

View File

@ -20,6 +20,10 @@
type CompatComponent {
%attribute string "status_path",
%attribute string "objects_path",
%attribute string "log_path",
%attribute string "command_path"
}
type CompatLog {
%attribute string "path_prefix",
%attribute number "rotation_interval"
}

View File

@ -89,20 +89,6 @@ String CompatComponent::GetObjectsPath(void) const
return objectsPath;
}
/**
* Retrieves the log path.
*
* @returns log path
*/
String CompatComponent::GetLogPath(void) const
{
Value logPath = m_LogPath;
if (logPath.IsEmpty())
return Application::GetLocalStateDir() + "/log/icinga2/compat";
else
return logPath;
}
/**
* Retrieves the icinga.cmd path.
*
@ -122,7 +108,6 @@ CompatComponent::CompatComponent(const Dictionary::Ptr& serializedUpdate)
{
RegisterAttribute("status_path", Attribute_Config, &m_StatusPath);
RegisterAttribute("objects_path", Attribute_Config, &m_ObjectsPath);
RegisterAttribute("log_path", Attribute_Config, &m_LogPath);
RegisterAttribute("command_path", Attribute_Config, &m_CommandPath);
}

View File

@ -50,7 +50,6 @@ public:
private:
Attribute<String> m_StatusPath;
Attribute<String> m_ObjectsPath;
Attribute<String> m_LogPath;
Attribute<String> m_CommandPath;
#ifndef _WIN32
@ -63,7 +62,6 @@ private:
String GetStatusPath(void) const;
String GetObjectsPath(void) const;
String GetLogPath(void) const;
String GetCommandPath(void) const;
void DumpDowntimes(std::ostream& fp, const Service::Ptr& owner, CompatObjectType type);

View File

@ -0,0 +1,274 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "compat/compatlog.h"
#include "icinga/checkresultmessage.h"
#include "icinga/service.h"
#include "icinga/macroprocessor.h"
#include "base/dynamictype.h"
#include "base/objectlock.h"
#include "base/logger_fwd.h"
#include "base/convert.h"
#include "base/application.h"
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/foreach.hpp>
using namespace icinga;
REGISTER_TYPE(CompatLog);
CompatLog::CompatLog(const Dictionary::Ptr& properties)
: DynamicObject(properties)
{
RegisterAttribute("log_dir", Attribute_Config, &m_LogDir);
RegisterAttribute("rotation_interval", Attribute_Config, &m_RotationInterval);
}
CompatLog::~CompatLog(void)
{
}
/**
* @threadsafety Always.
*/
void CompatLog::OnAttributeChanged(const String& name)
{
ASSERT(!OwnsLock());
if (name == "rotation_interval") {
m_RotationTimer->SetInterval(GetRotationInterval());
}
}
/**
* @threadsafety Always.
*/
void CompatLog::Start(void)
{
m_Endpoint = Endpoint::MakeEndpoint("compatlog_" + GetName(), false);
m_Endpoint->RegisterTopicHandler("checker::CheckResult",
boost::bind(&CompatLog::CheckResultRequestHandler, this, _3));
m_RotationTimer = boost::make_shared<Timer>();
m_RotationTimer->OnTimerExpired.connect(boost::bind(&CompatLog::RotationTimerHandler, this));
m_RotationTimer->SetInterval(GetRotationInterval());
m_RotationTimer->Start();
RotateFile();
}
/**
* @threadsafety Always.
*/
CompatLog::Ptr CompatLog::GetByName(const String& name)
{
DynamicObject::Ptr configObject = DynamicObject::GetObject("CompatLog", name);
return dynamic_pointer_cast<CompatLog>(configObject);
}
/**
* @threadsafety Always.
*/
String CompatLog::GetLogDir(void) const
{
if (!m_LogDir.IsEmpty())
return m_LogDir;
else
return Application::GetLocalStateDir() + "/log/icinga2/compat/";
}
/**
* @threadsafety Always.
*/
double CompatLog::GetRotationInterval(void) const
{
if (!m_RotationInterval.IsEmpty())
return m_RotationInterval;
else
return 3600;
}
/**
* @threadsafety Always.
*/
void CompatLog::CheckResultRequestHandler(const RequestMessage& request)
{
CheckResultMessage params;
if (!request.GetParams(&params))
return;
String svcname = params.GetService();
Service::Ptr service = Service::GetByName(svcname);
Host::Ptr host = service->GetHost();
if (!host)
return;
Dictionary::Ptr cr = params.GetCheckResult();
if (!cr)
return;
Dictionary::Ptr vars_after = cr->Get("vars_after");
long state_after = vars_after->Get("state");
long stateType_after = vars_after->Get("state_type");
long attempt_after = vars_after->Get("attempt");
bool reachable_after = vars_after->Get("reachable");
bool host_reachable_after = vars_after->Get("host_reachable");
Dictionary::Ptr vars_before = cr->Get("vars_before");
if (vars_before) {
long state_before = vars_before->Get("state");
long stateType_before = vars_before->Get("state_type");
long attempt_before = vars_before->Get("attempt");
bool reachable_before = vars_before->Get("reachable");
if (state_before == state_after && stateType_before == stateType_after &&
attempt_before == attempt_after && reachable_before == reachable_after)
return; /* Nothing changed, ignore this checkresult. */
}
std::ostringstream msgbuf;
msgbuf << "SERVICE ALERT: "
<< host->GetName() << ";"
<< service->GetShortName() << ";"
<< Service::StateToString(static_cast<ServiceState>(state_after)) << ";"
<< Service::StateTypeToString(static_cast<StateType>(stateType_after)) << ";"
<< attempt_after << ";"
<< "";
WriteLine(msgbuf.str());
if (service == host->GetHostCheckService()) {
std::ostringstream msgbuf;
msgbuf << "HOST ALERT: "
<< host->GetName() << ";"
<< Host::StateToString(Host::CalculateState(static_cast<ServiceState>(state_after), host_reachable_after)) << ";"
<< Service::StateTypeToString(static_cast<StateType>(stateType_after)) << ";"
<< attempt_after << ";"
<< "";
WriteLine(msgbuf.str());
}
Flush();
}
void CompatLog::WriteLine(const String& line)
{
ASSERT(OwnsLock());
if (!m_OutputFile.good())
return;
m_OutputFile << "[" << (long)Utility::GetTime() << "] " << line << "\n";
}
void CompatLog::Flush(void)
{
ASSERT(OwnsLock());
if (!m_OutputFile.good())
return;
m_OutputFile << std::flush;
}
/**
* @threadsafety Always.
*/
void CompatLog::RotateFile(void)
{
ObjectLock olock(this);
String tempFile = GetLogDir() + "/icinga.log";
if (m_OutputFile.good()) {
m_OutputFile.close();
String finalFile = GetLogDir() + "/archives/icinga-" + Convert::ToString((long)Utility::GetTime()) + ".log";
(void) rename(tempFile.CStr(), finalFile.CStr());
}
m_OutputFile.open(tempFile.CStr());
if (!m_OutputFile.good()) {
Log(LogWarning, "icinga", "Could not open compat log file '" + tempFile + "' for writing. Log output will be lost.");
return;
}
WriteLine("LOG VERSION: 2.0");
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Host")) {
Host::Ptr host = static_pointer_cast<Host>(object);
Service::Ptr hc = host->GetHostCheckService();
if (!hc)
continue;
bool reachable = host->IsReachable();
ObjectLock olock(hc);
std::ostringstream msgbuf;
msgbuf << "HOST STATE: CURRENT;"
<< host->GetName() << ";"
<< Host::StateToString(Host::CalculateState(hc->GetState(), reachable)) << ";"
<< Service::StateTypeToString(hc->GetStateType()) << ";"
<< hc->GetCurrentCheckAttempt() << ";"
<< "";
WriteLine(msgbuf.str());
}
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = static_pointer_cast<Service>(object);
Host::Ptr host = service->GetHost();
if (!host)
continue;
std::ostringstream msgbuf;
msgbuf << "SERVICE STATE: CURRENT;"
<< host->GetName() << ";"
<< service->GetShortName() << ";"
<< Service::StateToString(service->GetState()) << ";"
<< Service::StateTypeToString(service->GetStateType()) << ";"
<< service->GetCurrentCheckAttempt() << ";"
<< "";
WriteLine(msgbuf.str());
}
Flush();
}
/**
* @threadsafety Always.
*/
void CompatLog::RotationTimerHandler(void)
{
RotateFile();
}

View File

@ -0,0 +1,74 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef COMPATLOG_H
#define COMPATLOG_H
#include "icinga/i2-icinga.h"
#include "remoting/endpoint.h"
#include "base/dynamicobject.h"
#include "base/timer.h"
#include <fstream>
namespace icinga
{
/**
* An Icinga compat log writer.
*
* @ingroup compat
*/
class I2_ICINGA_API CompatLog : public DynamicObject
{
public:
typedef shared_ptr<CompatLog> Ptr;
typedef weak_ptr<CompatLog> WeakPtr;
CompatLog(const Dictionary::Ptr& properties);
~CompatLog(void);
static CompatLog::Ptr GetByName(const String& name);
String GetLogDir(void) const;
double GetRotationInterval(void) const;
protected:
virtual void OnAttributeChanged(const String& name);
virtual void Start(void);
private:
Attribute<String> m_LogDir;
Attribute<double> m_RotationInterval;
void WriteLine(const String& line);
void Flush(void);
Endpoint::Ptr m_Endpoint;
void CheckResultRequestHandler(const RequestMessage& request);
Timer::Ptr m_RotationTimer;
void RotationTimerHandler(void);
std::ofstream m_OutputFile;
void RotateFile(void);
};
}
#endif /* COMPATLOG_H */

View File

@ -516,17 +516,12 @@ std::set<Service::Ptr> Host::GetParentServices(void) const
return parents;
}
HostState Host::GetState(void) const
HostState Host::CalculateState(ServiceState state, bool reachable)
{
if (!IsReachable())
if (!reachable)
return HostUnreachable;
Service::Ptr hc = GetHostCheckService();
if (!hc)
return HostUp;
switch (hc->GetState()) {
switch (state) {
case StateOK:
case StateWarning:
return HostUp;
@ -535,16 +530,6 @@ HostState Host::GetState(void) const
}
}
StateType Host::GetStateType(void) const
{
Service::Ptr hc = GetHostCheckService();
if (!hc)
return StateTypeHard;
return hc->GetStateType();
}
HostState Host::GetLastState(void) const
{
ASSERT(!OwnsLock());
@ -576,7 +561,7 @@ StateType Host::GetLastStateType(void) const
return hc->GetLastStateType();
}
String Host::HostStateToString(HostState state)
String Host::StateToString(HostState state)
{
switch (state) {
case HostUp:
@ -611,13 +596,16 @@ Dictionary::Ptr Host::CalculateDynamicMacros(void) const
if (hc) {
ObjectLock olock(hc);
macros->Set("HOSTSTATE", HostStateToString(GetState()));
macros->Set("HOSTSTATEID", GetState());
ServiceState state = hc->GetState();
bool reachable = IsReachable();
macros->Set("HOSTSTATE", CalculateState(state, reachable));
macros->Set("HOSTSTATEID", state);
macros->Set("HOSTSTATETYPE", Service::StateTypeToString(hc->GetStateType()));
macros->Set("HOSTATTEMPT", hc->GetCurrentCheckAttempt());
macros->Set("MAXHOSTATTEMPT", hc->GetMaxCheckAttempts());
macros->Set("LASTHOSTSTATE", HostStateToString(GetLastState()));
macros->Set("LASTHOSTSTATE", StateToString(GetLastState()));
macros->Set("LASTHOSTSTATEID", GetLastState());
macros->Set("LASTHOSTSTATETYPE", Service::StateTypeToString(GetLastStateType()));
macros->Set("LASTHOSTSTATECHANGE", (long)hc->GetLastStateChange());

View File

@ -42,6 +42,20 @@ enum HostState
HostUnreachable = 2
};
/**
* The state of a service.
*
* @ingroup icinga
*/
enum ServiceState
{
StateOK = 0,
StateWarning = 1,
StateCritical = 2,
StateUnknown = 3,
StateUncheckable = 4,
};
/**
* The state type of a host or service.
*
@ -93,13 +107,12 @@ public:
static void ValidateServiceDictionary(const ScriptTask::Ptr& task,
const std::vector<icinga::Value>& arguments);
HostState GetState(void) const;
StateType GetStateType(void) const;
static HostState CalculateState(ServiceState state, bool reachable);
HostState GetLastState(void) const;
StateType GetLastStateType(void) const;
static String HostStateToString(HostState state);
static String StateToString(HostState state);
protected:
virtual void OnRegistrationCompleted(void);

View File

@ -267,6 +267,26 @@ StateType Service::GetLastStateType(void) const
return static_cast<StateType>(ivalue);
}
/**
* @threadsafety Always.
*/
void Service::SetLastReachable(bool reachable)
{
m_LastReachable = reachable;
Touch("last_reachable");
}
/**
* @threadsafety Always.
*/
bool Service::GetLastReachable(void) const
{
if (m_LastReachable.IsEmpty())
return true;
return m_LastReachable;
}
/**
* @threadsafety Always.
*/
@ -391,11 +411,19 @@ void Service::ProcessCheckResult(const Dictionary::Ptr& cr)
{
bool reachable = IsReachable();
Host::Ptr host = GetHost();
bool host_reachable = true;
if (host)
host_reachable = host->IsReachable();
ASSERT(!OwnsLock());
ObjectLock olock(this);
Dictionary::Ptr old_cr = GetLastCheckResult();
ServiceState old_state = GetState();
StateType old_stateType = GetStateType();
long old_attempt = GetCurrentCheckAttempt();
bool hardChange = false;
bool recovery;
@ -403,8 +431,9 @@ void Service::ProcessCheckResult(const Dictionary::Ptr& cr)
* in case this was a passive check result. */
SetLastState(old_state);
SetLastStateType(old_stateType);
SetLastReachable(reachable);
long attempt = GetCurrentCheckAttempt();
long attempt;
if (cr->Get("state") == StateOK) {
if (old_state != StateOK && old_stateType == StateTypeHard)
@ -419,13 +448,15 @@ void Service::ProcessCheckResult(const Dictionary::Ptr& cr)
attempt = 1;
recovery = true;
} else {
if (attempt >= GetMaxCheckAttempts()) {
if (old_attempt >= GetMaxCheckAttempts()) {
SetStateType(StateTypeHard);
attempt = 1;
hardChange = true;
} else if (GetStateType() == StateTypeSoft || GetState() == StateOK) {
SetStateType(StateTypeSoft);
attempt++;
attempt = old_attempt + 1;
} else {
attempt = old_attempt;
}
recovery = false;
@ -482,6 +513,18 @@ void Service::ProcessCheckResult(const Dictionary::Ptr& cr)
olock.Unlock();
Dictionary::Ptr vars_after = boost::make_shared<Dictionary>();
vars_after->Set("state", GetState());
vars_after->Set("state_type", GetStateType());
vars_after->Set("attempt", GetCurrentCheckAttempt());
vars_after->Set("reachable", reachable);
vars_after->Set("host_reachable", host_reachable);
if (old_cr)
cr->Set("vars_before", old_cr->Get("vars_after"));
cr->Set("vars_after", vars_after);
/* Update macros - these are used by event handlers and notifications. */
cr->Set("macros", CalculateAllMacros(cr));
@ -619,6 +662,8 @@ void Service::BeginExecuteCheck(const boost::function<void (void)>& callback)
SetLastStateType(GetLastStateType());
}
SetLastReachable(IsReachable());
/* keep track of scheduling info in case the check type doesn't provide its own information */
Dictionary::Ptr checkInfo = boost::make_shared<Dictionary>();
checkInfo->Set("schedule_start", GetNextCheck());

View File

@ -55,6 +55,7 @@ Service::Service(const Dictionary::Ptr& serializedObject)
RegisterAttribute("state_type", Attribute_Replicated, &m_StateType);
RegisterAttribute("last_state", Attribute_Replicated, &m_LastState);
RegisterAttribute("last_state_type", Attribute_Replicated, &m_LastStateType);
RegisterAttribute("last_reachable", Attribute_Replicated, &m_LastReachable);
RegisterAttribute("last_result", Attribute_Replicated, &m_LastResult);
RegisterAttribute("last_state_change", Attribute_Replicated, &m_LastStateChange);
RegisterAttribute("last_hard_state_change", Attribute_Replicated, &m_LastHardStateChange);

View File

@ -31,20 +31,6 @@
namespace icinga
{
/**
* The state of a service.
*
* @ingroup icinga
*/
enum ServiceState
{
StateOK,
StateWarning,
StateCritical,
StateUnknown,
StateUncheckable,
};
/**
* The acknowledgement type of a service.
*
@ -158,6 +144,9 @@ public:
void SetLastHardStateChange(double ts);
double GetLastHardStateChange(void) const;
void SetLastReachable(bool reachable);
bool GetLastReachable(void) const;
bool GetEnableActiveChecks(void) const;
void SetEnableActiveChecks(bool enabled);
@ -284,6 +273,7 @@ private:
Attribute<long> m_StateType;
Attribute<long> m_LastState;
Attribute<long> m_LastStateType;
Attribute<bool> m_LastReachable;
Attribute<Dictionary::Ptr> m_LastResult;
Attribute<double> m_LastStateChange;
Attribute<double> m_LastHardStateChange;