]> granicus.if.org Git - icinga2/commitdiff
Livestatus: Refactor historical tables.
authorMichael Friedrich <michael.friedrich@netways.de>
Tue, 17 Dec 2013 11:58:04 +0000 (12:58 +0100)
committerMichael Friedrich <michael.friedrich@netways.de>
Tue, 17 Dec 2013 17:34:05 +0000 (18:34 +0100)
Refs #5351
Refs #5348

components/livestatus/CMakeLists.txt
components/livestatus/logtable.cpp
components/livestatus/logtable.h
components/livestatus/logutility.cpp [new file with mode: 0644]
components/livestatus/logutility.h [new file with mode: 0644]
components/livestatus/statehisttable.cpp
components/livestatus/statehisttable.h
components/livestatus/table.cpp
components/livestatus/table.h

index 69925ca1e51352e9d8835ccc38fcf7aafe90d0c5..0c3cc0b0d3cc2f8d89e141287ce96d026bcdf47b 100644 (file)
@@ -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)
 
index 1493ec3ab2d988826aeb728f8581b388fdb498d4..4a745b93006104cde41cbde84bea45fd13392218 100644 (file)
@@ -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);
-
-       /* 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();
-       }
+       LogUtility::CreateLogIndex(compat_log_path, m_LogFileIndex);
+
+       /* 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<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)), GlobFile);
-       Utility::Glob(path + "/archives/*.log", boost::bind(&LogTable::CreateLogIndexFileHandler, _1, boost::ref(m_LogFileIndex)), GlobFile);
-}
-
-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")) {
-               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<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;
-}
index 7e6f30b154e3aee6b89ec814c90c2dd0ef88c7c5..7aec5b89150fb7cd210d31be2f77733498469ec8 100644 (file)
@@ -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<unsigned long, String> m_LogFileIndex;
-        std::map<unsigned long, Dictionary::Ptr> m_RowsCache;
-        unsigned long m_TimeFrom;
-        unsigned long m_TimeUntil;
+        std::map<unsigned int, String> m_LogFileIndex;
+        std::map<unsigned int, Dictionary::Ptr> 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<unsigned long, String>& 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 (file)
index 0000000..3115ae2
--- /dev/null
@@ -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 <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;
+
+void LogUtility::CreateLogIndex(const String& path, std::map<unsigned int, String>& 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<unsigned int, 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;
+}
+
+void LogUtility::CreateLogCache(std::map<unsigned int, String> 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<Dictionary>();
+
+        /*
+         * [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<String> 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 (file)
index 0000000..b5d44d2
--- /dev/null
@@ -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 <boost/thread/mutex.hpp>
+
+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<unsigned int, String>& index);
+       static void CreateLogIndexFileHandler(const String& path, std::map<unsigned int, String>& index);
+       static void CreateLogCache(std::map<unsigned int, String> index, Table *table, const unsigned int& from, const unsigned int& until);
+       static Dictionary::Ptr GetAttributes(const String& text);
+
+private:
+       LogUtility(void);
+};
+
+}
+
+#endif /* LOGUTILITY_H */
index 908f810b9610baba96df57d51b9fb32d6562d1cb..506e81ed15abd4b0eff443ee12d366a9e14af384 100644 (file)
@@ -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,207 +57,167 @@ StateHistTable::StateHistTable(const String& compat_log_path, const unsigned lon
        m_TimeUntil = until;
 
        /* create log file index */
-       CreateLogIndex(compat_log_path);
-
-       /* 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<Array>();
-                               state_hist_bag = make_shared<Dictionary>();
-
-                               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 */
-                               }
+       LogUtility::CreateLogIndex(compat_log_path, m_LogFileIndex);
 
-                               /* state duration */
-                               bool gone = state_hist_bag->Get("gone"); /* this requires initial state logging and setting it if not found TODO */
+       /* generate log cache */
+       LogUtility::CreateLogCache(m_LogFileIndex, this, from, until);
 
-                               /* 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();
+       AddColumns(this);
+}
 
-                                       if (notification_period) {
-                                               if (notification_period->IsInside(static_cast<double>(time)))
-                                                       in_notification_period = true;
-                                               else
-                                                       in_notification_period = false;
+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 */
 
-                                               notification_period_name = notification_period->GetName(); // last one wins
-                                       } else
-                                               in_notification_period = true; // assume "always"
-                               }
+       Service::Ptr state_hist_service;
 
-                               /* 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<Dictionary>();
-
-                                                       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;
-                               }
+       /* 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<Array>();
+               state_hist_bag = make_shared<Dictionary>();
+
+               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 */
 
-                       {
-                               boost::mutex::scoped_lock lock(m_Mutex);
-                               m_ServicesCache[state_hist_service] = state_hist_service_states;
-                       }
+               /* 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();
 
-                       lineno++;
+                       if (notification_period) {
+                               if (notification_period->IsInside(static_cast<double>(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<Dictionary>();
+
+                                       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;
                }
 
-               fp.close();
        }
 
-       AddColumns(this);
+       {
+               boost::mutex::scoped_lock lock(m_Mutex);
+               m_ServicesCache[state_hist_service] = state_hist_service_states;
+       }
 }
 
 void StateHistTable::AddColumns(Table *table, const String& prefix,
@@ -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<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 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<String> 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<Dictionary>();
-
-       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
index 5c8bf4987fbcd6d53a1b9f7b53996e40d4568beb..91bff7ae635bc307b1ba488c283a43cd4e7e8192 100644 (file)
@@ -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<unsigned long, String> m_LogFileIndex;
+        std::map<unsigned int, String> m_LogFileIndex;
         std::map<Service::Ptr, Array::Ptr> 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<unsigned long, String>& index);
-        void GetLogStateHistClassType(const String& text, int& log_class, int& log_type);
-        Dictionary::Ptr GetStateHistAttributes(const String& type, const String& options);
 };
 
 }
index bd476d3fc1b67e32c89b029a1401b4fb6a8a7bdc..4933174380dc385b940d750fef8c2b2cf630d962 100644 (file)
@@ -146,3 +146,8 @@ Value Table::EmptyDictionaryAccessor(const Value&)
 {
        return make_shared<Dictionary>();
 }
+
+void Table::UpdateLogCache(const Dictionary::Ptr&, int, int)
+{
+       /* does nothing by default */
+}
index dd5a5abdb101c562ccc6d7079703c9efe2221623..dc76e6d270c62624361fd4abca9274ae87ecd595 100644 (file)
@@ -50,6 +50,8 @@ public:
        Column GetColumn(const String& name) const;
        std::vector<String> GetColumnNames(void) const;
 
+        virtual void UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno);
+
 protected:
        Table(void);