Livestatus: Add log table.

refs #4433
This commit is contained in:
Michael Friedrich 2013-10-29 13:44:43 +01:00
parent f62846adcf
commit 75b69411b9
23 changed files with 1645 additions and 239 deletions

View File

@ -53,7 +53,7 @@ void CompatLogger::Start(void)
DynamicObject::Start();
Service::OnNewCheckResult.connect(bind(&CompatLogger::CheckResultHandler, this, _1, _2));
Service::OnNotificationSentToUser.connect(bind(&CompatLogger::NotificationSentHandler, this, _1, _2, _3, _4, _5, _6));
Service::OnNotificationSentToUser.connect(bind(&CompatLogger::NotificationSentHandler, this, _1, _2, _3, _4, _5, _6, _7));
Service::OnFlappingChanged.connect(bind(&CompatLogger::FlappingHandler, this, _1, _2));
Service::OnDowntimeTriggered.connect(boost::bind(&CompatLogger::TriggerDowntimeHandler, this, _1, _2));
Service::OnDowntimeRemoved.connect(boost::bind(&CompatLogger::RemoveDowntimeHandler, this, _1, _2));
@ -256,24 +256,18 @@ void CompatLogger::RemoveDowntimeHandler(const Service::Ptr& service, const Dict
*/
void CompatLogger::NotificationSentHandler(const Service::Ptr& service, const User::Ptr& user,
NotificationType const& notification_type, Dictionary::Ptr const& cr,
const String& author, const String& comment_text)
const String& author, const String& comment_text, const String& command_name)
{
Host::Ptr host = service->GetHost();
if (!host)
return;
CheckCommand::Ptr commandObj = service->GetCheckCommand();
String check_command = "";
if (commandObj)
check_command = commandObj->GetName();
String notification_type_str = Notification::NotificationTypeToString(notification_type);
String author_comment = "";
if (notification_type == NotificationCustom || notification_type == NotificationAcknowledgement) {
author_comment = ";" + author + ";" + comment_text;
author_comment = author + ";" + comment_text;
}
if (!cr)
@ -296,8 +290,9 @@ void CompatLogger::NotificationSentHandler(const Service::Ptr& service, const Us
<< service->GetShortName() << ";"
<< notification_type_str << " "
<< "(" << Service::StateToString(service->GetState()) << ");"
<< check_command << ";"
<< output << author_comment
<< command_name << ";"
<< output << ";"
<< author_comment
<< "";
{
@ -312,8 +307,9 @@ void CompatLogger::NotificationSentHandler(const Service::Ptr& service, const Us
<< host->GetName() << ";"
<< notification_type_str << " "
<< "(" << Service::StateToString(service->GetState()) << ");"
<< check_command << ";"
<< output << author_comment
<< command_name << ";"
<< output << ";"
<< author_comment
<< "";
{
@ -468,12 +464,12 @@ void CompatLogger::ReopenFile(bool rotate)
ObjectLock olock(hc);
std::ostringstream msgbuf;
msgbuf << "HOST STATE: CURRENT;"
msgbuf << "CURRENT HOST STATE: "
<< host->GetName() << ";"
<< Host::StateToString(Host::CalculateState(hc->GetState(), reachable)) << ";"
<< Service::StateTypeToString(hc->GetStateType()) << ";"
<< hc->GetCheckAttempt() << ";"
<< "";
<< hc->GetLastCheckOutput() << "";
WriteLine(msgbuf.str());
}
@ -485,13 +481,13 @@ void CompatLogger::ReopenFile(bool rotate)
continue;
std::ostringstream msgbuf;
msgbuf << "SERVICE STATE: CURRENT;"
msgbuf << "CURRENT SERVICE STATE: "
<< host->GetName() << ";"
<< service->GetShortName() << ";"
<< Service::StateToString(service->GetState()) << ";"
<< Service::StateTypeToString(service->GetStateType()) << ";"
<< service->GetCheckAttempt() << ";"
<< "";
<< service->GetLastCheckOutput() << "";
WriteLine(msgbuf.str());
}

View File

@ -54,7 +54,7 @@ private:
void CheckResultHandler(const Service::Ptr& service, const Dictionary::Ptr& cr);
void DowntimeHandler(const Service::Ptr& service, DowntimeState downtime_state);
void NotificationSentHandler(const Service::Ptr& service, const User::Ptr& user, NotificationType const& notification_type, Dictionary::Ptr const& cr, const String& author, const String& comment_text);
void NotificationSentHandler(const Service::Ptr& service, const User::Ptr& user, NotificationType const& notification_type, Dictionary::Ptr const& cr, const String& author, const String& comment_text, const String& command_name);
void FlappingHandler(const Service::Ptr& service, FlappingState flapping_state);
void TriggerDowntimeHandler(const Service::Ptr& service, const Dictionary::Ptr& downtime);
void RemoveDowntimeHandler(const Service::Ptr& service, const Dictionary::Ptr& downtime);

View File

@ -66,6 +66,9 @@ Value CommandsTable::NameAccessor(const Value& row)
String buf;
Command::Ptr command = static_cast<Command::Ptr>(row);
if (!command)
return Empty;
if (command->GetType() == DynamicType::GetByName("CheckCommand"))
buf += "check_";
if (command->GetType() == DynamicType::GetByName("NotificationCommand"))
@ -83,6 +86,9 @@ Value CommandsTable::LineAccessor(const Value& row)
String buf;
Command::Ptr command = static_cast<Command::Ptr>(row);
if (!command)
return Empty;
Value commandLine = command->GetCommandLine();
if (commandLine.IsObjectType<Array>()) {

View File

@ -52,19 +52,34 @@ void ContactGroupsTable::FetchRows(const AddRowFunction& addRowFn)
Value ContactGroupsTable::NameAccessor(const Value& row)
{
return static_cast<UserGroup::Ptr>(row)->GetName();
UserGroup::Ptr user_group = static_cast<UserGroup::Ptr>(row);
if(!user_group)
return Empty;
return user_group->GetName();
}
Value ContactGroupsTable::AliasAccessor(const Value& row)
{
return static_cast<UserGroup::Ptr>(row)->GetName();
UserGroup::Ptr user_group = static_cast<UserGroup::Ptr>(row);
if(!user_group)
return Empty;
return user_group->GetName();
}
Value ContactGroupsTable::MembersAccessor(const Value& row)
{
UserGroup::Ptr user_group = static_cast<UserGroup::Ptr>(row);
if(!user_group)
return Empty;
Array::Ptr members = boost::make_shared<Array>();
BOOST_FOREACH(const User::Ptr& user, static_cast<UserGroup::Ptr>(row)->GetMembers()) {
BOOST_FOREACH(const User::Ptr& user, user_group->GetMembers()) {
members->Add(user->GetName());
}

View File

@ -70,17 +70,32 @@ void ContactsTable::FetchRows(const AddRowFunction& addRowFn)
Value ContactsTable::NameAccessor(const Value& row)
{
return static_cast<User::Ptr>(row)->GetName();
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
return user->GetName();
}
Value ContactsTable::AliasAccessor(const Value& row)
{
return static_cast<User::Ptr>(row)->GetDisplayName();
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
return user->GetDisplayName();
}
Value ContactsTable::EmailAccessor(const Value& row)
{
Dictionary::Ptr macros = static_cast<User::Ptr>(row)->GetMacros();
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
Dictionary::Ptr macros = user->GetMacros();
if (!macros)
return Empty;
@ -90,7 +105,12 @@ Value ContactsTable::EmailAccessor(const Value& row)
Value ContactsTable::PagerAccessor(const Value& row)
{
Dictionary::Ptr macros = static_cast<User::Ptr>(row)->GetMacros();
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
Dictionary::Ptr macros = user->GetMacros();
if (!macros)
return Empty;
@ -100,8 +120,13 @@ Value ContactsTable::PagerAccessor(const Value& row)
Value ContactsTable::HostNotificationPeriodAccessor(const Value& row)
{
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
/* same as service */
TimePeriod::Ptr timeperiod = static_cast<User::Ptr>(row)->GetNotificationPeriod();
TimePeriod::Ptr timeperiod = user->GetNotificationPeriod();
if (!timeperiod)
return Empty;
@ -111,7 +136,12 @@ Value ContactsTable::HostNotificationPeriodAccessor(const Value& row)
Value ContactsTable::ServiceNotificationPeriodAccessor(const Value& row)
{
TimePeriod::Ptr timeperiod = static_cast<User::Ptr>(row)->GetNotificationPeriod();
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
TimePeriod::Ptr timeperiod = user->GetNotificationPeriod();
if (!timeperiod)
return Empty;
@ -121,17 +151,32 @@ Value ContactsTable::ServiceNotificationPeriodAccessor(const Value& row)
Value ContactsTable::HostNotificationsEnabledAccessor(const Value& row)
{
return (static_cast<User::Ptr>(row)->GetEnableNotifications() ? 1 : 0);
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
return (user->GetEnableNotifications() ? 1 : 0);
}
Value ContactsTable::ServiceNotificationsEnabledAccessor(const Value& row)
{
return (static_cast<User::Ptr>(row)->GetEnableNotifications() ? 1 : 0);
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
return (user->GetEnableNotifications() ? 1 : 0);
}
Value ContactsTable::InHostNotificationPeriodAccessor(const Value& row)
{
TimePeriod::Ptr timeperiod = static_cast<User::Ptr>(row)->GetNotificationPeriod();
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
TimePeriod::Ptr timeperiod = user->GetNotificationPeriod();
if (!timeperiod)
return Empty;
@ -141,7 +186,12 @@ Value ContactsTable::InHostNotificationPeriodAccessor(const Value& row)
Value ContactsTable::InServiceNotificationPeriodAccessor(const Value& row)
{
TimePeriod::Ptr timeperiod = static_cast<User::Ptr>(row)->GetNotificationPeriod();
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
TimePeriod::Ptr timeperiod = user->GetNotificationPeriod();
if (!timeperiod)
return Empty;
@ -151,7 +201,12 @@ Value ContactsTable::InServiceNotificationPeriodAccessor(const Value& row)
Value ContactsTable::CustomVariableNamesAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<User::Ptr>(row)->GetCustom();
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
Dictionary::Ptr custom = user->GetCustom();
if (!custom)
return Empty;
@ -179,7 +234,12 @@ Value ContactsTable::CustomVariableNamesAccessor(const Value& row)
Value ContactsTable::CustomVariableValuesAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<User::Ptr>(row)->GetCustom();
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
Dictionary::Ptr custom = user->GetCustom();
if (!custom)
return Empty;
@ -207,7 +267,12 @@ Value ContactsTable::CustomVariableValuesAccessor(const Value& row)
Value ContactsTable::CustomVariablesAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<User::Ptr>(row)->GetCustom();
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
Dictionary::Ptr custom = user->GetCustom();
if (!custom)
return Empty;
@ -238,12 +303,22 @@ Value ContactsTable::CustomVariablesAccessor(const Value& row)
Value ContactsTable::ModifiedAttributesAccessor(const Value& row)
{
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
/* not supported */
return Empty;
}
Value ContactsTable::ModifiedAttributesListAccessor(const Value& row)
{
User::Ptr user = static_cast<User::Ptr>(row);
if (!user)
return Empty;
/* not supported */
return Empty;
}

File diff suppressed because it is too large Load Diff

View File

@ -28,10 +28,10 @@
#include "base/networkstream.h"
#include "base/application.h"
#include "base/scriptfunction.h"
#include "base/convert.h"
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/exception/diagnostic_information.hpp>
using namespace icinga;
using namespace livestatus;
@ -145,6 +145,7 @@ void LivestatusListener::ClientThreadProc(const Socket::Ptr& client)
}
}
void LivestatusListener::ValidateSocketType(const String& location, const Dictionary::Ptr& attrs)
{
Value socket_type = attrs->Get("socket_type");
@ -154,4 +155,3 @@ void LivestatusListener::ValidateSocketType(const String& location, const Dictio
location + ": Socket type '" + socket_type + "' is invalid.");
}
}

View File

@ -18,15 +18,103 @@
******************************************************************************/
#include "livestatus/logtable.h"
#include "livestatus/hoststable.h"
#include "livestatus/servicestable.h"
#include "livestatus/contactstable.h"
#include "livestatus/commandstable.h"
#include "icinga/icingaapplication.h"
#include "icinga/cib.h"
#include "icinga/service.h"
#include "icinga/host.h"
#include "icinga/user.h"
#include "icinga/checkcommand.h"
#include "icinga/eventcommand.h"
#include "icinga/notificationcommand.h"
#include "base/convert.h"
#include "base/utility.h"
#include "base/logger_fwd.h"
#include "base/application.h"
#include "base/objectlock.h"
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/foreach.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <fstream>
using namespace icinga;
using namespace livestatus;
LogTable::LogTable(void)
LogTable::LogTable(const unsigned long& from, const unsigned long& until)
{
Log(LogInformation, "livestatus", "Pre-selecting log file from " + Convert::ToString(from) + " until " + Convert::ToString(until));
/* store from & until for FetchRows */
m_TimeFrom = from;
m_TimeUntil = until;
/* create log file index - TODO config option */
CreateLogIndex(Application::GetLocalStateDir() + "/log/icinga2/compat");
/* m_LogFileIndex map tells which log files are involved ordered by their start timestamp */
unsigned long ts;
unsigned long line_count = 0;
BOOST_FOREACH(boost::tie(ts, boost::tuples::ignore), m_LogFileIndex) {
/* skip log files not in range (performance optimization) */
if (ts < m_TimeFrom || ts > m_TimeUntil)
continue;
String log_file = m_LogFileIndex[ts];
int lineno = 0;
std::ifstream fp;
fp.exceptions(std::ifstream::badbit);
fp.open(log_file.CStr(), std::ifstream::in);
while (fp.good()) {
std::string line;
std::getline(fp, line);
if (line.empty())
continue; /* Ignore empty lines */
/*
* [1379025342] SERVICE NOTIFICATION: contactname;hostname;servicedesc;WARNING;true;foo output
*/
unsigned long time = atoi(line.substr(1, 11).c_str());
size_t colon = line.find_first_of(':');
size_t colon_offset = colon - 13;
std::string type_str = line.substr(13, colon_offset);
std::string options_str = line.substr(colon + 1);
String type = String(type_str);
String options = String(options_str);
type.Trim();
options.Trim();
Dictionary::Ptr bag = GetLogEntryAttributes(type, options);
bag->Set("time", time);
bag->Set("lineno", lineno);
bag->Set("message", String(line)); /* complete line */
bag->Set("type", type);
bag->Set("options", options);
{
boost::mutex::scoped_lock lock(m_Mutex);
m_RowsCache[line_count] = bag;
}
line_count++;
lineno++;
}
fp.close();
}
AddColumns(this);
}
@ -49,7 +137,10 @@ void LogTable::AddColumns(Table *table, const String& prefix,
table->AddColumn(prefix + "contact_name", Column(&LogTable::ContactNameAccessor, objectAccessor));
table->AddColumn(prefix + "command_name", Column(&LogTable::CommandNameAccessor, objectAccessor));
// TODO join with hosts, services, contacts, command tables
HostsTable::AddColumns(table, "current_host_", boost::bind(&LogTable::HostAccessor, _1, objectAccessor));
ServicesTable::AddColumns(table, "current_service_", boost::bind(&LogTable::ServiceAccessor, _1, objectAccessor));
ContactsTable::AddColumns(table, "current_contact_", boost::bind(&LogTable::ContactAccessor, _1, objectAccessor));
CommandsTable::AddColumns(table, "current_command_", boost::bind(&LogTable::CommandAccessor, _1, objectAccessor));
}
String LogTable::GetName(void) const
@ -59,98 +150,374 @@ String LogTable::GetName(void) const
void LogTable::FetchRows(const AddRowFunction& addRowFn)
{
Object::Ptr obj = boost::make_shared<Object>();
unsigned long line_count;
/* Return a fake row. */
addRowFn(obj);
BOOST_FOREACH(boost::tie(line_count, boost::tuples::ignore), m_RowsCache) {
/* pass a dictionary with "line_count" as key */
addRowFn(m_RowsCache[line_count]);
}
}
Object::Ptr LogTable::HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor)
{
String host_name = static_cast<Dictionary::Ptr>(row)->Get("host_name");
if (host_name.IsEmpty())
return Object::Ptr();
return Host::GetByName(host_name);
}
Object::Ptr LogTable::ServiceAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor)
{
String host_name = static_cast<Dictionary::Ptr>(row)->Get("host_name");
String service_description = static_cast<Dictionary::Ptr>(row)->Get("service_description");
if (service_description.IsEmpty() || host_name.IsEmpty())
return Object::Ptr();
return Service::GetByNamePair(host_name, service_description);
}
Object::Ptr LogTable::ContactAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor)
{
String contact_name = static_cast<Dictionary::Ptr>(row)->Get("contact_name");
if (contact_name.IsEmpty())
return Object::Ptr();
return User::GetByName(contact_name);
}
Object::Ptr LogTable::CommandAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor)
{
String command_name = static_cast<Dictionary::Ptr>(row)->Get("command_name");
if (command_name.IsEmpty())
return Object::Ptr();
CheckCommand::Ptr check_command = CheckCommand::GetByName(command_name);
if (!check_command) {
EventCommand::Ptr event_command = EventCommand::GetByName(command_name);
if (!event_command) {
NotificationCommand::Ptr notification_command = NotificationCommand::GetByName(command_name);
if (!notification_command)
return Object::Ptr();
else
return notification_command;
} else
return event_command;
} else
return check_command;
return Object::Ptr();
}
Value LogTable::TimeAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("time");
}
Value LogTable::LinenoAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("lineno");
}
Value LogTable::ClassAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("class");
}
Value LogTable::MessageAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("message");
}
Value LogTable::TypeAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("type");
}
Value LogTable::OptionsAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("options");
}
Value LogTable::CommentAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("comment");
}
Value LogTable::PluginOutputAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("plugin_output");
}
Value LogTable::StateAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("state");
}
Value LogTable::StateTypeAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("state_type");
}
Value LogTable::AttemptAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("attempt");
}
Value LogTable::ServiceDescriptionAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("service_description");
}
Value LogTable::HostNameAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("host_name");
}
Value LogTable::ContactNameAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("contact_name");
}
Value LogTable::CommandNameAccessor(const Value& row)
{
/* not supported */
return Empty;
return static_cast<Dictionary::Ptr>(row)->Get("command_name");
}
void LogTable::CreateLogIndex(const String& path)
{
Utility::Glob(path + "/icinga.log", boost::bind(&LogTable::CreateLogIndexFileHandler, _1, boost::ref(m_LogFileIndex)));
Utility::Glob(path + "/archives/*.log", boost::bind(&LogTable::CreateLogIndexFileHandler, _1, boost::ref(m_LogFileIndex)));
}
void LogTable::CreateLogIndexFileHandler(const String& path, std::map<unsigned long, String>& index)
{
std::ifstream stream;
stream.open(path.CStr(), std::ifstream::in);
if (!stream)
BOOST_THROW_EXCEPTION(std::runtime_error("Could not open log file: " + path));
/* read the first bytes to get the timestamp: [123456789] */
char buffer[12];
stream.read(buffer, 12);
if (buffer[0] != '[' || buffer[11] != ']') {
/* this can happen for directories too, silently ignore them */
return;
}
/* extract timestamp */
buffer[11] = 0;
unsigned int ts_start = atoi(buffer+1);
stream.close();
Log(LogDebug, "livestatus", "Indexing log file: '" + path + "' with timestamp start: '" + Convert::ToString(ts_start) + "'.");
index[ts_start] = path;
}
Dictionary::Ptr LogTable::GetLogEntryAttributes(const String& type, const String& options)
{
int log_class, log_type = 0;
unsigned long state, attempt;
String host_name, service_description, contact_name, command_name, comment, plugin_output, state_type;
std::vector<String> tokens;
boost::algorithm::split(tokens, options, boost::is_any_of(";"));
/* States - TODO refactor */
if (boost::algorithm::contains(type, "INITIAL HOST STATE")) {
log_class = LogClassState;
log_type = LogTypeHostInitialState;
host_name = tokens[0];
state = Host::StateFromString(tokens[1]);
state_type = tokens[2];
attempt = atoi(tokens[3].CStr());
plugin_output = tokens[4];
}
else if (boost::algorithm::contains(type, "CURRENT HOST STATE")) {
log_class = LogClassState;
log_type = LogTypeHostCurrentState;
host_name = tokens[0];
state = Host::StateFromString(tokens[1]);
state_type = tokens[2];
attempt = atoi(tokens[3].CStr());
plugin_output = tokens[4];
}
else if (boost::algorithm::contains(type, "HOST ALERT")) {
log_class = LogClassAlert;
log_type = LogTypeHostAlert;
host_name = tokens[0];
state = Host::StateFromString(tokens[1]);
state_type = tokens[2];
attempt = atoi(tokens[3].CStr());
plugin_output = tokens[4];
}
else if (boost::algorithm::contains(type, "HOST DOWNTIME ALERT")) {
log_class = LogClassAlert;
log_type = LogTypeHostDowntimeAlert;
host_name = tokens[0];
state_type = tokens[1];
comment = tokens[2];
}
else if (boost::algorithm::contains(type, "HOST FLAPPING ALERT")) {
log_class = LogClassAlert;
log_type = LogTypeHostFlapping;
host_name = tokens[0];
state_type = tokens[1];
comment = tokens[2];
}
else if (boost::algorithm::contains(type, "INITIAL SERVICE STATE")) {
log_class = LogClassState;
log_type = LogTypeServiceInitialState;
host_name = tokens[0];
service_description = tokens[1];
state = Service::StateFromString(tokens[2]);
state_type = tokens[3];
attempt = atoi(tokens[4].CStr());
plugin_output = tokens[5];
}
else if (boost::algorithm::contains(type, "CURRENT SERVICE STATE")) {
log_class = LogClassState;
log_type = LogTypeServiceCurrentState;
host_name = tokens[0];
service_description = tokens[1];
state = Service::StateFromString(tokens[2]);
state_type = tokens[3];
attempt = atoi(tokens[4].CStr());
plugin_output = tokens[5];
}
else if (boost::algorithm::contains(type, "SERVICE ALERT")) {
log_class = LogClassAlert;
log_type = LogTypeServiceAlert;
host_name = tokens[0];
service_description = tokens[1];
state = Service::StateFromString(tokens[2]);
state_type = tokens[3];
attempt = atoi(tokens[4].CStr());
plugin_output = tokens[5];
}
else if (boost::algorithm::contains(type, "SERVICE DOWNTIME ALERT")) {
log_class = LogClassAlert;
log_type = LogTypeServiceDowntimeAlert;
host_name = tokens[0];
service_description = tokens[1];
state_type = tokens[2];
comment = tokens[3];
}
else if (boost::algorithm::contains(type, "SERVICE FLAPPING ALERT")) {
log_class = LogClassAlert;
log_type = LogTypeServiceFlapping;
host_name = tokens[0];
service_description = tokens[1];
state_type = tokens[2];
comment = tokens[3];
}
else if (boost::algorithm::contains(type, "TIMEPERIOD TRANSITION")) {
log_class = LogClassState;
log_type = LogTypeTimeperiodTransition;
host_name = tokens[0];
service_description = tokens[1];
state_type = tokens[2];
comment = tokens[3];
}
/* Notifications - TODO refactor */
else if (boost::algorithm::contains(type, "HOST NOTIFICATION")) {
log_class = LogClassNotification;
log_type = LogTypeHostNotification;
contact_name = tokens[0];
host_name = tokens[1];
state_type = tokens[2];
state = Host::StateFromString(tokens[3]);
command_name = tokens[4];
plugin_output = tokens[5];
}
else if (boost::algorithm::contains(type, "SERVICE NOTIFICATION")) {
log_class = LogClassNotification;
log_type = LogTypeHostNotification;
contact_name = tokens[0];
host_name = tokens[1];
service_description = tokens[2];
state_type = tokens[3];
state = Service::StateFromString(tokens[4]);
command_name = tokens[5];
plugin_output = tokens[6];
}
/* Passive Checks - TODO refactor */
else if (boost::algorithm::contains(type, "PASSIVE HOST CHECK")) {
log_class = LogClassPassive;
host_name = tokens[0];
state = Host::StateFromString(tokens[1]);
plugin_output = tokens[2];
}
else if (boost::algorithm::contains(type, "PASSIVE SERVICE CHECK")) {
log_class = LogClassPassive;
host_name = tokens[0];
service_description = tokens[1];
state = Service::StateFromString(tokens[2]);
plugin_output = tokens[3];
}
/* External Command - TODO refactor */
else if (boost::algorithm::contains(type, "EXTERNAL COMMAND")) {
log_class = LogClassCommand;
/* string processing not implemented in 1.x */
}
/* normal text entries */
else if (boost::algorithm::contains(type, "LOG VERSION")) {
log_class = LogClassProgram;
log_type = LogTypeVersion;
}
else if (boost::algorithm::contains(type, "logging initial states")) {
log_class = LogClassProgram;
log_type = LogTypeInitialStates;
}
else if (boost::algorithm::contains(type, "starting... (PID=")) {
log_class = LogClassProgram;
log_type = LogTypeProgramStarting;
}
/* program */
else if (boost::algorithm::contains(type, "restarting...") ||
boost::algorithm::contains(type, "shutting down...") ||
boost::algorithm::contains(type, "Bailing out") ||
boost::algorithm::contains(type, "active mode...") ||
boost::algorithm::contains(type, "standby mode...")) {
log_class = LogClassProgram;
}
Dictionary::Ptr bag = boost::make_shared<Dictionary>();
bag->Set("class", log_class); /* 0 is the default if not populated */
bag->Set("comment", comment);
bag->Set("plugin_output", plugin_output);
bag->Set("state", state);
bag->Set("state_type", state_type);
bag->Set("attempt", attempt);
bag->Set("host_name", host_name);
bag->Set("service_description", service_description);
bag->Set("contact_name", contact_name);
bag->Set("command_name", command_name);
return bag;
}

View File

@ -21,12 +21,43 @@
#define LOGTABLE_H
#include "livestatus/table.h"
#include <boost/thread/mutex.hpp>
using namespace icinga;
namespace livestatus
{
enum LogType {
LogTypeHostAlert,
LogTypeHostDowntimeAlert,
LogTypeHostFlapping,
LogTypeHostNotification,
LogTypeHostInitialState,
LogTypeHostCurrentState,
LogTypeServiceAlert,
LogTypeServiceDowntimeAlert,
LogTypeServiceFlapping,
LogTypeServiceNotification,
LogTypeServiceInitialState,
LogTypeServiceCurrentState,
LogTypeTimeperiodTransition,
LogTypeVersion,
LogTypeInitialStates,
LogTypeProgramStarting
};
enum LogClass {
LogClassInfo = 0,
LogClassAlert = 1,
LogClassProgram = 2,
LogClassNotification = 3,
LogClassPassive = 4,
LogClassCommand = 5,
LogClassState = 6,
LogClassText = 7
};
/**
* @ingroup livestatus
*/
@ -35,7 +66,7 @@ class LogTable : public Table
public:
DECLARE_PTR_TYPEDEFS(LogTable);
LogTable(void);
LogTable(const unsigned long& from, const unsigned long& until);
static void AddColumns(Table *table, const String& prefix = String(),
const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor());
@ -45,6 +76,11 @@ public:
protected:
virtual void FetchRows(const AddRowFunction& addRowFn);
static Object::Ptr HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor);
static Object::Ptr ServiceAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor);
static Object::Ptr ContactAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor);
static Object::Ptr CommandAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor);
static Value TimeAccessor(const Value& row);
static Value LinenoAccessor(const Value& row);
static Value ClassAccessor(const Value& row);
@ -60,6 +96,18 @@ protected:
static Value HostNameAccessor(const Value& row);
static Value ContactNameAccessor(const Value& row);
static Value CommandNameAccessor(const Value& row);
private:
std::map<unsigned long, String> m_LogFileIndex;
std::map<unsigned long, Dictionary::Ptr> m_RowsCache;
unsigned long m_TimeFrom;
unsigned long m_TimeUntil;
boost::mutex m_Mutex;
void CreateLogIndex(const String& path);
static void CreateLogIndexFileHandler(const String& path, std::map<unsigned long, String>& index);
void GetLogClassType(const String& text, int& log_class, int& log_type);
Dictionary::Ptr GetLogEntryAttributes(const String& type, const String& options);
};
}

View File

@ -36,6 +36,7 @@
#include "base/objectlock.h"
#include "base/logger_fwd.h"
#include "base/exception.h"
#include "base/utility.h"
#include <boost/algorithm/string/classification.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/foreach.hpp>
@ -48,7 +49,8 @@ static int l_ExternalCommands = 0;
static boost::mutex l_QueryMutex;
Query::Query(const std::vector<String>& lines)
: m_KeepAlive(false), m_OutputFormat("csv"), m_ColumnHeaders(true), m_Limit(-1)
: m_KeepAlive(false), m_OutputFormat("csv"), m_ColumnHeaders(true), m_Limit(-1),
m_LogTimeFrom(0), m_LogTimeUntil(static_cast<long>(Utility::GetTime()))
{
if (lines.size() == 0) {
m_Verb = "ERROR";
@ -120,7 +122,7 @@ Query::Query(const std::vector<String>& lines)
else if (header == "ColumnHeaders")
m_ColumnHeaders = (params == "on");
else if (header == "Filter") {
Filter::Ptr filter = ParseFilter(params);
Filter::Ptr filter = ParseFilter(params, m_LogTimeFrom, m_LogTimeUntil);
if (!filter) {
m_Verb = "ERROR";
@ -162,7 +164,7 @@ Query::Query(const std::vector<String>& lines)
} else if (aggregate_arg == "avginv") {
aggregator = boost::make_shared<InvAvgAggregator>(aggregate_attr);
} else {
filter = ParseFilter(params);
filter = ParseFilter(params, m_LogTimeFrom, m_LogTimeUntil);
if (!filter) {
m_Verb = "ERROR";
@ -249,7 +251,7 @@ int Query::GetExternalCommands(void)
return l_ExternalCommands;
}
Filter::Ptr Query::ParseFilter(const String& params)
Filter::Ptr Query::ParseFilter(const String& params, unsigned long& from, unsigned long& until)
{
std::vector<String> tokens;
boost::algorithm::split(tokens, params, boost::is_any_of(" "));
@ -282,6 +284,15 @@ Filter::Ptr Query::ParseFilter(const String& params)
if (negate)
filter = boost::make_shared<NegateFilter>(filter);
/* pre-filter log time duration */
if (tokens[0] == "time") {
if (op == "<" || op == "<=") {
until = Convert::ToLong(tokens[2]);
} else if (op == ">" || op == ">=") {
from = Convert::ToLong(tokens[2]);
}
}
return filter;
}
@ -350,7 +361,7 @@ void Query::ExecuteGetHelper(const Stream::Ptr& stream)
{
Log(LogInformation, "livestatus", "Table: " + m_Table);
Table::Ptr table = Table::GetByName(m_Table);
Table::Ptr table = Table::GetByName(m_Table, m_LogTimeFrom, m_LogTimeUntil);
if (!table) {
SendResponse(stream, LivestatusErrorNotFound, "Table '" + m_Table + "' does not exist.");

View File

@ -79,6 +79,9 @@ private:
int m_ErrorCode;
String m_ErrorMessage;
unsigned long m_LogTimeFrom;
unsigned long m_LogTimeUntil;
void PrintResultSet(std::ostream& fp, const std::vector<String>& columns, const Array::Ptr& rs);
void PrintCsvArray(std::ostream& fp, const Array::Ptr& array, int level);
@ -89,7 +92,7 @@ private:
void SendResponse(const Stream::Ptr& stream, int code, const String& data);
void PrintFixed16(const Stream::Ptr& stream, int code, const String& data);
static Filter::Ptr ParseFilter(const String& params);
static Filter::Ptr ParseFilter(const String& params, unsigned long& from, unsigned long& until);
};
}

View File

@ -151,22 +151,42 @@ Object::Ptr ServicesTable::HostAccessor(const Value& row, const Column::ObjectAc
else
service = row;
return static_cast<Service::Ptr>(service)->GetHost();
Service::Ptr svc = static_cast<Service::Ptr>(service);
if (!svc)
return Object::Ptr();
return svc->GetHost();
}
Value ServicesTable::ShortNameAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetShortName();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetShortName();
}
Value ServicesTable::DisplayNameAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetDisplayName();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetDisplayName();
}
Value ServicesTable::CheckCommandAccessor(const Value& row)
{
CheckCommand::Ptr checkcommand = static_cast<Service::Ptr>(row)->GetCheckCommand();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
CheckCommand::Ptr checkcommand = service->GetCheckCommand();
if (checkcommand)
return checkcommand->GetName(); /* this is the name without '!' args */
@ -178,6 +198,9 @@ Value ServicesTable::CheckCommandExpandedAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
CheckCommand::Ptr commandObj = service->GetCheckCommand();
if (!commandObj)
@ -218,7 +241,12 @@ Value ServicesTable::CheckCommandExpandedAccessor(const Value& row)
Value ServicesTable::EventHandlerAccessor(const Value& row)
{
EventCommand::Ptr eventcommand = static_cast<Service::Ptr>(row)->GetEventCommand();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
EventCommand::Ptr eventcommand = service->GetEventCommand();
if (eventcommand)
return eventcommand->GetName();
@ -228,22 +256,42 @@ Value ServicesTable::EventHandlerAccessor(const Value& row)
Value ServicesTable::PluginOutputAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetLastCheckOutput();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetLastCheckOutput();
}
Value ServicesTable::LongPluginOutputAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetLastCheckLongOutput();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetLastCheckLongOutput();
}
Value ServicesTable::PerfDataAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetLastCheckPerfData();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetLastCheckPerfData();
}
Value ServicesTable::NotificationPeriodAccessor(const Value& row)
{
BOOST_FOREACH(const Notification::Ptr& notification, static_cast<Service::Ptr>(row)->GetNotifications()) {
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
ObjectLock olock(notification);
TimePeriod::Ptr timeperiod = notification->GetNotificationPeriod();
@ -258,7 +306,12 @@ Value ServicesTable::NotificationPeriodAccessor(const Value& row)
Value ServicesTable::CheckPeriodAccessor(const Value& row)
{
TimePeriod::Ptr timeperiod = static_cast<Service::Ptr>(row)->GetCheckPeriod();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
TimePeriod::Ptr timeperiod = service->GetCheckPeriod();
if (!timeperiod)
return Empty;
@ -268,7 +321,12 @@ Value ServicesTable::CheckPeriodAccessor(const Value& row)
Value ServicesTable::NotesAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<Service::Ptr>(row)->GetCustom();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
return Empty;
@ -279,6 +337,10 @@ Value ServicesTable::NotesAccessor(const Value& row)
Value ServicesTable::NotesExpandedAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
@ -299,7 +361,12 @@ Value ServicesTable::NotesExpandedAccessor(const Value& row)
Value ServicesTable::NotesUrlAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<Service::Ptr>(row)->GetCustom();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
return Empty;
@ -310,6 +377,10 @@ Value ServicesTable::NotesUrlAccessor(const Value& row)
Value ServicesTable::NotesUrlExpandedAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
@ -330,7 +401,12 @@ Value ServicesTable::NotesUrlExpandedAccessor(const Value& row)
Value ServicesTable::ActionUrlAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<Service::Ptr>(row)->GetCustom();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
return Empty;
@ -341,6 +417,10 @@ Value ServicesTable::ActionUrlAccessor(const Value& row)
Value ServicesTable::ActionUrlExpandedAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
@ -361,7 +441,12 @@ Value ServicesTable::ActionUrlExpandedAccessor(const Value& row)
Value ServicesTable::IconImageAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<Service::Ptr>(row)->GetCustom();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
return Empty;
@ -372,6 +457,10 @@ Value ServicesTable::IconImageAccessor(const Value& row)
Value ServicesTable::IconImageExpandedAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
@ -392,7 +481,12 @@ Value ServicesTable::IconImageExpandedAccessor(const Value& row)
Value ServicesTable::IconImageAltAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<Service::Ptr>(row)->GetCustom();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
return Empty;
@ -402,48 +496,91 @@ Value ServicesTable::IconImageAltAccessor(const Value& row)
Value ServicesTable::MaxCheckAttemptsAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetMaxCheckAttempts();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetMaxCheckAttempts();
}
Value ServicesTable::CurrentAttemptAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetCheckAttempt();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetCheckAttempt();
}
Value ServicesTable::StateAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetState();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetState();
}
Value ServicesTable::HasBeenCheckedAccessor(const Value& row)
{
return (static_cast<Service::Ptr>(row)->HasBeenChecked() ? 1 : 0);
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (service->HasBeenChecked() ? 1 : 0);
}
Value ServicesTable::LastStateAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetLastState();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetLastState();
}
Value ServicesTable::LastHardStateAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetLastHardState();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetLastHardState();
}
Value ServicesTable::StateTypeAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetStateType();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetStateType();
}
Value ServicesTable::CheckTypeAccessor(const Value& row)
{
return (static_cast<Service::Ptr>(row)->GetEnableActiveChecks() ? 0 : 1);
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (service->GetEnableActiveChecks() ? 0 : 1);
}
Value ServicesTable::AcknowledgedAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
/* important: lock acknowledgements */
ObjectLock olock(service);
@ -454,6 +591,9 @@ Value ServicesTable::AcknowledgementTypeAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
/* important: lock acknowledgements */
ObjectLock olock(service);
@ -464,6 +604,9 @@ Value ServicesTable::NoMoreNotificationsAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
/* XXX take the smallest notification_interval */
double notification_interval = -1;
BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
@ -479,38 +622,71 @@ Value ServicesTable::NoMoreNotificationsAccessor(const Value& row)
Value ServicesTable::LastTimeOkAccessor(const Value& row)
{
return static_cast<int>(static_cast<Service::Ptr>(row)->GetLastStateOK());
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return static_cast<int>(service->GetLastStateOK());
}
Value ServicesTable::LastTimeWarningAccessor(const Value& row)
{
return static_cast<int>(static_cast<Service::Ptr>(row)->GetLastStateWarning());
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return static_cast<int>(service->GetLastStateWarning());
}
Value ServicesTable::LastTimeCriticalAccessor(const Value& row)
{
return static_cast<int>(static_cast<Service::Ptr>(row)->GetLastStateCritical());
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return static_cast<int>(service->GetLastStateCritical());
}
Value ServicesTable::LastTimeUnknownAccessor(const Value& row)
{
return static_cast<int>(static_cast<Service::Ptr>(row)->GetLastStateUnknown());
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return static_cast<int>(service->GetLastStateUnknown());
}
Value ServicesTable::LastCheckAccessor(const Value& row)
{
return static_cast<int>(static_cast<Service::Ptr>(row)->GetLastCheck());
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return static_cast<int>(service->GetLastCheck());
}
Value ServicesTable::NextCheckAccessor(const Value& row)
{
return static_cast<int>(static_cast<Service::Ptr>(row)->GetNextCheck());
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return static_cast<int>(service->GetNextCheck());
}
Value ServicesTable::LastNotificationAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
/* XXX Service -> Notifications, latest wins */
double last_notification = 0;
BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
@ -525,6 +701,9 @@ Value ServicesTable::NextNotificationAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
/* XXX Service -> Notifications, latest wins */
double next_notification = 0;
BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
@ -539,6 +718,9 @@ Value ServicesTable::CurrentNotificationNumberAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
/* XXX Service -> Notifications, biggest wins */
int notification_number = 0;
BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
@ -551,37 +733,72 @@ Value ServicesTable::CurrentNotificationNumberAccessor(const Value& row)
Value ServicesTable::LastStateChangeAccessor(const Value& row)
{
return static_cast<int>(static_cast<Service::Ptr>(row)->GetLastStateChange());
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return static_cast<int>(service->GetLastStateChange());
}
Value ServicesTable::LastHardStateChangeAccessor(const Value& row)
{
return static_cast<int>(static_cast<Service::Ptr>(row)->GetLastHardStateChange());
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return static_cast<int>(service->GetLastHardStateChange());
}
Value ServicesTable::ScheduledDowntimeDepthAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetDowntimeDepth();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetDowntimeDepth();
}
Value ServicesTable::IsFlappingAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->IsFlapping();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->IsFlapping();
}
Value ServicesTable::ChecksEnabledAccessor(const Value& row)
{
return (static_cast<Service::Ptr>(row)->GetEnableActiveChecks() ? 1 : 0);
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (service->GetEnableActiveChecks() ? 1 : 0);
}
Value ServicesTable::AcceptPassiveChecksAccessor(const Value& row)
{
return (static_cast<Service::Ptr>(row)->GetEnablePassiveChecks() ? 1 : 0);
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (service->GetEnablePassiveChecks() ? 1 : 0);
}
Value ServicesTable::EventHandlerEnabledAccessor(const Value& row)
{
EventCommand::Ptr eventcommand = static_cast<Service::Ptr>(row)->GetEventCommand();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
EventCommand::Ptr eventcommand = service->GetEventCommand();
if (eventcommand)
return 1;
@ -591,12 +808,22 @@ Value ServicesTable::EventHandlerEnabledAccessor(const Value& row)
Value ServicesTable::NotificationsEnabledAccessor(const Value& row)
{
return (static_cast<Service::Ptr>(row)->GetEnableNotifications() ? 1 : 0);
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (service->GetEnableNotifications() ? 1 : 0);
}
Value ServicesTable::ActiveChecksEnabledAccessor(const Value& row)
{
return (static_cast<Service::Ptr>(row)->GetEnableActiveChecks() ? 1 : 0);
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (service->GetEnableActiveChecks() ? 1 : 0);
}
Value ServicesTable::CheckOptionsAccessor(const Value& row)
@ -607,7 +834,12 @@ Value ServicesTable::CheckOptionsAccessor(const Value& row)
Value ServicesTable::FlapDetectionEnabledAccessor(const Value& row)
{
return (static_cast<Service::Ptr>(row)->GetEnableFlapping() ? 1 : 0);
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (service->GetEnableFlapping() ? 1 : 0);
}
Value ServicesTable::CheckFreshnessAccessor(const Value& row)
@ -618,7 +850,12 @@ Value ServicesTable::CheckFreshnessAccessor(const Value& row)
Value ServicesTable::ModifiedAttributesAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetModifiedAttributes();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetModifiedAttributes();
}
Value ServicesTable::ModifiedAttributesListAccessor(const Value& row)
@ -631,6 +868,9 @@ Value ServicesTable::StalenessAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
if (service->HasBeenChecked() && service->GetLastCheck() > 0)
return (Utility::GetTime() - service->GetLastCheck()) / (service->GetCheckInterval() * 3600);
@ -639,18 +879,31 @@ Value ServicesTable::StalenessAccessor(const Value& row)
Value ServicesTable::CheckIntervalAccessor(const Value& row)
{
return (static_cast<Service::Ptr>(row)->GetCheckInterval() / 60.0);
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (service->GetCheckInterval() / 60.0);
}
Value ServicesTable::RetryIntervalAccessor(const Value& row)
{
return (static_cast<Service::Ptr>(row)->GetRetryInterval() / 60.0);
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (service->GetRetryInterval() / 60.0);
}
Value ServicesTable::NotificationIntervalAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
/* XXX take the smallest notification_interval */
double notification_interval = -1;
BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
@ -666,32 +919,62 @@ Value ServicesTable::NotificationIntervalAccessor(const Value& row)
Value ServicesTable::LowFlapThresholdAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetFlappingThreshold();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetFlappingThreshold();
}
Value ServicesTable::HighFlapThresholdAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetFlappingThreshold();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetFlappingThreshold();
}
Value ServicesTable::LatencyAccessor(const Value& row)
{
return (Service::CalculateLatency(static_cast<Service::Ptr>(row)->GetLastCheckResult()));
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (Service::CalculateLatency(service->GetLastCheckResult()));
}
Value ServicesTable::ExecutionTimeAccessor(const Value& row)
{
return (Service::CalculateExecutionTime(static_cast<Service::Ptr>(row)->GetLastCheckResult()));
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return (Service::CalculateExecutionTime(service->GetLastCheckResult()));
}
Value ServicesTable::PercentStateChangeAccessor(const Value& row)
{
return static_cast<Service::Ptr>(row)->GetFlappingCurrent();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
return service->GetFlappingCurrent();
}
Value ServicesTable::InCheckPeriodAccessor(const Value& row)
{
TimePeriod::Ptr timeperiod = static_cast<Service::Ptr>(row)->GetCheckPeriod();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
TimePeriod::Ptr timeperiod = service->GetCheckPeriod();
/* none set means always checked */
if (!timeperiod)
@ -702,7 +985,12 @@ Value ServicesTable::InCheckPeriodAccessor(const Value& row)
Value ServicesTable::InNotificationPeriodAccessor(const Value& row)
{
BOOST_FOREACH(const Notification::Ptr& notification, static_cast<Service::Ptr>(row)->GetNotifications()) {
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
ObjectLock olock(notification);
TimePeriod::Ptr timeperiod = notification->GetNotificationPeriod();
@ -718,9 +1006,14 @@ Value ServicesTable::InNotificationPeriodAccessor(const Value& row)
Value ServicesTable::ContactsAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Array::Ptr contact_names = boost::make_shared<Array>();
BOOST_FOREACH(const User::Ptr& user, CompatUtility::GetServiceNotificationUsers(static_cast<Service::Ptr>(row))) {
BOOST_FOREACH(const User::Ptr& user, CompatUtility::GetServiceNotificationUsers(service)) {
contact_names->Add(user->GetName());
}
@ -729,7 +1022,12 @@ Value ServicesTable::ContactsAccessor(const Value& row)
Value ServicesTable::DowntimesAccessor(const Value& row)
{
Dictionary::Ptr downtimes = static_cast<Service::Ptr>(row)->GetDowntimes();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr downtimes = service->GetDowntimes();
Array::Ptr ids = boost::make_shared<Array>();
@ -753,7 +1051,12 @@ Value ServicesTable::DowntimesAccessor(const Value& row)
Value ServicesTable::DowntimesWithInfoAccessor(const Value& row)
{
Dictionary::Ptr downtimes = static_cast<Service::Ptr>(row)->GetDowntimes();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr downtimes = service->GetDowntimes();
Array::Ptr ids = boost::make_shared<Array>();
@ -781,7 +1084,12 @@ Value ServicesTable::DowntimesWithInfoAccessor(const Value& row)
Value ServicesTable::CommentsAccessor(const Value& row)
{
Dictionary::Ptr comments = static_cast<Service::Ptr>(row)->GetComments();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr comments = service->GetComments();
Array::Ptr ids = boost::make_shared<Array>();
@ -805,7 +1113,12 @@ Value ServicesTable::CommentsAccessor(const Value& row)
Value ServicesTable::CommentsWithInfoAccessor(const Value& row)
{
Dictionary::Ptr comments = static_cast<Service::Ptr>(row)->GetComments();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr comments = service->GetComments();
Array::Ptr ids = boost::make_shared<Array>();
@ -833,7 +1146,12 @@ Value ServicesTable::CommentsWithInfoAccessor(const Value& row)
Value ServicesTable::CommentsWithExtraInfoAccessor(const Value& row)
{
Dictionary::Ptr comments = static_cast<Service::Ptr>(row)->GetComments();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr comments = service->GetComments();
Array::Ptr ids = boost::make_shared<Array>();
@ -863,7 +1181,12 @@ Value ServicesTable::CommentsWithExtraInfoAccessor(const Value& row)
Value ServicesTable::CustomVariableNamesAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<Service::Ptr>(row)->GetCustom();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
return Empty;
@ -891,7 +1214,12 @@ Value ServicesTable::CustomVariableNamesAccessor(const Value& row)
Value ServicesTable::CustomVariableValuesAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<Service::Ptr>(row)->GetCustom();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
return Empty;
@ -919,7 +1247,12 @@ Value ServicesTable::CustomVariableValuesAccessor(const Value& row)
Value ServicesTable::CustomVariablesAccessor(const Value& row)
{
Dictionary::Ptr custom = static_cast<Service::Ptr>(row)->GetCustom();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Dictionary::Ptr custom = service->GetCustom();
if (!custom)
return Empty;
@ -950,7 +1283,12 @@ Value ServicesTable::CustomVariablesAccessor(const Value& row)
Value ServicesTable::GroupsAccessor(const Value& row)
{
Array::Ptr groups = static_cast<Service::Ptr>(row)->GetGroups();
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Array::Ptr groups = service->GetGroups();
if (!groups)
return Empty;
@ -960,9 +1298,14 @@ Value ServicesTable::GroupsAccessor(const Value& row)
Value ServicesTable::ContactGroupsAccessor(const Value& row)
{
Service::Ptr service = static_cast<Service::Ptr>(row);
if (!service)
return Empty;
Array::Ptr contactgroup_names = boost::make_shared<Array>();
BOOST_FOREACH(const UserGroup::Ptr& usergroup, CompatUtility::GetServiceNotificationUserGroups(static_cast<Service::Ptr>(row))) {
BOOST_FOREACH(const UserGroup::Ptr& usergroup, CompatUtility::GetServiceNotificationUserGroups(service)) {
contactgroup_names->Add(usergroup->GetName());
}

View File

@ -44,7 +44,7 @@ using namespace livestatus;
Table::Table(void)
{ }
Table::Ptr Table::GetByName(const String& name)
Table::Ptr Table::GetByName(const String& name, const unsigned long& from, const unsigned long& until)
{
if (name == "status")
return boost::make_shared<StatusTable>();
@ -69,7 +69,7 @@ Table::Ptr Table::GetByName(const String& name)
else if (name == "timeperiods")
return boost::make_shared<TimePeriodsTable>();
else if (name == "log")
return boost::make_shared<LogTable>();
return boost::make_shared<LogTable>(from, until);
return Table::Ptr();
}

View File

@ -40,8 +40,7 @@ public:
typedef boost::function<void (const Value&)> AddRowFunction;
static Table::Ptr GetByName(const String& name);
static Table::Ptr GetByName(const String& name, const unsigned long& from = 0, const unsigned long& until = 0);
virtual String GetName(void) const = 0;

View File

@ -499,6 +499,18 @@ StateType Host::GetStateType(void) const
return hc->GetStateType();
}
HostState Host::StateFromString(const String& state)
{
if (state == "UP")
return HostUp;
else if (state == "DOWN")
return HostDown;
else if (state == "UNREACHABLE")
return HostUnreachable;
else
return HostUnreachable;
}
String Host::StateToString(HostState state)
{
switch (state) {
@ -513,6 +525,22 @@ String Host::StateToString(HostState state)
}
}
StateType Host::StateTypeFromString(const String& type)
{
if (type == "SOFT")
return StateTypeSoft;
else
return StateTypeHard;
}
String Host::StateTypeToString(StateType type)
{
if (type == StateTypeSoft)
return "SOFT";
else
return "HARD";
}
bool Host::ResolveMacro(const String& macro, const Dictionary::Ptr&, String *result) const
{
if (macro == "HOSTNAME") {

View File

@ -82,8 +82,12 @@ public:
double GetLastStateDown(void) const;
double GetLastStateUnreachable(void) const;
static HostState StateFromString(const String& state);
static String StateToString(HostState state);
static StateType StateTypeFromString(const String& state);
static String StateTypeToString(StateType state);
virtual bool ResolveMacro(const String& macro, const Dictionary::Ptr& cr, String *result) const;
protected:

View File

@ -286,7 +286,7 @@ void Notification::ExecuteNotificationHelper(NotificationType type, const User::
SetLastNotification(Utility::GetTime());
}
Service::OnNotificationSentToUser(GetService(), user, type, cr, author, text);
Service::OnNotificationSentToUser(GetService(), user, type, cr, author, text, command->GetName());
Log(LogInformation, "icinga", "Completed sending notification for service '" + GetService()->GetName() + "'");
} catch (const std::exception& ex) {

View File

@ -33,7 +33,7 @@
using namespace icinga;
boost::signals2::signal<void (const Service::Ptr&, const std::set<User::Ptr>&, const NotificationType&, const Dictionary::Ptr&, const String&, const String&)> Service::OnNotificationSentToAllUsers;
boost::signals2::signal<void (const Service::Ptr&, const User::Ptr&, const NotificationType&, const Dictionary::Ptr&, const String&, const String&)> Service::OnNotificationSentToUser;
boost::signals2::signal<void (const Service::Ptr&, const User::Ptr&, const NotificationType&, const Dictionary::Ptr&, const String&, const String&, const String&)> Service::OnNotificationSentToUser;
void Service::ResetNotificationNumbers(void)
{

View File

@ -203,7 +203,7 @@ public:
static boost::signals2::signal<void (const Service::Ptr&, const Dictionary::Ptr&, const String&)> OnNewCheckResult;
static boost::signals2::signal<void (const Service::Ptr&, const Dictionary::Ptr&, StateType, const String&)> OnStateChange;
static boost::signals2::signal<void (const Service::Ptr&, NotificationType, const Dictionary::Ptr&, const String&, const String&)> OnNotificationsRequested;
static boost::signals2::signal<void (const Service::Ptr&, const User::Ptr&, const NotificationType&, const Dictionary::Ptr&, const String&, const String&)> OnNotificationSentToUser;
static boost::signals2::signal<void (const Service::Ptr&, const User::Ptr&, const NotificationType&, const Dictionary::Ptr&, const String&, const String&, const String&)> OnNotificationSentToUser;
static boost::signals2::signal<void (const Service::Ptr&, const std::set<User::Ptr>&, const NotificationType&, const Dictionary::Ptr&, const String&, const String&)> OnNotificationSentToAllUsers;
static boost::signals2::signal<void (const Service::Ptr&, const Dictionary::Ptr&, const String&)> OnCommentAdded;
static boost::signals2::signal<void (const Service::Ptr&, const Dictionary::Ptr&, const String&)> OnCommentRemoved;

View File

@ -0,0 +1,7 @@
GET log
Columns: host_name service_description time lineno class type options plugin_output state state_type comment contact_name command_name
Filter: time >= 1348657741
Filter: host_name = localhost
Filter: service_description = disk
ResponseHeader: fixed16

View File

@ -0,0 +1,4 @@
GET log
Filter: time >= 1348657741
ResponseHeader: fixed16

View File

@ -0,0 +1,5 @@
GET log
Columns: host_name service_description time lineno class type options plugin_output state state_type comment contact_name command_name
Filter: time >= 1348657741
ResponseHeader: fixed16

View File

@ -1,14 +1,14 @@
#!/bin/bash
LIVESTATUSHOST="10.0.10.18"
LIVESTATUSHOST="127.0.0.1"
LIVESTATUSPORT="6558"
LIVESTATUSQUERIES="./queries"
LIVESTATUSTABLE=$1
if [ -n "$LIVESTATUSTABLE" ]; then
cat "$LIVESTATUSQUERIES/$LIVESTATUSTABLE"
(cat "$LIVESTATUSQUERIES/$LIVESTATUSTABLE"; sleep 1) | netcat $LIVESTATUSHOST $LIVESTATUSPORT
cat "$LIVESTATUSTABLE"
(cat "$LIVESTATUSTABLE"; sleep 1) | netcat $LIVESTATUSHOST $LIVESTATUSPORT
else
echo -e "Looking into $LIVESTATUSQUERIES\n"