From 7fa9188df86ab48882f4cd8df7c1c8b1510e1c2a Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Tue, 17 Dec 2013 12:19:29 +0100 Subject: [PATCH 1/4] Add String::Contains(). Refs #5355 --- lib/base/qstring.cpp | 7 +++++++ lib/base/qstring.h | 1 + test/CMakeLists.txt | 1 + test/base-string.cpp | 15 +++++++++++++++ 4 files changed, 24 insertions(+) diff --git a/lib/base/qstring.cpp b/lib/base/qstring.cpp index 180fe532f..24cc970df 100644 --- a/lib/base/qstring.cpp +++ b/lib/base/qstring.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include using namespace icinga; @@ -179,6 +181,11 @@ void String::Trim(void) boost::algorithm::trim(m_Data); } +bool String::Contains(const String& str) const +{ + return boost::algorithm::contains(m_Data, str); +} + void String::swap(String& str) { m_Data.swap(str.m_Data); diff --git a/lib/base/qstring.h b/lib/base/qstring.h index 47f7e5ad7..e5bd45adf 100644 --- a/lib/base/qstring.h +++ b/lib/base/qstring.h @@ -91,6 +91,7 @@ public: void Replace(size_t first, size_t second, const String& str); void Trim(void); + bool Contains(const String& str) const; void swap(String& str); Iterator erase(Iterator first, Iterator last); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f4867e128..752914d58 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -62,6 +62,7 @@ add_boost_test(base base_string/clear base_string/append base_string/trim + base_string/contains base_string/replace base_string/index base_string/find diff --git a/test/base-string.cpp b/test/base-string.cpp index 0de138f7a..f4c0970c2 100644 --- a/test/base-string.cpp +++ b/test/base-string.cpp @@ -79,6 +79,21 @@ BOOST_AUTO_TEST_CASE(trim) BOOST_CHECK(s4 == "hello"); } +BOOST_AUTO_TEST_CASE(contains) +{ + String s1 = "hello world"; + String s2 = "hello"; + BOOST_CHECK(s1.Contains(s2)); + + String s3 = " hello world "; + String s4 = " hello"; + BOOST_CHECK(s3.Contains(s4)); + + String s5 = " hello world "; + String s6 = "world "; + BOOST_CHECK(s5.Contains(s6)); +} + BOOST_AUTO_TEST_CASE(replace) { String s = "hello"; From 88fa67c108b05eb5b6279e3f966890c1933b0e2d Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Tue, 17 Dec 2013 12:58:04 +0100 Subject: [PATCH 2/4] Livestatus: Refactor historical tables. Refs #5351 Refs #5348 --- components/livestatus/CMakeLists.txt | 2 +- components/livestatus/logtable.cpp | 351 +------------- components/livestatus/logtable.h | 47 +- components/livestatus/logutility.cpp | 365 +++++++++++++++ components/livestatus/logutility.h | 79 ++++ components/livestatus/statehisttable.cpp | 563 +++++++---------------- components/livestatus/statehisttable.h | 43 +- components/livestatus/table.cpp | 5 + components/livestatus/table.h | 2 + 9 files changed, 639 insertions(+), 818 deletions(-) create mode 100644 components/livestatus/logutility.cpp create mode 100644 components/livestatus/logutility.h diff --git a/components/livestatus/CMakeLists.txt b/components/livestatus/CMakeLists.txt index 69925ca1e..0c3cc0b0d 100644 --- a/components/livestatus/CMakeLists.txt +++ b/components/livestatus/CMakeLists.txt @@ -19,7 +19,7 @@ mkclass_target(listener.ti listener.th) mkembedconfig_target(livestatus-type.conf livestatus-type.cpp) -add_library(livestatus SHARED aggregator.cpp andfilter.cpp attributefilter.cpp avgaggregator.cpp column.cpp combinerfilter.cpp commandstable.cpp commentstable.cpp contactgroupstable.cpp contactstable.cpp countaggregator.cpp downtimestable.cpp filter.cpp hostgroupstable.cpp hoststable.cpp invavgaggregator.cpp invsumaggregator.cpp listener.cpp listener.th logtable.cpp maxaggregator.cpp minaggregator.cpp negatefilter.cpp orfilter.cpp query.cpp servicegroupstable.cpp servicestable.cpp statehisttable.cpp statustable.cpp stdaggregator.cpp sumaggregator.cpp table.cpp timeperiodstable.cpp livestatus-type.cpp) +add_library(livestatus SHARED aggregator.cpp andfilter.cpp attributefilter.cpp avgaggregator.cpp column.cpp combinerfilter.cpp commandstable.cpp commentstable.cpp contactgroupstable.cpp contactstable.cpp countaggregator.cpp downtimestable.cpp filter.cpp hostgroupstable.cpp hoststable.cpp invavgaggregator.cpp invsumaggregator.cpp listener.cpp listener.th logutility.cpp logtable.cpp maxaggregator.cpp minaggregator.cpp negatefilter.cpp orfilter.cpp query.cpp servicegroupstable.cpp servicestable.cpp statehisttable.cpp statustable.cpp stdaggregator.cpp sumaggregator.cpp table.cpp timeperiodstable.cpp livestatus-type.cpp) target_link_libraries(livestatus ${Boost_LIBRARIES} base config icinga) diff --git a/components/livestatus/logtable.cpp b/components/livestatus/logtable.cpp index 1493ec3ab..4a745b930 100644 --- a/components/livestatus/logtable.cpp +++ b/components/livestatus/logtable.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "livestatus/logtable.h" +#include "livestatus/logutility.h" #include "livestatus/hoststable.h" #include "livestatus/servicestable.h" #include "livestatus/contactstable.h" @@ -55,70 +56,25 @@ LogTable::LogTable(const String& compat_log_path, const unsigned long& from, con m_TimeUntil = until; /* create log file index */ - CreateLogIndex(compat_log_path); + LogUtility::CreateLogIndex(compat_log_path, m_LogFileIndex); - /* 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); - - if (!bag) - continue; - - 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(); - } + /* generate log cache */ + LogUtility::CreateLogCache(m_LogFileIndex, this, from, until); AddColumns(this); } +void LogTable::UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno) +{ + /* additional attributes only for log table */ + bag->Set("lineno", lineno); + + { + boost::mutex::scoped_lock lock(m_Mutex); + m_RowsCache[line_count] = bag; + } +} + void LogTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { @@ -289,282 +245,5 @@ Value LogTable::CommandNameAccessor(const Value& row) return static_cast(row)->Get("command_name"); } -void LogTable::CreateLogIndex(const String& path) -{ - Utility::Glob(path + "/icinga.log", boost::bind(&LogTable::CreateLogIndexFileHandler, _1, boost::ref(m_LogFileIndex)), GlobFile); - Utility::Glob(path + "/archives/*.log", boost::bind(&LogTable::CreateLogIndexFileHandler, _1, boost::ref(m_LogFileIndex)), GlobFile); -} -void LogTable::CreateLogIndexFileHandler(const String& path, std::map& 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 tokens; - boost::algorithm::split(tokens, options, boost::is_any_of(";")); - - /* States - TODO refactor */ - if (boost::algorithm::contains(type, "INITIAL HOST STATE")) { - if (tokens.size() < 5) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 5) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 5) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 3) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 3) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 6) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 6) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 6) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 4) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 4) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 4) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 6) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 7) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 3) - return Dictionary::Ptr(); - - 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")) { - if (tokens.size() < 4) - return Dictionary::Ptr(); - - 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; - } else - return Dictionary::Ptr(); - - Dictionary::Ptr bag = make_shared(); - - 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; -} diff --git a/components/livestatus/logtable.h b/components/livestatus/logtable.h index 7e6f30b15..7aec5b891 100644 --- a/components/livestatus/logtable.h +++ b/components/livestatus/logtable.h @@ -28,36 +28,6 @@ using namespace icinga; namespace icinga { -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 */ @@ -73,6 +43,8 @@ public: virtual String GetName(void) const; + void UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno); + protected: virtual void FetchRows(const AddRowFunction& addRowFn); @@ -96,18 +68,13 @@ protected: static Value HostNameAccessor(const Value& row); static Value ContactNameAccessor(const Value& row); static Value CommandNameAccessor(const Value& row); - + private: - std::map m_LogFileIndex; - std::map m_RowsCache; - unsigned long m_TimeFrom; - unsigned long m_TimeUntil; + std::map m_LogFileIndex; + std::map m_RowsCache; + unsigned int m_TimeFrom; + unsigned int m_TimeUntil; boost::mutex m_Mutex; - - void CreateLogIndex(const String& path); - static void CreateLogIndexFileHandler(const String& path, std::map& index); - void GetLogClassType(const String& text, int& log_class, int& log_type); - Dictionary::Ptr GetLogEntryAttributes(const String& type, const String& options); }; } diff --git a/components/livestatus/logutility.cpp b/components/livestatus/logutility.cpp new file mode 100644 index 000000000..3115ae2c0 --- /dev/null +++ b/components/livestatus/logutility.cpp @@ -0,0 +1,365 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2013 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 "livestatus/logutility.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/utility.h" +#include "base/convert.h" +#include "base/logger_fwd.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace icinga; + +void LogUtility::CreateLogIndex(const String& path, std::map& index) +{ + Utility::Glob(path + "/icinga.log", boost::bind(&LogUtility::CreateLogIndexFileHandler, _1, boost::ref(index)), GlobFile); + Utility::Glob(path + "/archives/*.log", boost::bind(&LogUtility::CreateLogIndexFileHandler, _1, boost::ref(index)), GlobFile); +} + +void LogUtility::CreateLogIndexFileHandler(const String& path, std::map& 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; +} + +void LogUtility::CreateLogCache(std::map index, Table *table, + const unsigned int& from, const unsigned int& until) +{ + if (!table) + return; + + /* m_LogFileIndex map tells which log files are involved ordered by their start timestamp */ + unsigned int ts; + unsigned long line_count = 0; + BOOST_FOREACH(boost::tie(ts, boost::tuples::ignore), index) { + /* skip log files not in range (performance optimization) */ + if (ts < from || ts > until) + continue; + + String log_file = index[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 */ + + Dictionary::Ptr bag = LogUtility::GetAttributes(line); + + /* no attributes available - invalid log line */ + if (!bag) { + Log(LogDebug, "livestatus", "Skipping invalid log line: '" + line + "'."); + continue; + } + + table->UpdateLogCache(bag, line_count, lineno); + + line_count++; + lineno++; + } + + fp.close(); + } +} + + + +Dictionary::Ptr LogUtility::GetAttributes(const String& text) +{ + Dictionary::Ptr bag = make_shared(); + + /* + * [1379025342] SERVICE NOTIFICATION: contactname;hostname;servicedesc;WARNING;true;foo output + */ + unsigned long time = atoi(text.SubStr(1, 11).CStr()); + + Log(LogDebug, "livestatus", "Processing log line: '" + text + "'."); + bag->Set("time", time); + + size_t colon = text.FindFirstOf(':'); + size_t colon_offset = colon - 13; + + String type = String(text.SubStr(13, colon_offset)); + String options = String(text.SubStr(colon + 1)); + + type.Trim(); + options.Trim(); + + bag->Set("type", type); + bag->Set("options", options); + + std::vector tokens; + boost::algorithm::split(tokens, options, boost::is_any_of(";")); + + /* set default values */ + bag->Set("log_class", LogEntryClassInfo); + bag->Set("log_type", 0); + bag->Set("state", 0); + bag->Set("attempt", 0); + bag->Set("message", text); /* used as 'message' in log table, and 'log_output' in statehist table */ + + /* Host States */ + if (type.Contains("INITIAL HOST STATE") || + type.Contains("CURRENT HOST STATE") || + type.Contains("HOST ALERT")) { + if (tokens.size() < 5) + return bag; + + bag->Set("host_name", tokens[0]); + bag->Set("state", Host::StateFromString(tokens[1])); + bag->Set("state_type", tokens[2]); + bag->Set("attempt", atoi(tokens[3].CStr())); + bag->Set("plugin_output", tokens[4]); + + if (type.Contains("INITIAL HOST STATE")) { + bag->Set("log_class", LogEntryClassState); + bag->Set("log_type", LogEntryTypeHostInitialState); + } + else if (type.Contains("CURRENT HOST STATE")) { + bag->Set("log_class", LogEntryClassState); + bag->Set("log_type", LogEntryTypeHostCurrentState); + } + else { + bag->Set("log_class", LogEntryClassAlert); + bag->Set("log_type", LogEntryTypeHostAlert); + } + + return bag; + } + else if (type.Contains("HOST DOWNTIME ALERT") || + type.Contains("HOST FLAPPING ALERT")) { + if (tokens.size() < 3) + return bag; + + bag->Set("host_name", tokens[0]); + bag->Set("state_type", tokens[1]); + bag->Set("comment", tokens[2]); + + if (type.Contains("HOST FLAPPING ALERT")) { + bag->Set("log_class", LogEntryClassAlert); + bag->Set("log_type", LogEntryTypeHostFlapping); + } else { + bag->Set("log_class", LogEntryClassAlert); + bag->Set("log_type", LogEntryTypeHostDowntimeAlert); + } + + return bag; + } + /* Service States */ + else if (type.Contains("INITIAL SERVICE STATE") || + type.Contains("CURRENT SERVICE STATE") || + type.Contains("SERVICE ALERT")) { + if (tokens.size() < 6) + return bag; + + bag->Set("host_name", tokens[0]); + bag->Set("service_description", tokens[1]); + bag->Set("state", Service::StateFromString(tokens[2])); + bag->Set("state_type", tokens[3]); + bag->Set("attempt", atoi(tokens[4].CStr())); + bag->Set("plugin_output", tokens[5]); + + if (type.Contains("INITIAL SERVICE STATE")) { + bag->Set("log_class", LogEntryClassState); + bag->Set("log_type", LogEntryTypeServiceInitialState); + } + else if (type.Contains("CURRENT SERVICE STATE")) { + bag->Set("log_class", LogEntryClassState); + bag->Set("log_type", LogEntryTypeServiceCurrentState); + } + else { + bag->Set("log_class", LogEntryClassAlert); + bag->Set("log_type", LogEntryTypeServiceAlert); + } + + return bag; + } + else if (type.Contains("SERVICE DOWNTIME ALERT") || + type.Contains("SERVICE FLAPPING ALERT")) { + if (tokens.size() < 4) + return bag; + + bag->Set("host_name", tokens[0]); + bag->Set("service_description", tokens[1]); + bag->Set("state_type", tokens[2]); + bag->Set("comment", tokens[3]); + + if (type.Contains("SERVICE FLAPPING ALERT")) { + bag->Set("log_class", LogEntryClassAlert); + bag->Set("log_type", LogEntryTypeServiceFlapping); + } else { + bag->Set("log_class", LogEntryClassAlert); + bag->Set("log_type", LogEntryTypeServiceDowntimeAlert); + } + + return bag; + } + /* Timeperiods */ + else if (type.Contains("TIMEPERIOD TRANSITION")) { + if (tokens.size() < 4) + return bag; + + bag->Set("log_class", LogEntryClassState); + bag->Set("log_type", LogEntryTypeTimeperiodTransition); + + bag->Set("host_name", tokens[0]); + bag->Set("service_description", tokens[1]); + bag->Set("state_type", tokens[2]); + bag->Set("comment", tokens[3]); + } + /* Notifications */ + else if (type.Contains("HOST NOTIFICATION")) { + if (tokens.size() < 6) + return bag; + + bag->Set("contact_name", tokens[0]); + bag->Set("host_name", tokens[1]); + bag->Set("state_type", tokens[2]); + bag->Set("state", Service::StateFromString(tokens[3])); + bag->Set("command_name", atoi(tokens[4].CStr())); + bag->Set("plugin_output", tokens[5]); + + bag->Set("log_class", LogEntryClassNotification); + bag->Set("log_type", LogEntryTypeHostNotification); + + return bag; + } + else if (type.Contains("SERVICE NOTIFICATION")) { + if (tokens.size() < 7) + return bag; + + bag->Set("contact_name", tokens[0]); + bag->Set("host_name", tokens[1]); + bag->Set("service_description", tokens[2]); + bag->Set("state_type", tokens[3]); + bag->Set("state", Service::StateFromString(tokens[4])); + bag->Set("command_name", atoi(tokens[5].CStr())); + bag->Set("plugin_output", tokens[6]); + + bag->Set("log_class", LogEntryClassNotification); + bag->Set("log_type", LogEntryTypeServiceNotification); + + return bag; + } + /* Passive Checks */ + else if (type.Contains("PASSIVE HOST CHECK")) { + if (tokens.size() < 3) + return bag; + + bag->Set("host_name", tokens[0]); + bag->Set("state", Host::StateFromString(tokens[1])); + bag->Set("plugin_output", tokens[2]); + + bag->Set("log_class", LogEntryClassPassive); + + return bag; + } + else if (type.Contains("PASSIVE SERVICE CHECK")) { + if (tokens.size() < 4) + return bag; + + bag->Set("host_name", tokens[0]); + bag->Set("service_description", tokens[1]); + bag->Set("state", Host::StateFromString(tokens[2])); + bag->Set("plugin_output", tokens[3]); + + bag->Set("log_class", LogEntryClassPassive); + + return bag; + } + /* External Command */ + else if (type.Contains("EXTERNAL COMMAND")) { + bag->Set("log_class", LogEntryClassCommand); + /* string processing not implemented in 1.x */ + + return bag; + } + /* normal text entries */ + else if (type.Contains("LOG VERSION")) { + bag->Set("log_class", LogEntryClassProgram); + bag->Set("log_type", LogEntryTypeVersion); + + return bag; + } + else if (type.Contains("logging initial states")) { + bag->Set("log_class", LogEntryClassProgram); + bag->Set("log_type", LogEntryTypeInitialStates); + + return bag; + } + else if (type.Contains("starting... (PID=")) { + bag->Set("log_class", LogEntryClassProgram); + bag->Set("log_type", LogEntryTypeProgramStarting); + + return bag; + } + /* program */ + else if (type.Contains("restarting...") || + type.Contains("shutting down...") || + type.Contains("Bailing out") || + type.Contains("active mode...") || + type.Contains("standby mode...")) { + bag->Set("log_class", LogEntryClassProgram); + + return bag; + } + + return bag; +} diff --git a/components/livestatus/logutility.h b/components/livestatus/logutility.h new file mode 100644 index 000000000..b5d44d266 --- /dev/null +++ b/components/livestatus/logutility.h @@ -0,0 +1,79 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2013 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 LOGUTILITY_H +#define LOGUTILITY_H + +#include "livestatus/table.h" +#include + +using namespace icinga; + +namespace icinga +{ + +enum LogEntryType { + LogEntryTypeHostAlert, + LogEntryTypeHostDowntimeAlert, + LogEntryTypeHostFlapping, + LogEntryTypeHostNotification, + LogEntryTypeHostInitialState, + LogEntryTypeHostCurrentState, + LogEntryTypeServiceAlert, + LogEntryTypeServiceDowntimeAlert, + LogEntryTypeServiceFlapping, + LogEntryTypeServiceNotification, + LogEntryTypeServiceInitialState, + LogEntryTypeServiceCurrentState, + LogEntryTypeTimeperiodTransition, + LogEntryTypeVersion, + LogEntryTypeInitialStates, + LogEntryTypeProgramStarting +}; + +enum LogEntryClass { + LogEntryClassInfo = 0, + LogEntryClassAlert = 1, + LogEntryClassProgram = 2, + LogEntryClassNotification = 3, + LogEntryClassPassive = 4, + LogEntryClassCommand = 5, + LogEntryClassState = 6, + LogEntryClassText = 7 +}; + +/** + * @ingroup livestatus + */ +class LogUtility +{ + +public: + static void CreateLogIndex(const String& path, std::map& index); + static void CreateLogIndexFileHandler(const String& path, std::map& index); + static void CreateLogCache(std::map index, Table *table, const unsigned int& from, const unsigned int& until); + static Dictionary::Ptr GetAttributes(const String& text); + +private: + LogUtility(void); +}; + +} + +#endif /* LOGUTILITY_H */ diff --git a/components/livestatus/statehisttable.cpp b/components/livestatus/statehisttable.cpp index 908f810b9..506e81ed1 100644 --- a/components/livestatus/statehisttable.cpp +++ b/components/livestatus/statehisttable.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "livestatus/statehisttable.h" +#include "livestatus/logutility.h" #include "livestatus/hoststable.h" #include "livestatus/servicestable.h" #include "livestatus/contactstable.h" @@ -56,209 +57,169 @@ StateHistTable::StateHistTable(const String& compat_log_path, const unsigned lon m_TimeUntil = until; /* create log file index */ - CreateLogIndex(compat_log_path); + LogUtility::CreateLogIndex(compat_log_path, m_LogFileIndex); - /* m_LogFileIndex map tells which log files are involved ordered by their start timestamp */ - unsigned long ts; - 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); - String log_line = String(line); - type.Trim(); - options.Trim(); - log_line.Trim(); - - Dictionary::Ptr bag = GetStateHistAttributes(type, options); - - /* no attributes available - invalid log line */ - if (!bag) { - //Log(LogDebug, "livestatus", "Skipping invalid statehist line: '" + log_line + "'."); - continue; - } - - String host_name = bag->Get("host_name"); - String service_description = bag->Get("service_description"); - unsigned long state = bag->Get("state"); - int log_class = bag->Get("log_class"); - int log_type = bag->Get("log_type"); - String state_type = bag->Get("state_type"); //SOFT, HARD, STARTED, STOPPED, ... - - Service::Ptr state_hist_service; - /* host alert == get service check */ - if (service_description.IsEmpty()) { - Host::Ptr state_host = Host::GetByName(host_name); - state_hist_service = state_host->GetCheckService(); - } else { - /* assign service ptr as key */ - state_hist_service = Service::GetByNamePair(host_name, service_description); - } - - /* invalid log line for state history */ - if (!state_hist_service) { - //Log(LogDebug, "livestatus", "Skipping invalid statehist line: '" + log_line + "'."); - continue; - } - - Array::Ptr state_hist_service_states; - Dictionary::Ptr state_hist_bag; - unsigned long query_part = until - from; - - /* insert new service states array with values if not existing */ - if (m_ServicesCache.find(state_hist_service) == m_ServicesCache.end()) { - - /* create new values */ - state_hist_service_states = make_shared(); - state_hist_bag = make_shared(); - - state_hist_bag->Set("host_name", state_hist_service->GetHost()->GetName()); - state_hist_bag->Set("service_description", state_hist_service->GetShortName()); - state_hist_bag->Set("state", state); - state_hist_bag->Set("in_downtime", 0); - state_hist_bag->Set("in_host_downtime", 0); - state_hist_bag->Set("in_notification_period", 1); // assume "always" - state_hist_bag->Set("is_flapping", 0); - state_hist_bag->Set("time", time); - state_hist_bag->Set("lineno", lineno); - state_hist_bag->Set("log_output", log_line); /* complete line */ - state_hist_bag->Set("from", time); /* starting at current timestamp */ - state_hist_bag->Set("until", time); /* will be updated later on state change */ - state_hist_bag->Set("query_part", query_part); /* required for _part calculations */ - - state_hist_service_states->Add(state_hist_bag); - - Log(LogDebug, "livestatus", "statehist: Adding new service '" + state_hist_service->GetName() + "' to services cache."); - } else { - { - boost::mutex::scoped_lock lock(m_Mutex); - state_hist_service_states = m_ServicesCache[state_hist_service]; - state_hist_bag = state_hist_service_states->Get(state_hist_service_states->GetLength()-1); /* fetch latest state from history */ - } - - /* state duration */ - bool gone = state_hist_bag->Get("gone"); /* this requires initial state logging and setting it if not found TODO */ - - /* determine service notifications notification_period and compare against current timestamp */ - bool in_notification_period = true; - String notification_period_name; - BOOST_FOREACH(const Notification::Ptr& notification, state_hist_service->GetNotifications()) { - TimePeriod::Ptr notification_period = notification->GetNotificationPeriod(); - - if (notification_period) { - if (notification_period->IsInside(static_cast(time))) - in_notification_period = true; - else - in_notification_period = false; - - notification_period_name = notification_period->GetName(); // last one wins - } else - in_notification_period = true; // assume "always" - } - - /* check for state changes, flapping & downtime start/end */ - switch (log_type) { - case LogStateHistTypeHostAlert: - case LogStateHistTypeHostInitialState: - case LogStateHistTypeHostCurrentState: - case LogStateHistTypeServiceAlert: - case LogStateHistTypeServiceInitialState: - case LogStateHistTypeServiceCurrentState: - if (state != state_hist_bag->Get("state")) { - /* 1. seal old state_hist_bag */ - state_hist_bag->Set("until", time); /* add until record for duration calculation */ - - /* 2. add new state_hist_bag */ - Dictionary::Ptr state_hist_bag_new = make_shared(); - - state_hist_bag_new->Set("host_name", state_hist_bag->Get("host_name")); - state_hist_bag_new->Set("service_description", state_hist_bag->Get("service_description")); - state_hist_bag_new->Set("state", state); - state_hist_bag_new->Set("in_downtime", state_hist_bag->Get("in_downtime")); // keep value from previous state! - state_hist_bag_new->Set("in_host_downtime", state_hist_bag->Get("in_host_downtime")); // keep value from previous state! - state_hist_bag_new->Set("in_notification_period", (in_notification_period ? 1 : 0)); - state_hist_bag_new->Set("notification_period", notification_period_name); - state_hist_bag_new->Set("is_flapping", state_hist_bag->Get("is_flapping")); // keep value from previous state! - state_hist_bag_new->Set("time", time); - state_hist_bag_new->Set("lineno", lineno); - state_hist_bag_new->Set("log_output", log_line); /* complete line */ - state_hist_bag_new->Set("from", time); /* starting at current timestamp */ - state_hist_bag_new->Set("until", time + 1); /* will be updated later */ - state_hist_bag_new->Set("query_part", query_part); - - state_hist_service_states->Add(state_hist_bag_new); - - Log(LogDebug, "livestatus", "statehist: State change detected for service '" + - state_hist_service->GetName() + "' in '" + log_line + "'."); - } - break; - case LogStateHistTypeHostFlapping: - case LogStateHistTypeServiceFlapping: - if (state_type == "STARTED") - state_hist_bag->Set("is_flapping", 1); - else if (state_type == "STOPPED" || state_type == "DISABLED") - state_hist_bag->Set("is_flapping", 0); - break; - break; - case LogStateHistTypeHostDowntimeAlert: - case LogStateHistTypeServiceDowntimeAlert: - if (state_type == "STARTED") { - state_hist_bag->Set("in_downtime", 1); - if (log_type == LogStateHistTypeHostDowntimeAlert) - state_hist_bag->Set("in_host_downtime", 1); - } - else if (state_type == "STOPPED" || state_type == "CANCELLED") { - state_hist_bag->Set("in_downtime", 0); - if (log_type == LogStateHistTypeHostDowntimeAlert) - state_hist_bag->Set("in_host_downtime", 0); - } - break; - default: - //nothing to update - break; - } - - } - - { - boost::mutex::scoped_lock lock(m_Mutex); - m_ServicesCache[state_hist_service] = state_hist_service_states; - } - - lineno++; - } - - fp.close(); - } + /* generate log cache */ + LogUtility::CreateLogCache(m_LogFileIndex, this, from, until); AddColumns(this); } +void StateHistTable::UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno) +{ + unsigned int time = bag->Get("time"); + String host_name = bag->Get("host_name"); + String service_description = bag->Get("service_description"); + unsigned long state = bag->Get("state"); + int log_class = bag->Get("log_class"); + int log_type = bag->Get("log_type"); + String state_type = bag->Get("state_type"); //SOFT, HARD, STARTED, STOPPED, ... + String log_line = bag->Get("message"); /* use message from log table */ + + Service::Ptr state_hist_service; + + /* host alert == get service check */ + if (service_description.IsEmpty()) { + Host::Ptr state_host = Host::GetByName(host_name); + + if (!state_host) + return; + + state_hist_service = state_host->GetCheckService(); + } else { + /* assign service ptr as key */ + state_hist_service = Service::GetByNamePair(host_name, service_description); + } + + /* invalid log line for state history */ + if (!state_hist_service) + return; + + Array::Ptr state_hist_service_states; + Dictionary::Ptr state_hist_bag; + unsigned long query_part = m_TimeUntil - m_TimeFrom; + + /* insert new service states array with values if not existing */ + if (m_ServicesCache.find(state_hist_service) == m_ServicesCache.end()) { + + /* create new values */ + state_hist_service_states = make_shared(); + state_hist_bag = make_shared(); + + state_hist_bag->Set("host_name", state_hist_service->GetHost()->GetName()); + state_hist_bag->Set("service_description", state_hist_service->GetShortName()); + state_hist_bag->Set("state", state); + state_hist_bag->Set("in_downtime", 0); + state_hist_bag->Set("in_host_downtime", 0); + state_hist_bag->Set("in_notification_period", 1); // assume "always" + state_hist_bag->Set("is_flapping", 0); + state_hist_bag->Set("time", time); + state_hist_bag->Set("lineno", lineno); + state_hist_bag->Set("log_output", log_line); /* complete line */ + state_hist_bag->Set("from", time); /* starting at current timestamp */ + state_hist_bag->Set("until", time); /* will be updated later on state change */ + state_hist_bag->Set("query_part", query_part); /* required for _part calculations */ + + state_hist_service_states->Add(state_hist_bag); + + Log(LogDebug, "livestatus", "statehist: Adding new service '" + state_hist_service->GetName() + "' to services cache."); + } else { + { + boost::mutex::scoped_lock lock(m_Mutex); + state_hist_service_states = m_ServicesCache[state_hist_service]; + state_hist_bag = state_hist_service_states->Get(state_hist_service_states->GetLength()-1); /* fetch latest state from history */ + } + + /* state duration */ + bool gone = state_hist_bag->Get("gone"); /* this requires initial state logging and setting it if not found TODO */ + + /* determine service notifications notification_period and compare against current timestamp */ + bool in_notification_period = true; + String notification_period_name; + BOOST_FOREACH(const Notification::Ptr& notification, state_hist_service->GetNotifications()) { + TimePeriod::Ptr notification_period = notification->GetNotificationPeriod(); + + if (notification_period) { + if (notification_period->IsInside(static_cast(time))) + in_notification_period = true; + else + in_notification_period = false; + + notification_period_name = notification_period->GetName(); // last one wins + } else + in_notification_period = true; // assume "always" + } + + /* check for state changes, flapping & downtime start/end */ + switch (log_type) { + case LogEntryTypeHostAlert: + case LogEntryTypeHostInitialState: + case LogEntryTypeHostCurrentState: + case LogEntryTypeServiceAlert: + case LogEntryTypeServiceInitialState: + case LogEntryTypeServiceCurrentState: + if (state != state_hist_bag->Get("state")) { + /* 1. seal old state_hist_bag */ + state_hist_bag->Set("until", time); /* add until record for duration calculation */ + + /* 2. add new state_hist_bag */ + Dictionary::Ptr state_hist_bag_new = make_shared(); + + state_hist_bag_new->Set("host_name", state_hist_bag->Get("host_name")); + state_hist_bag_new->Set("service_description", state_hist_bag->Get("service_description")); + state_hist_bag_new->Set("state", state); + state_hist_bag_new->Set("in_downtime", state_hist_bag->Get("in_downtime")); // keep value from previous state! + state_hist_bag_new->Set("in_host_downtime", state_hist_bag->Get("in_host_downtime")); // keep value from previous state! + state_hist_bag_new->Set("in_notification_period", (in_notification_period ? 1 : 0)); + state_hist_bag_new->Set("notification_period", notification_period_name); + state_hist_bag_new->Set("is_flapping", state_hist_bag->Get("is_flapping")); // keep value from previous state! + state_hist_bag_new->Set("time", time); + state_hist_bag_new->Set("lineno", lineno); + state_hist_bag_new->Set("log_output", log_line); /* complete line */ + state_hist_bag_new->Set("from", time); /* starting at current timestamp */ + state_hist_bag_new->Set("until", time + 1); /* will be updated later */ + state_hist_bag_new->Set("query_part", query_part); + + state_hist_service_states->Add(state_hist_bag_new); + + Log(LogDebug, "livestatus", "statehist: State change detected for service '" + + state_hist_service->GetName() + "' in '" + log_line + "'."); + } + break; + case LogEntryTypeHostFlapping: + case LogEntryTypeServiceFlapping: + if (state_type == "STARTED") + state_hist_bag->Set("is_flapping", 1); + else if (state_type == "STOPPED" || state_type == "DISABLED") + state_hist_bag->Set("is_flapping", 0); + break; + break; + case LogEntryTypeHostDowntimeAlert: + case LogEntryTypeServiceDowntimeAlert: + if (state_type == "STARTED") { + state_hist_bag->Set("in_downtime", 1); + if (log_type == LogEntryTypeHostDowntimeAlert) + state_hist_bag->Set("in_host_downtime", 1); + } + else if (state_type == "STOPPED" || state_type == "CANCELLED") { + state_hist_bag->Set("in_downtime", 0); + if (log_type == LogEntryTypeHostDowntimeAlert) + state_hist_bag->Set("in_host_downtime", 0); + } + break; + default: + //nothing to update + break; + } + + } + + { + boost::mutex::scoped_lock lock(m_Mutex); + m_ServicesCache[state_hist_service] = state_hist_service_states; + } +} + void StateHistTable::AddColumns(Table *table, const String& prefix, const Column::ObjectAccessor& objectAccessor) { @@ -514,208 +475,4 @@ Value StateHistTable::DurationPartUnmonitoredAccessor(const Value& row) return (state_hist_bag->Get("until") - state_hist_bag->Get("from")) / state_hist_bag->Get("query_part"); return 0; -} - -void StateHistTable::CreateLogIndex(const String& path) -{ - Utility::Glob(path + "/icinga.log", boost::bind(&StateHistTable::CreateLogIndexFileHandler, _1, boost::ref(m_LogFileIndex)), GlobFile); - Utility::Glob(path + "/archives/*.log", boost::bind(&StateHistTable::CreateLogIndexFileHandler, _1, boost::ref(m_LogFileIndex)), GlobFile); -} - -void StateHistTable::CreateLogIndexFileHandler(const String& path, std::map& 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 StateHistTable::GetStateHistAttributes(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 tokens; - boost::algorithm::split(tokens, options, boost::is_any_of(";")); - - /* States - TODO refactor */ - if (boost::algorithm::contains(type, "INITIAL HOST STATE")) { - if (tokens.size() < 5) - return Dictionary::Ptr(); - - log_class = LogStateHistClassState; - log_type = LogStateHistTypeHostInitialState; - - 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")) { - if (tokens.size() < 5) - return Dictionary::Ptr(); - - log_class = LogStateHistClassState; - log_type = LogStateHistTypeHostCurrentState; - - 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")) { - if (tokens.size() < 5) - return Dictionary::Ptr(); - - log_class = LogStateHistClassAlert; - log_type = LogStateHistTypeHostAlert; - - 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")) { - if (tokens.size() < 3) - return Dictionary::Ptr(); - - log_class = LogStateHistClassAlert; - log_type = LogStateHistTypeHostDowntimeAlert; - - host_name = tokens[0]; - state_type = tokens[1]; - comment = tokens[2]; - } - else if (boost::algorithm::contains(type, "HOST FLAPPING ALERT")) { - if (tokens.size() < 3) - return Dictionary::Ptr(); - - log_class = LogStateHistClassAlert; - log_type = LogStateHistTypeHostFlapping; - - host_name = tokens[0]; - state_type = tokens[1]; - comment = tokens[2]; - } - else if (boost::algorithm::contains(type, "INITIAL SERVICE STATE")) { - if (tokens.size() < 6) - return Dictionary::Ptr(); - - log_class = LogStateHistClassState; - log_type = LogStateHistTypeServiceInitialState; - - 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")) { - if (tokens.size() < 6) - return Dictionary::Ptr(); - - log_class = LogStateHistClassState; - log_type = LogStateHistTypeServiceCurrentState; - - 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")) { - if (tokens.size() < 6) - return Dictionary::Ptr(); - - log_class = LogStateHistClassAlert; - log_type = LogStateHistTypeServiceAlert; - - 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")) { - if (tokens.size() < 4) - return Dictionary::Ptr(); - - log_class = LogStateHistClassAlert; - log_type = LogStateHistTypeServiceDowntimeAlert; - - host_name = tokens[0]; - service_description = tokens[1]; - state_type = tokens[2]; - comment = tokens[3]; - } - else if (boost::algorithm::contains(type, "SERVICE FLAPPING ALERT")) { - if (tokens.size() < 4) - return Dictionary::Ptr(); - - log_class = LogStateHistClassAlert; - log_type = LogStateHistTypeServiceFlapping; - - host_name = tokens[0]; - service_description = tokens[1]; - state_type = tokens[2]; - comment = tokens[3]; - } - else if (boost::algorithm::contains(type, "TIMEPERIOD TRANSITION")) { - if (tokens.size() < 4) - return Dictionary::Ptr(); - - log_class = LogStateHistClassState; - log_type = LogStateHistTypeTimeperiodTransition; - - host_name = tokens[0]; - service_description = tokens[1]; - state_type = tokens[2]; - comment = tokens[3]; - } - else - return Dictionary::Ptr(); - - Dictionary::Ptr bag = make_shared(); - - bag->Set("log_class", log_class); /* 0 is the default if not populated */ - bag->Set("log_type", log_type); - 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; -} +} \ No newline at end of file diff --git a/components/livestatus/statehisttable.h b/components/livestatus/statehisttable.h index 5c8bf4987..91bff7ae6 100644 --- a/components/livestatus/statehisttable.h +++ b/components/livestatus/statehisttable.h @@ -29,36 +29,6 @@ using namespace icinga; namespace icinga { -enum LogStateHistType { - LogStateHistTypeHostAlert, - LogStateHistTypeHostDowntimeAlert, - LogStateHistTypeHostFlapping, - LogStateHistTypeHostNotification, - LogStateHistTypeHostInitialState, - LogStateHistTypeHostCurrentState, - LogStateHistTypeServiceAlert, - LogStateHistTypeServiceDowntimeAlert, - LogStateHistTypeServiceFlapping, - LogStateHistTypeServiceNotification, - LogStateHistTypeServiceInitialState, - LogStateHistTypeServiceCurrentState, - LogStateHistTypeTimeperiodTransition, - LogStateHistTypeVersion, - LogStateHistTypeInitialStates, - LogStateHistTypeProgramStarting -}; - -enum LogStateHistClass { - LogStateHistClassInfo = 0, - LogStateHistClassAlert = 1, - LogStateHistClassProgram = 2, - LogStateHistClassNotification = 3, - LogStateHistClassPassive = 4, - LogStateHistClassCommand = 5, - LogStateHistClassState = 6, - LogStateHistClassText = 7 -}; - /** * @ingroup livestatus */ @@ -74,6 +44,8 @@ public: virtual String GetName(void) const; + void UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno); + protected: virtual void FetchRows(const AddRowFunction& addRowFn); @@ -108,16 +80,11 @@ protected: static Value DurationPartUnmonitoredAccessor(const Value& row); private: - std::map m_LogFileIndex; + std::map m_LogFileIndex; std::map m_ServicesCache; - unsigned long m_TimeFrom; - unsigned long m_TimeUntil; + unsigned int m_TimeFrom; + unsigned int m_TimeUntil; boost::mutex m_Mutex; - - void CreateLogIndex(const String& path); - static void CreateLogIndexFileHandler(const String& path, std::map& index); - void GetLogStateHistClassType(const String& text, int& log_class, int& log_type); - Dictionary::Ptr GetStateHistAttributes(const String& type, const String& options); }; } diff --git a/components/livestatus/table.cpp b/components/livestatus/table.cpp index bd476d3fc..493317438 100644 --- a/components/livestatus/table.cpp +++ b/components/livestatus/table.cpp @@ -146,3 +146,8 @@ Value Table::EmptyDictionaryAccessor(const Value&) { return make_shared(); } + +void Table::UpdateLogCache(const Dictionary::Ptr&, int, int) +{ + /* does nothing by default */ +} diff --git a/components/livestatus/table.h b/components/livestatus/table.h index dd5a5abdb..dc76e6d27 100644 --- a/components/livestatus/table.h +++ b/components/livestatus/table.h @@ -50,6 +50,8 @@ public: Column GetColumn(const String& name) const; std::vector GetColumnNames(void) const; + virtual void UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno); + protected: Table(void); From 79f5618ebaa1fbe899780b73b2b43544ac54ab42 Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Tue, 17 Dec 2013 18:18:13 +0100 Subject: [PATCH 3/4] Use std::string::find() in String::Contains(). Refs #5355 --- lib/base/qstring.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/base/qstring.cpp b/lib/base/qstring.cpp index 24cc970df..85694708b 100644 --- a/lib/base/qstring.cpp +++ b/lib/base/qstring.cpp @@ -183,7 +183,7 @@ void String::Trim(void) bool String::Contains(const String& str) const { - return boost::algorithm::contains(m_Data, str); + return (m_Data.find(str) != std::string::npos); } void String::swap(String& str) From 9f82274fceba542c6d9bd0efb825acdbf3731c59 Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Tue, 17 Dec 2013 18:33:17 +0100 Subject: [PATCH 4/4] Fix some more compiler warnings. Refs #5348 --- components/livestatus/statehisttable.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/livestatus/statehisttable.cpp b/components/livestatus/statehisttable.cpp index 506e81ed1..d233803c9 100644 --- a/components/livestatus/statehisttable.cpp +++ b/components/livestatus/statehisttable.cpp @@ -71,7 +71,6 @@ void StateHistTable::UpdateLogCache(const Dictionary::Ptr& bag, int line_count, String host_name = bag->Get("host_name"); String service_description = bag->Get("service_description"); unsigned long state = bag->Get("state"); - int log_class = bag->Get("log_class"); int log_type = bag->Get("log_type"); String state_type = bag->Get("state_type"); //SOFT, HARD, STARTED, STOPPED, ... String log_line = bag->Get("message"); /* use message from log table */ @@ -131,7 +130,6 @@ void StateHistTable::UpdateLogCache(const Dictionary::Ptr& bag, int line_count, } /* state duration */ - bool gone = state_hist_bag->Get("gone"); /* this requires initial state logging and setting it if not found TODO */ /* determine service notifications notification_period and compare against current timestamp */ bool in_notification_period = true;