Livestatus: Use HistoryTable for log/statehist tables.

Refs 
This commit is contained in:
Michael Friedrich 2013-12-18 16:06:39 +01:00
parent 9a992c026a
commit 9a2153d4e0
11 changed files with 125 additions and 96 deletions

View File

@ -19,7 +19,7 @@ mkclass_target(listener.ti listener.th)
mkembedconfig_target(livestatus-type.conf livestatus-type.cpp) 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) target_link_libraries(livestatus ${Boost_LIBRARIES} base config icinga)

View File

@ -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)
{
/* does nothing by default */
}

View File

@ -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);
};
}
#endif /* HISTORYTABLE_H */

View File

@ -47,7 +47,7 @@
using namespace icinga; 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)); Log(LogInformation, "livestatus", "Pre-selecting log file from " + Convert::ToString(from) + " until " + Convert::ToString(until));
@ -64,15 +64,12 @@ LogTable::LogTable(const String& compat_log_path, const unsigned long& from, con
AddColumns(this); AddColumns(this);
} }
void LogTable::UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno) void LogTable::UpdateLogEntries(const Dictionary::Ptr& log_entry_attrs, int line_count, int lineno)
{ {
/* additional attributes only for log table */ /* additional attributes only for log table */
bag->Set("lineno", lineno); log_entry_attrs->Set("lineno", lineno);
{ m_RowsCache[line_count] = log_entry_attrs;
boost::mutex::scoped_lock lock(m_Mutex);
m_RowsCache[line_count] = bag;
}
} }
void LogTable::AddColumns(Table *table, const String& prefix, void LogTable::AddColumns(Table *table, const String& prefix,

View File

@ -20,7 +20,7 @@
#ifndef LOGTABLE_H #ifndef LOGTABLE_H
#define LOGTABLE_H #define LOGTABLE_H
#include "livestatus/table.h" #include "livestatus/historytable.h"
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
using namespace icinga; using namespace icinga;
@ -31,19 +31,19 @@ namespace icinga
/** /**
* @ingroup livestatus * @ingroup livestatus
*/ */
class LogTable : public Table class LogTable : public HistoryTable
{ {
public: public:
DECLARE_PTR_TYPEDEFS(LogTable); 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(), static void AddColumns(Table *table, const String& prefix = String(),
const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor());
virtual String GetName(void) const; 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);
protected: protected:
virtual void FetchRows(const AddRowFunction& addRowFn); virtual void FetchRows(const AddRowFunction& addRowFn);
@ -70,11 +70,10 @@ protected:
static Value CommandNameAccessor(const Value& row); static Value CommandNameAccessor(const Value& row);
private: private:
std::map<unsigned int, String> m_LogFileIndex; std::map<time_t, String> m_LogFileIndex;
std::map<unsigned int, Dictionary::Ptr> m_RowsCache; std::map<time_t, Dictionary::Ptr> m_RowsCache;
unsigned int m_TimeFrom; time_t m_TimeFrom;
unsigned int m_TimeUntil; time_t m_TimeUntil;
boost::mutex m_Mutex;
}; };
} }

View File

@ -38,13 +38,13 @@
using namespace icinga; using namespace icinga;
void LogUtility::CreateLogIndex(const String& path, std::map<unsigned int, String>& index) void LogUtility::CreateLogIndex(const String& path, std::map<time_t, String>& index)
{ {
Utility::Glob(path + "/icinga.log", boost::bind(&LogUtility::CreateLogIndexFileHandler, _1, boost::ref(index)), GlobFile); 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); 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) void LogUtility::CreateLogIndexFileHandler(const String& path, std::map<time_t, String>& index)
{ {
std::ifstream stream; std::ifstream stream;
stream.open(path.CStr(), std::ifstream::in); stream.open(path.CStr(), std::ifstream::in);
@ -64,7 +64,7 @@ void LogUtility::CreateLogIndexFileHandler(const String& path, std::map<unsigned
/* extract timestamp */ /* extract timestamp */
buffer[11] = 0; buffer[11] = 0;
unsigned int ts_start = atoi(buffer+1); time_t ts_start = atoi(buffer+1);
stream.close(); stream.close();
@ -73,11 +73,10 @@ void LogUtility::CreateLogIndexFileHandler(const String& path, std::map<unsigned
index[ts_start] = path; index[ts_start] = path;
} }
void LogUtility::CreateLogCache(std::map<unsigned int, String> index, Table *table, void LogUtility::CreateLogCache(std::map<time_t, String> index, HistoryTable *table,
const unsigned int& from, const unsigned int& until) time_t from, time_t until)
{ {
if (!table) ASSERT(table);
return;
/* m_LogFileIndex map tells which log files are involved ordered by their start timestamp */ /* m_LogFileIndex map tells which log files are involved ordered by their start timestamp */
unsigned int ts; unsigned int ts;
@ -101,15 +100,15 @@ void LogUtility::CreateLogCache(std::map<unsigned int, String> index, Table *tab
if (line.empty()) if (line.empty())
continue; /* Ignore empty lines */ continue; /* Ignore empty lines */
Dictionary::Ptr bag = LogUtility::GetAttributes(line); Dictionary::Ptr log_entry_attrs = LogUtility::GetAttributes(line);
/* no attributes available - invalid log line */ /* no attributes available - invalid log line */
if (!bag) { if (!log_entry_attrs) {
Log(LogDebug, "livestatus", "Skipping invalid log line: '" + line + "'."); Log(LogDebug, "livestatus", "Skipping invalid log line: '" + line + "'.");
continue; continue;
} }
table->UpdateLogCache(bag, line_count, lineno); table->UpdateLogEntries(log_entry_attrs, line_count, lineno);
line_count++; line_count++;
lineno++; lineno++;
@ -155,7 +154,6 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text)
bag->Set("attempt", 0); bag->Set("attempt", 0);
bag->Set("message", text); /* used as 'message' in log table, and 'log_output' in statehist table */ bag->Set("message", text); /* used as 'message' in log table, and 'log_output' in statehist table */
/* Host States */
if (type.Contains("INITIAL HOST STATE") || if (type.Contains("INITIAL HOST STATE") ||
type.Contains("CURRENT HOST STATE") || type.Contains("CURRENT HOST STATE") ||
type.Contains("HOST ALERT")) { type.Contains("HOST ALERT")) {
@ -182,8 +180,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text)
} }
return bag; return bag;
} } else if (type.Contains("HOST DOWNTIME ALERT") ||
else if (type.Contains("HOST DOWNTIME ALERT") ||
type.Contains("HOST FLAPPING ALERT")) { type.Contains("HOST FLAPPING ALERT")) {
if (tokens.size() < 3) if (tokens.size() < 3)
return bag; return bag;
@ -201,9 +198,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text)
} }
return bag; return bag;
} } else if (type.Contains("INITIAL SERVICE STATE") ||
/* Service States */
else if (type.Contains("INITIAL SERVICE STATE") ||
type.Contains("CURRENT SERVICE STATE") || type.Contains("CURRENT SERVICE STATE") ||
type.Contains("SERVICE ALERT")) { type.Contains("SERVICE ALERT")) {
if (tokens.size() < 6) if (tokens.size() < 6)
@ -230,8 +225,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text)
} }
return bag; return bag;
} } else if (type.Contains("SERVICE DOWNTIME ALERT") ||
else if (type.Contains("SERVICE DOWNTIME ALERT") ||
type.Contains("SERVICE FLAPPING ALERT")) { type.Contains("SERVICE FLAPPING ALERT")) {
if (tokens.size() < 4) if (tokens.size() < 4)
return bag; return bag;
@ -250,9 +244,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text)
} }
return bag; return bag;
} } else if (type.Contains("TIMEPERIOD TRANSITION")) {
/* Timeperiods */
else if (type.Contains("TIMEPERIOD TRANSITION")) {
if (tokens.size() < 4) if (tokens.size() < 4)
return bag; return bag;
@ -263,9 +255,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text)
bag->Set("service_description", tokens[1]); bag->Set("service_description", tokens[1]);
bag->Set("state_type", tokens[2]); bag->Set("state_type", tokens[2]);
bag->Set("comment", tokens[3]); bag->Set("comment", tokens[3]);
} } else if (type.Contains("HOST NOTIFICATION")) {
/* Notifications */
else if (type.Contains("HOST NOTIFICATION")) {
if (tokens.size() < 6) if (tokens.size() < 6)
return bag; return bag;
@ -280,8 +270,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text)
bag->Set("log_type", LogEntryTypeHostNotification); bag->Set("log_type", LogEntryTypeHostNotification);
return bag; return bag;
} } else if (type.Contains("SERVICE NOTIFICATION")) {
else if (type.Contains("SERVICE NOTIFICATION")) {
if (tokens.size() < 7) if (tokens.size() < 7)
return bag; return bag;
@ -297,9 +286,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text)
bag->Set("log_type", LogEntryTypeServiceNotification); bag->Set("log_type", LogEntryTypeServiceNotification);
return bag; return bag;
} } else if (type.Contains("PASSIVE HOST CHECK")) {
/* Passive Checks */
else if (type.Contains("PASSIVE HOST CHECK")) {
if (tokens.size() < 3) if (tokens.size() < 3)
return bag; return bag;
@ -310,8 +297,7 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text)
bag->Set("log_class", LogEntryClassPassive); bag->Set("log_class", LogEntryClassPassive);
return bag; return bag;
} } else if (type.Contains("PASSIVE SERVICE CHECK")) {
else if (type.Contains("PASSIVE SERVICE CHECK")) {
if (tokens.size() < 4) if (tokens.size() < 4)
return bag; return bag;
@ -323,28 +309,22 @@ Dictionary::Ptr LogUtility::GetAttributes(const String& text)
bag->Set("log_class", LogEntryClassPassive); bag->Set("log_class", LogEntryClassPassive);
return bag; return bag;
} } else if (type.Contains("EXTERNAL COMMAND")) {
/* External Command */
else if (type.Contains("EXTERNAL COMMAND")) {
bag->Set("log_class", LogEntryClassCommand); bag->Set("log_class", LogEntryClassCommand);
/* string processing not implemented in 1.x */ /* string processing not implemented in 1.x */
return bag; return bag;
} } else if (type.Contains("LOG VERSION")) {
/* normal text entries */
else if (type.Contains("LOG VERSION")) {
bag->Set("log_class", LogEntryClassProgram); bag->Set("log_class", LogEntryClassProgram);
bag->Set("log_type", LogEntryTypeVersion); bag->Set("log_type", LogEntryTypeVersion);
return bag; return bag;
} } else if (type.Contains("logging initial states")) {
else if (type.Contains("logging initial states")) {
bag->Set("log_class", LogEntryClassProgram); bag->Set("log_class", LogEntryClassProgram);
bag->Set("log_type", LogEntryTypeInitialStates); bag->Set("log_type", LogEntryTypeInitialStates);
return bag; return bag;
} } else if (type.Contains("starting... (PID=")) {
else if (type.Contains("starting... (PID=")) {
bag->Set("log_class", LogEntryClassProgram); bag->Set("log_class", LogEntryClassProgram);
bag->Set("log_type", LogEntryTypeProgramStarting); bag->Set("log_type", LogEntryTypeProgramStarting);

View File

@ -20,8 +20,7 @@
#ifndef LOGUTILITY_H #ifndef LOGUTILITY_H
#define LOGUTILITY_H #define LOGUTILITY_H
#include "livestatus/table.h" #include "livestatus/historytable.h"
#include <boost/thread/mutex.hpp>
using namespace icinga; using namespace icinga;
@ -65,9 +64,9 @@ class LogUtility
{ {
public: public:
static void CreateLogIndex(const String& path, std::map<unsigned int, String>& index); static void CreateLogIndex(const String& path, std::map<time_t, String>& index);
static void CreateLogIndexFileHandler(const String& path, std::map<unsigned int, String>& index); static void CreateLogIndexFileHandler(const String& path, std::map<time_t, String>& index);
static void CreateLogCache(std::map<unsigned int, String> index, Table *table, const unsigned int& from, const unsigned int& until); static void CreateLogCache(std::map<time_t, String> index, HistoryTable *table, time_t from, time_t until);
static Dictionary::Ptr GetAttributes(const String& text); static Dictionary::Ptr GetAttributes(const String& text);
private: private:

View File

@ -48,7 +48,7 @@
using namespace icinga; 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)); Log(LogInformation, "livestatus", "Pre-selecting log file from " + Convert::ToString(from) + " until " + Convert::ToString(until));
@ -65,15 +65,15 @@ StateHistTable::StateHistTable(const String& compat_log_path, const unsigned lon
AddColumns(this); 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)
{ {
unsigned int time = bag->Get("time"); unsigned int time = log_entry_attrs->Get("time");
String host_name = bag->Get("host_name"); String host_name = log_entry_attrs->Get("host_name");
String service_description = bag->Get("service_description"); String service_description = log_entry_attrs->Get("service_description");
unsigned long state = bag->Get("state"); unsigned long state = log_entry_attrs->Get("state");
int log_type = bag->Get("log_type"); int log_type = log_entry_attrs->Get("log_type");
String state_type = bag->Get("state_type"); //SOFT, HARD, STARTED, STOPPED, ... String state_type = log_entry_attrs->Get("state_type"); //SOFT, HARD, STARTED, STOPPED, ...
String log_line = bag->Get("message"); /* use message from log table */ String log_line = log_entry_attrs->Get("message"); /* use message from log table */
Service::Ptr state_hist_service; Service::Ptr state_hist_service;
@ -123,11 +123,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."); Log(LogDebug, "livestatus", "statehist: Adding new service '" + state_hist_service->GetName() + "' to services cache.");
} else { } else {
{
boost::mutex::scoped_lock lock(m_Mutex);
state_hist_service_states = m_ServicesCache[state_hist_service]; 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_bag = state_hist_service_states->Get(state_hist_service_states->GetLength()-1); /* fetch latest state from history */
}
/* state duration */ /* state duration */
@ -212,11 +209,8 @@ 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;
} }
}
void StateHistTable::AddColumns(Table *table, const String& prefix, void StateHistTable::AddColumns(Table *table, const String& prefix,
const Column::ObjectAccessor& objectAccessor) const Column::ObjectAccessor& objectAccessor)

View File

@ -21,7 +21,7 @@
#define STATEHISTTABLE_H #define STATEHISTTABLE_H
#include "icinga/service.h" #include "icinga/service.h"
#include "livestatus/table.h" #include "livestatus/historytable.h"
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
using namespace icinga; using namespace icinga;
@ -32,19 +32,19 @@ namespace icinga
/** /**
* @ingroup livestatus * @ingroup livestatus
*/ */
class StateHistTable : public Table class StateHistTable : public HistoryTable
{ {
public: public:
DECLARE_PTR_TYPEDEFS(StateHistTable); 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(), static void AddColumns(Table *table, const String& prefix = String(),
const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor()); const Column::ObjectAccessor& objectAccessor = Column::ObjectAccessor());
virtual String GetName(void) const; 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);
protected: protected:
virtual void FetchRows(const AddRowFunction& addRowFn); virtual void FetchRows(const AddRowFunction& addRowFn);
@ -80,11 +80,10 @@ protected:
static Value DurationPartUnmonitoredAccessor(const Value& row); static Value DurationPartUnmonitoredAccessor(const Value& row);
private: private:
std::map<unsigned int, String> m_LogFileIndex; std::map<time_t, String> m_LogFileIndex;
std::map<Service::Ptr, Array::Ptr> m_ServicesCache; std::map<Service::Ptr, Array::Ptr> m_ServicesCache;
unsigned int m_TimeFrom; time_t m_TimeFrom;
unsigned int m_TimeUntil; time_t m_TimeUntil;
boost::mutex m_Mutex;
}; };
} }

View File

@ -146,8 +146,3 @@ Value Table::EmptyDictionaryAccessor(const Value&)
{ {
return make_shared<Dictionary>(); return make_shared<Dictionary>();
} }
void Table::UpdateLogCache(const Dictionary::Ptr&, int, int)
{
/* does nothing by default */
}

View File

@ -50,8 +50,6 @@ public:
Column GetColumn(const String& name) const; Column GetColumn(const String& name) const;
std::vector<String> GetColumnNames(void) const; std::vector<String> GetColumnNames(void) const;
virtual void UpdateLogCache(const Dictionary::Ptr& bag, int line_count, int lineno);
protected: protected:
Table(void); Table(void);