Implement IcingaStatusWriter object dumping local and feature stats.

Refactored the cluster listener health check too.

Refs #5622
Refs #5444
This commit is contained in:
Michael Friedrich 2014-02-17 18:51:16 +01:00
parent 84be5e3413
commit d3cdbb5156
11 changed files with 276 additions and 106 deletions

View File

@ -38,5 +38,4 @@ install(TARGETS cluster RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DES
#install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/cluster\")")
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/cluster/config\")")
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/icinga2/cluster/log\")")
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/icinga2/cluster\")")

View File

@ -34,10 +34,7 @@ type ClusterListener {
%attribute array "peers" {
%attribute name(Endpoint) "*"
},
%attribute string "status_path",
%attribute number "status_update_interval"
}
}
type Endpoint {

View File

@ -44,6 +44,10 @@ Value ClusterListener::StatsFunc(Dictionary::Ptr& status, Dictionary::Ptr& perfd
{
status->Set("clusterlistener_", 1);
BOOST_FOREACH(const ClusterListener::Ptr& cluster_listener, DynamicType::GetObjects<ClusterListener>()) {
status->Set("clusterlistener_" + cluster_listener->GetName(), cluster_listener->GetClusterStatus());
}
return 0;
}
@ -130,12 +134,6 @@ void ClusterListener::Start(void)
}
}
}
m_StatusTimer = make_shared<Timer>();
m_StatusTimer->SetInterval(GetStatusUpdateInterval());
m_StatusTimer->OnTimerExpired.connect(boost::bind(&ClusterListener::StatusTimerHandler, this));
m_StatusTimer->Start();
m_StatusTimer->Reschedule(0);
}
/**
@ -1586,36 +1584,6 @@ bool ClusterListener::SupportsFeature(const String& name)
return !type->GetObjects().empty();
}
void ClusterListener::StatusTimerHandler(void)
{
Log(LogInformation, "cluster", "Writing cluster.json file");
String statuspath = GetStatusPath();
String statuspathtmp = statuspath + ".tmp"; /* XXX make this a global definition */
std::ofstream statusfp;
statusfp.open(statuspathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
statusfp << std::fixed;
statusfp << JsonSerialize(GetClusterStatus());
statusfp.close();
#ifdef _WIN32
_unlink(statuspath.CStr());
#endif /* _WIN32 */
if (rename(statuspathtmp.CStr(), statuspath.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
<< boost::errinfo_file_name(statuspathtmp));
}
Log(LogInformation, "cluster", "Finished writing cluster.json file");
}
Dictionary::Ptr ClusterListener::GetClusterStatus(void)
{
Dictionary::Ptr bag = make_shared<Dictionary>();
@ -1646,59 +1614,6 @@ Dictionary::Ptr ClusterListener::GetClusterStatus(void)
bag->Set("conn_endpoints", connected_endpoints);
bag->Set("not_conn_endpoints", not_connected_endpoints);
/* features */
std::pair<Dictionary::Ptr, Dictionary::Ptr> stats = CIB::GetFeatureStats();
/* XXX find a more clean way */
bag->Set("feature_status", stats.first);
bag->Set("feature_perfdata", stats.second);
/* icinga stats */
double interval = Utility::GetTime() - Application::GetStartTime();
if (interval > 60)
interval = 60;
bag->Set("active_checks", CIB::GetActiveChecksStatistics(interval) / interval);
bag->Set("passive_checks", CIB::GetPassiveChecksStatistics(interval) / interval);
bag->Set("active_checks_1min", CIB::GetActiveChecksStatistics(60));
bag->Set("passive_checks_1min", CIB::GetPassiveChecksStatistics(60));
bag->Set("active_checks_5min", CIB::GetActiveChecksStatistics(60 * 5));
bag->Set("passive_checks_5min", CIB::GetPassiveChecksStatistics(60 * 5));
bag->Set("active_checks_15min", CIB::GetActiveChecksStatistics(60 * 15));
bag->Set("passive_checks_15min", CIB::GetPassiveChecksStatistics(60 * 15));
ServiceCheckStatistics scs = CIB::CalculateServiceCheckStats();
bag->Set("min_latency", scs.min_latency);
bag->Set("max_latency", scs.max_latency);
bag->Set("avg_latency", scs.avg_latency);
bag->Set("min_execution_time", scs.min_latency);
bag->Set("max_execution_time", scs.max_latency);
bag->Set("avg_execution_time", scs.avg_execution_time);
ServiceStatistics ss = CIB::CalculateServiceStats();
bag->Set("num_services_ok", ss.services_ok);
bag->Set("num_services_warning", ss.services_warning);
bag->Set("num_services_critical", ss.services_critical);
bag->Set("num_services_unknown", ss.services_unknown);
bag->Set("num_services_pending", ss.services_pending);
bag->Set("num_services_unreachable", ss.services_unreachable);
bag->Set("num_services_flapping", ss.services_flapping);
bag->Set("num_services_in_downtime", ss.services_in_downtime);
bag->Set("num_services_acknowledged", ss.services_acknowledged);
HostStatistics hs = CIB::CalculateHostStats();
bag->Set("num_hosts_up", hs.hosts_up);
bag->Set("num_hosts_down", hs.hosts_down);
bag->Set("num_hosts_unreachable", hs.hosts_unreachable);
bag->Set("num_hosts_flapping", hs.hosts_flapping);
bag->Set("num_hosts_in_downtime", hs.hosts_in_downtime);
bag->Set("num_hosts_acknowledged", hs.hosts_acknowledged);
return bag;
}

View File

@ -65,9 +65,6 @@ private:
Timer::Ptr m_ClusterTimer;
void ClusterTimerHandler(void);
Timer::Ptr m_StatusTimer;
void StatusTimerHandler(void);
std::set<TcpSocket::Ptr> m_Servers;
void AddListener(const String& service);

View File

@ -15,12 +15,6 @@ class ClusterListener : DynamicObject
[config] Array::Ptr peers;
[state] double log_message_timestamp;
String identity;
[config] String status_path {
default {{{ return Application::GetLocalStateDir() + "/cache/icinga2/cluster/cluster.json"; }}}
};
[config] double status_update_interval {
default {{{ return 15; }}}
};
};
}

View File

@ -829,6 +829,28 @@ Example:
object NotificationComponent "notification" { }
### <a id="objecttype-icingastatuswriter"></a> IcingaStatusWriter
The IcingaStatusWriter feature periodically dumps the current status
and performance data from Icinga 2 and all registered features into
a defined JSON file.
Example:
library "icinga"
object IcingaStatusWriter "status" {
status_path = (IcingaLocalStateDir + "/cache/icinga2/status.json),
update_interval = 15s
}
Attributes:
Name |Description
--------------------------|--------------------------
status\_path |**Optional.** Path to cluster status file. Defaults to IcingaLocalStateDir + "/cache/icinga2/status.json"
update\_interval |**Optional.** The interval in which the status files are updated. Defaults to 15 seconds.
### <a id="objecttype-clusterlistener"></a> ClusterListener
ClusterListener objects are used to specify remote cluster
@ -860,8 +882,6 @@ Attributes:
bind\_host |**Optional.** The IP address the cluster listener should be bound to.
bind\_port |**Optional.** The port the cluster listener should be bound to.
peers |**Optional.** A list of
status\_path |**Optional.** Path to cluster status file. Defaults to IcingaLocalStateDir + "/cache/icinga2/cluster/cluster.json"
status\_update\_interval |**Optional.** The interval in which the status files are updated. Defaults to 15 seconds.
### <a id="objecttype-endpoint"></a> Endpoint

View File

@ -25,6 +25,7 @@ mkclass_target(eventcommand.ti eventcommand.th)
mkclass_target(hostgroup.ti hostgroup.th)
mkclass_target(host.ti host.th)
mkclass_target(icingaapplication.ti icingaapplication.th)
mkclass_target(icingastatuswriter.ti icingastatuswriter.th)
mkclass_target(notificationcommand.ti notificationcommand.th)
mkclass_target(notification.ti notification.th)
mkclass_target(perfdatavalue.ti perfdatavalue.th)
@ -42,7 +43,8 @@ add_library(icinga SHARED
cib.cpp command.cpp command.th comment.cpp comment.th compatutility.cpp
domain.cpp domain.th downtime.cpp downtime.th eventcommand.cpp eventcommand.th
externalcommandprocessor.cpp host.cpp host.th hostgroup.cpp hostgroup.th
icingaapplication.cpp icingaapplication.th legacytimeperiod.cpp
icingaapplication.cpp icingaapplication.th icingastatuswriter.cpp
icingastatuswriter.th legacytimeperiod.cpp
macroprocessor.cpp macroresolver.cpp notificationcommand.cpp notificationcommand.th
notification.cpp notification.th perfdatavalue.cpp perfdatavalue.th
pluginutility.cpp scheduleddowntime.cpp scheduleddowntime.th service-check.cpp

View File

@ -57,6 +57,11 @@ type HostGroup {
type IcingaApplication {
}
type IcingaStatusWriter {
%attribute string "status_path",
%attribute number "update_interval"
}
type Service {
%require "host",
%attribute name(Host) "host",

View File

@ -0,0 +1,166 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-present 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 "icinga/icingastatuswriter.h"
#include "icinga/icingaapplication.h"
#include "icinga/cib.h"
#include "icinga/hostgroup.h"
#include "icinga/servicegroup.h"
#include "icinga/checkcommand.h"
#include "icinga/eventcommand.h"
#include "icinga/timeperiod.h"
#include "icinga/notificationcommand.h"
#include "icinga/compatutility.h"
#include "base/dynamictype.h"
#include "base/objectlock.h"
#include "base/convert.h"
#include "base/logger_fwd.h"
#include "base/exception.h"
#include "base/application.h"
#include "base/context.h"
#include "base/statsfunction.h"
#include <boost/foreach.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <fstream>
using namespace icinga;
REGISTER_TYPE(IcingaStatusWriter);
REGISTER_STATSFUNCTION(IcingaStatusWriterStats, &IcingaStatusWriter::StatsFunc);
Value IcingaStatusWriter::StatsFunc(Dictionary::Ptr& status, Dictionary::Ptr& perfdata)
{
/* FIXME */
status->Set("icingastatuswriter_", 1);
return 0;
}
/**
* Hint: The reason why we're using "\n" rather than std::endl is because
* std::endl also _flushes_ the output stream which severely degrades
* performance (see http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt11ch25s02.html).
*/
/**
* Starts the component.
*/
void IcingaStatusWriter::Start(void)
{
DynamicObject::Start();
m_StatusTimer = make_shared<Timer>();
m_StatusTimer->SetInterval(GetUpdateInterval());
m_StatusTimer->OnTimerExpired.connect(boost::bind(&IcingaStatusWriter::StatusTimerHandler, this));
m_StatusTimer->Start();
m_StatusTimer->Reschedule(0);
}
Dictionary::Ptr IcingaStatusWriter::GetStatusData(void)
{
Dictionary::Ptr bag = make_shared<Dictionary>();
/* features */
std::pair<Dictionary::Ptr, Dictionary::Ptr> stats = CIB::GetFeatureStats();
bag->Set("feature_status", stats.first);
bag->Set("feature_perfdata", stats.second);
/* icinga stats */
double interval = Utility::GetTime() - Application::GetStartTime();
if (interval > 60)
interval = 60;
bag->Set("active_checks", CIB::GetActiveChecksStatistics(interval) / interval);
bag->Set("passive_checks", CIB::GetPassiveChecksStatistics(interval) / interval);
bag->Set("active_checks_1min", CIB::GetActiveChecksStatistics(60));
bag->Set("passive_checks_1min", CIB::GetPassiveChecksStatistics(60));
bag->Set("active_checks_5min", CIB::GetActiveChecksStatistics(60 * 5));
bag->Set("passive_checks_5min", CIB::GetPassiveChecksStatistics(60 * 5));
bag->Set("active_checks_15min", CIB::GetActiveChecksStatistics(60 * 15));
bag->Set("passive_checks_15min", CIB::GetPassiveChecksStatistics(60 * 15));
ServiceCheckStatistics scs = CIB::CalculateServiceCheckStats();
bag->Set("min_latency", scs.min_latency);
bag->Set("max_latency", scs.max_latency);
bag->Set("avg_latency", scs.avg_latency);
bag->Set("min_execution_time", scs.min_latency);
bag->Set("max_execution_time", scs.max_latency);
bag->Set("avg_execution_time", scs.avg_execution_time);
ServiceStatistics ss = CIB::CalculateServiceStats();
bag->Set("num_services_ok", ss.services_ok);
bag->Set("num_services_warning", ss.services_warning);
bag->Set("num_services_critical", ss.services_critical);
bag->Set("num_services_unknown", ss.services_unknown);
bag->Set("num_services_pending", ss.services_pending);
bag->Set("num_services_unreachable", ss.services_unreachable);
bag->Set("num_services_flapping", ss.services_flapping);
bag->Set("num_services_in_downtime", ss.services_in_downtime);
bag->Set("num_services_acknowledged", ss.services_acknowledged);
HostStatistics hs = CIB::CalculateHostStats();
bag->Set("num_hosts_up", hs.hosts_up);
bag->Set("num_hosts_down", hs.hosts_down);
bag->Set("num_hosts_unreachable", hs.hosts_unreachable);
bag->Set("num_hosts_flapping", hs.hosts_flapping);
bag->Set("num_hosts_in_downtime", hs.hosts_in_downtime);
bag->Set("num_hosts_acknowledged", hs.hosts_acknowledged);
return bag;
}
void IcingaStatusWriter::StatusTimerHandler(void)
{
Log(LogInformation, "icinga", "Writing status.json file");
String statuspath = GetStatusPath();
String statuspathtmp = statuspath + ".tmp"; /* XXX make this a global definition */
std::ofstream statusfp;
statusfp.open(statuspathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
statusfp << std::fixed;
statusfp << JsonSerialize(GetStatusData());
statusfp.close();
#ifdef _WIN32
_unlink(statuspath.CStr());
#endif /* _WIN32 */
if (rename(statuspathtmp.CStr(), statuspath.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
<< boost::errinfo_file_name(statuspathtmp));
}
Log(LogInformation, "icinga", "Finished writing status.json file");
}

View File

@ -0,0 +1,58 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-present 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 ICINGASTATUSWRITER_H
#define ICINGASTATUSWRITER_H
#include "icinga/icingastatuswriter.th"
#include "icinga/host.h"
#include "icinga/service.h"
#include "icinga/command.h"
#include "icinga/compatutility.h"
#include "base/objectlock.h"
#include "base/timer.h"
#include "base/utility.h"
#include <boost/thread/thread.hpp>
#include <iostream>
namespace icinga
{
/**
* @ingroup compat
*/
class IcingaStatusWriter : public ObjectImpl<IcingaStatusWriter>
{
public:
DECLARE_PTR_TYPEDEFS(IcingaStatusWriter);
static Value StatsFunc(Dictionary::Ptr& status, Dictionary::Ptr& perfdata);
static Dictionary::Ptr GetStatusData(void);
protected:
virtual void Start(void);
private:
Timer::Ptr m_StatusTimer;
void StatusTimerHandler(void);
};
}
#endif /* ICINGASTATUSWRITER_H */

View File

@ -0,0 +1,17 @@
#include "base/dynamicobject.h"
#include "base/application.h"
namespace icinga
{
class IcingaStatusWriter : DynamicObject
{
[config] String status_path {
default {{{ return Application::GetLocalStateDir() + "/cache/icinga2/status.json"; }}}
};
[config] double update_interval {
default {{{ return 15; }}}
};
};
}