diff --git a/components/livestatus/CMakeLists.txt b/components/livestatus/CMakeLists.txt index 0c3cc0b0d..3d34d369a 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 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) +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 historytable.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/historytable.cpp b/components/livestatus/historytable.cpp new file mode 100644 index 000000000..8f4ffc90b --- /dev/null +++ b/components/livestatus/historytable.cpp @@ -0,0 +1,27 @@ +/****************************************************************************** + * 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/historytable.h" + +using namespace icinga; + +void HistoryTable::UpdateLogEntries(const Dictionary::Ptr&, int, int, const AddRowFunction&) +{ + /* does nothing by default */ +} diff --git a/components/livestatus/historytable.h b/components/livestatus/historytable.h new file mode 100644 index 000000000..58f07c838 --- /dev/null +++ b/components/livestatus/historytable.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * 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 HISTORYTABLE_H +#define HISTORYTABLE_H + +#include "livestatus/table.h" +#include "base/dictionary.h" + +namespace icinga +{ + + +/** + * @ingroup livestatus + */ +class HistoryTable : public Table +{ +public: + virtual void UpdateLogEntries(const Dictionary::Ptr& bag, int line_count, int lineno, const AddRowFunction& addRowFn); +}; + +} + +#endif /* HISTORYTABLE_H */ diff --git a/components/livestatus/logtable.cpp b/components/livestatus/logtable.cpp index 4a745b930..43bb70674 100644 --- a/components/livestatus/logtable.cpp +++ b/components/livestatus/logtable.cpp @@ -47,33 +47,17 @@ using namespace icinga; -LogTable::LogTable(const String& compat_log_path, const unsigned long& from, const unsigned long& until) +LogTable::LogTable(const String& compat_log_path, time_t from, time_t until) { - Log(LogInformation, "livestatus", "Pre-selecting log file from " + Convert::ToString(from) + " until " + Convert::ToString(until)); - - /* store from & until for FetchRows */ + /* store attributes for FetchRows */ m_TimeFrom = from; m_TimeUntil = until; - - /* create log file index */ - LogUtility::CreateLogIndex(compat_log_path, m_LogFileIndex); - - /* generate log cache */ - LogUtility::CreateLogCache(m_LogFileIndex, this, from, until); + m_CompatLogPath = compat_log_path; 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) @@ -107,12 +91,22 @@ String LogTable::GetName(void) const void LogTable::FetchRows(const AddRowFunction& addRowFn) { - unsigned long line_count; + Log(LogInformation, "livestatus", "Pre-selecting log file from " + Convert::ToString(m_TimeFrom) + " until " + Convert::ToString(m_TimeUntil)); - BOOST_FOREACH(boost::tie(line_count, boost::tuples::ignore), m_RowsCache) { - /* pass a dictionary with "line_count" as key */ - addRowFn(m_RowsCache[line_count]); - } + /* create log file index */ + LogUtility::CreateLogIndex(m_CompatLogPath, m_LogFileIndex); + + /* generate log cache */ + LogUtility::CreateLogCache(m_LogFileIndex, this, m_TimeFrom, m_TimeUntil, addRowFn); +} + +/* gets called in LogUtility::CreateLogCache */ +void LogTable::UpdateLogEntries(const Dictionary::Ptr& log_entry_attrs, int line_count, int lineno, const AddRowFunction& addRowFn) +{ + /* additional attributes only for log table */ + log_entry_attrs->Set("lineno", lineno); + + addRowFn(log_entry_attrs); } Object::Ptr LogTable::HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor) diff --git a/components/livestatus/logtable.h b/components/livestatus/logtable.h index 7aec5b891..b71e12396 100644 --- a/components/livestatus/logtable.h +++ b/components/livestatus/logtable.h @@ -20,7 +20,7 @@ #ifndef LOGTABLE_H #define LOGTABLE_H -#include "livestatus/table.h" +#include "livestatus/historytable.h" #include using namespace icinga; @@ -31,19 +31,19 @@ namespace icinga /** * @ingroup livestatus */ -class LogTable : public Table +class LogTable : public HistoryTable { public: DECLARE_PTR_TYPEDEFS(LogTable); - LogTable(const String& compat_log_path, const unsigned long& from, const unsigned long& until); + LogTable(const String& compat_log_path, time_t from, time_t until); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const; - void UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno); + void UpdateLogEntries(const Dictionary::Ptr& log_entry_attrs, int line_count, int lineno, const AddRowFunction& addRowFn); protected: virtual void FetchRows(const AddRowFunction& addRowFn); @@ -70,11 +70,11 @@ protected: static Value CommandNameAccessor(const Value& row); private: - std::map m_LogFileIndex; - std::map m_RowsCache; - unsigned int m_TimeFrom; - unsigned int m_TimeUntil; - boost::mutex m_Mutex; + std::map m_LogFileIndex; + std::map m_RowsCache; + time_t m_TimeFrom; + time_t m_TimeUntil; + String m_CompatLogPath; }; } diff --git a/components/livestatus/logutility.cpp b/components/livestatus/logutility.cpp index 3115ae2c0..7ace7f79b 100644 --- a/components/livestatus/logutility.cpp +++ b/components/livestatus/logutility.cpp @@ -38,13 +38,13 @@ using namespace icinga; -void LogUtility::CreateLogIndex(const String& path, std::map& index) +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) +void LogUtility::CreateLogIndexFileHandler(const String& path, std::map& index) { std::ifstream stream; stream.open(path.CStr(), std::ifstream::in); @@ -64,7 +64,7 @@ void LogUtility::CreateLogIndexFileHandler(const String& path, std::map index, Table *table, - const unsigned int& from, const unsigned int& until) +void LogUtility::CreateLogCache(std::map index, HistoryTable *table, + time_t from, time_t until, const AddRowFunction& addRowFn) { - if (!table) - return; + ASSERT(table); /* m_LogFileIndex map tells which log files are involved ordered by their start timestamp */ unsigned int ts; @@ -101,15 +100,15 @@ void LogUtility::CreateLogCache(std::map index, Table *tab if (line.empty()) continue; /* Ignore empty lines */ - Dictionary::Ptr bag = LogUtility::GetAttributes(line); + Dictionary::Ptr log_entry_attrs = LogUtility::GetAttributes(line); /* no attributes available - invalid log line */ - if (!bag) { + if (!log_entry_attrs) { Log(LogDebug, "livestatus", "Skipping invalid log line: '" + line + "'."); continue; } - table->UpdateLogCache(bag, line_count, lineno); + table->UpdateLogEntries(log_entry_attrs, line_count, lineno, addRowFn); line_count++; lineno++; @@ -119,8 +118,6 @@ void LogUtility::CreateLogCache(std::map index, Table *tab } } - - Dictionary::Ptr LogUtility::GetAttributes(const String& text) { Dictionary::Ptr bag = make_shared(); @@ -155,7 +152,6 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text) 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")) { @@ -182,8 +178,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text) } return bag; - } - else if (type.Contains("HOST DOWNTIME ALERT") || + } else if (type.Contains("HOST DOWNTIME ALERT") || type.Contains("HOST FLAPPING ALERT")) { if (tokens.size() < 3) return bag; @@ -201,9 +196,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text) } return bag; - } - /* Service States */ - else if (type.Contains("INITIAL SERVICE STATE") || + } else if (type.Contains("INITIAL SERVICE STATE") || type.Contains("CURRENT SERVICE STATE") || type.Contains("SERVICE ALERT")) { if (tokens.size() < 6) @@ -230,8 +223,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text) } return bag; - } - else if (type.Contains("SERVICE DOWNTIME ALERT") || + } else if (type.Contains("SERVICE DOWNTIME ALERT") || type.Contains("SERVICE FLAPPING ALERT")) { if (tokens.size() < 4) return bag; @@ -250,9 +242,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text) } return bag; - } - /* Timeperiods */ - else if (type.Contains("TIMEPERIOD TRANSITION")) { + } else if (type.Contains("TIMEPERIOD TRANSITION")) { if (tokens.size() < 4) return bag; @@ -263,43 +253,38 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text) bag->Set("service_description", tokens[1]); bag->Set("state_type", tokens[2]); bag->Set("comment", tokens[3]); - } - /* Notifications */ - else if (type.Contains("HOST NOTIFICATION")) { + } 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_type", tokens[2].CStr()); bag->Set("state", Service::StateFromString(tokens[3])); - bag->Set("command_name", atoi(tokens[4].CStr())); + bag->Set("command_name", tokens[4]); bag->Set("plugin_output", tokens[5]); bag->Set("log_class", LogEntryClassNotification); bag->Set("log_type", LogEntryTypeHostNotification); return bag; - } - else if (type.Contains("SERVICE NOTIFICATION")) { + } 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_type", tokens[3].CStr()); bag->Set("state", Service::StateFromString(tokens[4])); - bag->Set("command_name", atoi(tokens[5].CStr())); + bag->Set("command_name", tokens[5]); 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")) { + } else if (type.Contains("PASSIVE HOST CHECK")) { if (tokens.size() < 3) return bag; @@ -310,8 +295,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text) bag->Set("log_class", LogEntryClassPassive); return bag; - } - else if (type.Contains("PASSIVE SERVICE CHECK")) { + } else if (type.Contains("PASSIVE SERVICE CHECK")) { if (tokens.size() < 4) return bag; @@ -323,28 +307,22 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text) bag->Set("log_class", LogEntryClassPassive); return bag; - } - /* External Command */ - else if (type.Contains("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")) { + } 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")) { + } 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=")) { + } else if (type.Contains("starting... (PID=")) { bag->Set("log_class", LogEntryClassProgram); bag->Set("log_type", LogEntryTypeProgramStarting); diff --git a/components/livestatus/logutility.h b/components/livestatus/logutility.h index b5d44d266..9e92afc64 100644 --- a/components/livestatus/logutility.h +++ b/components/livestatus/logutility.h @@ -20,8 +20,7 @@ #ifndef LOGUTILITY_H #define LOGUTILITY_H -#include "livestatus/table.h" -#include +#include "livestatus/historytable.h" using namespace icinga; @@ -65,9 +64,9 @@ 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 void CreateLogIndex(const String& path, std::map& index); + static void CreateLogIndexFileHandler(const String& path, std::map& index); + static void CreateLogCache(std::map index, HistoryTable *table, time_t from, time_t until, const AddRowFunction& addRowFn); static Dictionary::Ptr GetAttributes(const String& text); private: diff --git a/components/livestatus/statehisttable.cpp b/components/livestatus/statehisttable.cpp index d233803c9..0eca997cb 100644 --- a/components/livestatus/statehisttable.cpp +++ b/components/livestatus/statehisttable.cpp @@ -48,32 +48,25 @@ using namespace icinga; -StateHistTable::StateHistTable(const String& compat_log_path, const unsigned long& from, const unsigned long& until) +StateHistTable::StateHistTable(const String& compat_log_path, time_t from, time_t until) { - Log(LogInformation, "livestatus", "Pre-selecting log file from " + Convert::ToString(from) + " until " + Convert::ToString(until)); - - /* store from & until for FetchRows */ + /* store attributes for FetchRows */ m_TimeFrom = from; m_TimeUntil = until; - - /* create log file index */ - LogUtility::CreateLogIndex(compat_log_path, m_LogFileIndex); - - /* generate log cache */ - LogUtility::CreateLogCache(m_LogFileIndex, this, from, until); + m_CompatLogPath = compat_log_path; AddColumns(this); } -void StateHistTable::UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno) +void StateHistTable::UpdateLogEntries(const Dictionary::Ptr& log_entry_attrs, int line_count, int lineno, const AddRowFunction& addRowFn) { - 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_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 */ + unsigned int time = log_entry_attrs->Get("time"); + String host_name = log_entry_attrs->Get("host_name"); + String service_description = log_entry_attrs->Get("service_description"); + unsigned long state = log_entry_attrs->Get("state"); + int log_type = log_entry_attrs->Get("log_type"); + String state_type = log_entry_attrs->Get("state_type"); //SOFT, HARD, STARTED, STOPPED, ... + String log_line = log_entry_attrs->Get("message"); /* use message from log table */ Service::Ptr state_hist_service; @@ -123,11 +116,8 @@ void StateHistTable::UpdateLogCache(const Dictionary::Ptr& bag, int line_count, 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_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 */ @@ -212,10 +202,9 @@ void StateHistTable::UpdateLogCache(const Dictionary::Ptr& bag, int line_count, } - { - boost::mutex::scoped_lock lock(m_Mutex); - m_ServicesCache[state_hist_service] = state_hist_service_states; - } + m_ServicesCache[state_hist_service] = state_hist_service_states; + + /* TODO find a way to directly call addRowFn() - right now m_ServicesCache depends on historical lines ("already seen service") */ } void StateHistTable::AddColumns(Table *table, const String& prefix, @@ -260,6 +249,14 @@ String StateHistTable::GetName(void) const void StateHistTable::FetchRows(const AddRowFunction& addRowFn) { + Log(LogInformation, "livestatus", "Pre-selecting log file from " + Convert::ToString(m_TimeFrom) + " until " + Convert::ToString(m_TimeUntil)); + + /* create log file index */ + LogUtility::CreateLogIndex(m_CompatLogPath, m_LogFileIndex); + + /* generate log cache */ + LogUtility::CreateLogCache(m_LogFileIndex, this, m_TimeFrom, m_TimeUntil, addRowFn); + Service::Ptr state_hist_service; BOOST_FOREACH(boost::tie(state_hist_service, boost::tuples::ignore), m_ServicesCache) { diff --git a/components/livestatus/statehisttable.h b/components/livestatus/statehisttable.h index 91bff7ae6..388de2bcb 100644 --- a/components/livestatus/statehisttable.h +++ b/components/livestatus/statehisttable.h @@ -21,7 +21,7 @@ #define STATEHISTTABLE_H #include "icinga/service.h" -#include "livestatus/table.h" +#include "livestatus/historytable.h" #include using namespace icinga; @@ -32,19 +32,19 @@ namespace icinga /** * @ingroup livestatus */ -class StateHistTable : public Table +class StateHistTable : public HistoryTable { public: DECLARE_PTR_TYPEDEFS(StateHistTable); - StateHistTable(const String& compat_log_path, const unsigned long& from, const unsigned long& until); + StateHistTable(const String& compat_log_path, time_t from, time_t until); static void AddColumns(Table *table, const String& prefix = String(), const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); virtual String GetName(void) const; - void UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno); + void UpdateLogEntries(const Dictionary::Ptr& log_entry_attrs, int line_count, int lineno, const AddRowFunction& addRowFn); protected: virtual void FetchRows(const AddRowFunction& addRowFn); @@ -80,11 +80,11 @@ protected: static Value DurationPartUnmonitoredAccessor(const Value& row); private: - std::map m_LogFileIndex; + std::map m_LogFileIndex; std::map m_ServicesCache; - unsigned int m_TimeFrom; - unsigned int m_TimeUntil; - boost::mutex m_Mutex; + time_t m_TimeFrom; + time_t m_TimeUntil; + String m_CompatLogPath; }; } diff --git a/components/livestatus/table.cpp b/components/livestatus/table.cpp index 493317438..bd476d3fc 100644 --- a/components/livestatus/table.cpp +++ b/components/livestatus/table.cpp @@ -146,8 +146,3 @@ 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 dc76e6d27..01bb96de1 100644 --- a/components/livestatus/table.h +++ b/components/livestatus/table.h @@ -28,6 +28,8 @@ namespace icinga { +typedef boost::function AddRowFunction; + class Filter; /** @@ -38,8 +40,6 @@ class Table : public Object public: DECLARE_PTR_TYPEDEFS(Table); - typedef boost::function AddRowFunction; - static Table::Ptr GetByName(const String& name, const String& compat_log_path = "", const unsigned long& from = 0, const unsigned long& until = 0); virtual String GetName(void) const = 0; @@ -50,8 +50,6 @@ 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);