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}
libcompat_la_SOURCES = \
compatcomponent.cpp \
compatcomponent.h \
+ compatlog.cpp \
+ compatlog.h \
compat-type.cpp
libcompat_la_CPPFLAGS = \
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"
+}
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.
*
{
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);
}
private:
Attribute<String> m_StatusPath;
Attribute<String> m_ObjectsPath;
- Attribute<String> m_LogPath;
Attribute<String> m_CommandPath;
#ifndef _WIN32
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);
--- /dev/null
+/******************************************************************************
+ * 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(¶ms))
+ 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();
+}
--- /dev/null
+/******************************************************************************
+ * 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 */
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;
}
}
-StateType Host::GetStateType(void) const
-{
- Service::Ptr hc = GetHostCheckService();
-
- if (!hc)
- return StateTypeHard;
-
- return hc->GetStateType();
-}
-
HostState Host::GetLastState(void) const
{
ASSERT(!OwnsLock());
return hc->GetLastStateType();
}
-String Host::HostStateToString(HostState state)
+String Host::StateToString(HostState state)
{
switch (state) {
case HostUp:
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());
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.
*
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);
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.
*/
{
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;
* 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)
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;
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));
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());
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);
namespace icinga
{
-/**
- * The state of a service.
- *
- * @ingroup icinga
- */
-enum ServiceState
-{
- StateOK,
- StateWarning,
- StateCritical,
- StateUnknown,
- StateUncheckable,
-};
-
/**
* The acknowledgement type of a service.
*
void SetLastHardStateChange(double ts);
double GetLastHardStateChange(void) const;
+ void SetLastReachable(bool reachable);
+ bool GetLastReachable(void) const;
+
bool GetEnableActiveChecks(void) const;
void SetEnableActiveChecks(bool enabled);
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;