mirror of https://github.com/Icinga/icinga2.git
parent
0fb55060d2
commit
6455ef6b0a
|
@ -1,6 +1,6 @@
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Icinga 2 *
|
* Icinga 2 *
|
||||||
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
|
* Copyright (C) 2012-2015 Icinga Development Team (https://www.icinga.org) *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or *
|
* This program is free software; you can redistribute it and/or *
|
||||||
* modify it under the terms of the GNU General Public License *
|
* modify it under the terms of the GNU General Public License *
|
||||||
|
@ -27,9 +27,7 @@
|
||||||
#include "base/json.hpp"
|
#include "base/json.hpp"
|
||||||
#include "base/objectlock.hpp"
|
#include "base/objectlock.hpp"
|
||||||
#include "base/convert.hpp"
|
#include "base/convert.hpp"
|
||||||
|
|
||||||
#include "config/configitembuilder.hpp"
|
#include "config/configitembuilder.hpp"
|
||||||
|
|
||||||
#include <boost/circular_buffer.hpp>
|
#include <boost/circular_buffer.hpp>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
@ -174,20 +172,21 @@ bool TroubleshootCollectCommand::ConfigInfo(InfoLog& log, const boost::program_o
|
||||||
|
|
||||||
InfoLogLine(log) << "A collection of important configuration files follows, please make sure to remove any sensitive data such as credentials, internal company names, etc";
|
InfoLogLine(log) << "A collection of important configuration files follows, please make sure to remove any sensitive data such as credentials, internal company names, etc";
|
||||||
if (!PrintConf(log, Application::GetSysconfDir() + "/icinga2/icinga2.conf")) {
|
if (!PrintConf(log, Application::GetSysconfDir() + "/icinga2/icinga2.conf")) {
|
||||||
InfoLogLine(log, LogWarning) << "icinga2.conf not found, therefore skipping validation.\n"
|
InfoLogLine(log, LogWarning)
|
||||||
|
<< "icinga2.conf not found, therefore skipping validation.\n"
|
||||||
<< "If you are using an icinga2.conf somewhere but the default path please validate it via 'icinga2 daemon -C -c \"path\to/icinga2.conf\"'\n"
|
<< "If you are using an icinga2.conf somewhere but the default path please validate it via 'icinga2 daemon -C -c \"path\to/icinga2.conf\"'\n"
|
||||||
<< "and provide it with your support request.";
|
<< "and provide it with your support request.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PrintConf(log, Application::GetSysconfDir() + "/icinga2/zones.conf")) {
|
if (!PrintConf(log, Application::GetSysconfDir() + "/icinga2/zones.conf")) {
|
||||||
InfoLogLine(log, LogWarning) << "zones.conf not found.\n"
|
InfoLogLine(log, LogWarning)
|
||||||
|
<< "zones.conf not found.\n"
|
||||||
<< "If you are using a zones.conf somewhere but the default path please provide it with your support request";
|
<< "If you are using a zones.conf somewhere but the default path please provide it with your support request";
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*Print the last *numLines* of *file* to *os* */
|
/*Print the last *numLines* of *file* to *os* */
|
||||||
int TroubleshootCollectCommand::Tail(const String& file, int numLines, InfoLog& log)
|
int TroubleshootCollectCommand::Tail(const String& file, int numLines, InfoLog& log)
|
||||||
{
|
{
|
||||||
|
@ -208,11 +207,16 @@ int TroubleshootCollectCommand::Tail(const String& file, int numLines, InfoLog&
|
||||||
if (lines < numLines)
|
if (lines < numLines)
|
||||||
numLines = lines;
|
numLines = lines;
|
||||||
|
|
||||||
|
for (int k = 0; k < numLines; k++) {
|
||||||
|
InfoLogLine(log)
|
||||||
|
<< '\t' << ringBuf[k];
|
||||||
|
}
|
||||||
|
|
||||||
for (int k = 0; k < numLines; k++)
|
|
||||||
InfoLogLine(log) << '\t' << ringBuf[k];
|
|
||||||
text.close();
|
text.close();
|
||||||
InfoLogLine(log) << "[end: '" << file << "' line: " << lines << ']';
|
|
||||||
|
InfoLogLine(log)
|
||||||
|
<< "[end: '" << file << "' line: " << lines << ']';
|
||||||
|
|
||||||
return numLines;
|
return numLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,9 +226,10 @@ bool TroubleshootCollectCommand::CheckFeatures(InfoLog& log)
|
||||||
std::vector<String> disabled_features;
|
std::vector<String> disabled_features;
|
||||||
std::vector<String> enabled_features;
|
std::vector<String> enabled_features;
|
||||||
|
|
||||||
if (!FeatureUtility::GetFeatures(disabled_features, true)
|
if (!FeatureUtility::GetFeatures(disabled_features, true) ||
|
||||||
|| !FeatureUtility::GetFeatures(enabled_features, false)) {
|
!FeatureUtility::GetFeatures(enabled_features, false)) {
|
||||||
InfoLogLine(log, LogCritical) << "Failed to collect enabled and/or disabled features. Check\n"
|
InfoLogLine(log, LogCritical)
|
||||||
|
<< "Failed to collect enabled and/or disabled features. Check\n"
|
||||||
<< FeatureUtility::GetFeaturesAvailablePath() << '\n'
|
<< FeatureUtility::GetFeaturesAvailablePath() << '\n'
|
||||||
<< FeatureUtility::GetFeaturesEnabledPath();
|
<< FeatureUtility::GetFeaturesEnabledPath();
|
||||||
return false;
|
return false;
|
||||||
|
@ -235,7 +240,8 @@ bool TroubleshootCollectCommand::CheckFeatures(InfoLog& log)
|
||||||
BOOST_FOREACH(const String feature, enabled_features)
|
BOOST_FOREACH(const String feature, enabled_features)
|
||||||
features->Set(feature, true);
|
features->Set(feature, true);
|
||||||
|
|
||||||
InfoLogLine(log) << "Enabled features:\n\t" << boost::algorithm::join(enabled_features, " ") << '\n'
|
InfoLogLine(log)
|
||||||
|
<< "Enabled features:\n\t" << boost::algorithm::join(enabled_features, " ") << '\n'
|
||||||
<< "Disabled features:\n\t" << boost::algorithm::join(disabled_features, " ") << '\n';
|
<< "Disabled features:\n\t" << boost::algorithm::join(disabled_features, " ") << '\n';
|
||||||
|
|
||||||
if (!features->Get("checker").ToBool())
|
if (!features->Get("checker").ToBool())
|
||||||
|
@ -244,6 +250,7 @@ bool TroubleshootCollectCommand::CheckFeatures(InfoLog& log)
|
||||||
InfoLogLine(log, LogWarning) << "mainlog is disabled, please activate it and rerun icinga2";
|
InfoLogLine(log, LogWarning) << "mainlog is disabled, please activate it and rerun icinga2";
|
||||||
if (!features->Get("debuglog").ToBool())
|
if (!features->Get("debuglog").ToBool())
|
||||||
InfoLogLine(log, LogWarning) << "debuglog is disabled, please activate it and rerun icinga2";
|
InfoLogLine(log, LogWarning) << "debuglog is disabled, please activate it and rerun icinga2";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,36 +278,44 @@ bool TroubleshootCollectCommand::PrintCrashReports(InfoLog& log)
|
||||||
String bestFilename;
|
String bestFilename;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Utility::Glob(spath,
|
Utility::Glob(spath, boost::bind(&GetLatestReport, _1, boost::ref(bestTimestamp),
|
||||||
boost::bind(&GetLatestReport, _1, boost::ref(bestTimestamp), boost::ref(bestFilename)),
|
boost::ref(bestFilename)), GlobFile);
|
||||||
GlobFile);
|
|
||||||
}
|
}
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
catch (win32_error &ex) {
|
catch (win32_error &ex) {
|
||||||
if (int const * err = boost::get_error_info<errinfo_win32_error>(ex)) {
|
if (int const * err = boost::get_error_info<errinfo_win32_error>(ex)) {
|
||||||
if (*err != 3) {//Error code for path does not exist
|
if (*err != 3) {//Error code for path does not exist
|
||||||
InfoLogLine(log, LogWarning) << Application::GetLocalStateDir() << "/log/icinga2/crash/ does not exist";
|
InfoLogLine(log, LogWarning)
|
||||||
|
<< Application::GetLocalStateDir() << "/log/icinga2/crash/ does not exist";
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InfoLogLine(log, LogWarning) << "Error printing crash reports";
|
InfoLogLine(log, LogWarning)
|
||||||
|
<< "Error printing crash reports";
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
catch (...) {
|
catch (...) {
|
||||||
InfoLogLine(log, LogWarning) << "Error printing crash reports.\nDoes "
|
InfoLogLine(log, LogWarning)
|
||||||
|
<< "Error printing crash reports.\nDoes "
|
||||||
<< Application::GetLocalStateDir() << "/log/icinga2/crash/ exist?";
|
<< Application::GetLocalStateDir() << "/log/icinga2/crash/ exist?";
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif /*_WIN32*/
|
#endif /*_WIN32*/
|
||||||
|
|
||||||
if (!bestTimestamp)
|
if (!bestTimestamp)
|
||||||
InfoLogLine(log) << "No crash logs found in " << Application::GetLocalStateDir().CStr() << "/log/icinga2/crash/";
|
InfoLogLine(log)
|
||||||
|
<< "No crash logs found in " << Application::GetLocalStateDir().CStr() << "/log/icinga2/crash/";
|
||||||
else {
|
else {
|
||||||
InfoLogLine(log) << "Latest crash report is from " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", Utility::GetTime())
|
InfoLogLine(log)
|
||||||
|
<< "Latest crash report is from " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", Utility::GetTime())
|
||||||
<< "\nFile: " << bestFilename;
|
<< "\nFile: " << bestFilename;
|
||||||
Tail(bestFilename, 20, log);
|
Tail(bestFilename, 20, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,11 +328,17 @@ bool TroubleshootCollectCommand::PrintConf(InfoLog& log, const String& path)
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
||||||
InfoLogLine(log) << "\n[begin: '" << path << "']";
|
InfoLogLine(log)
|
||||||
|
<< "\n[begin: '" << path << "']";
|
||||||
|
|
||||||
while (std::getline(text, line)) {
|
while (std::getline(text, line)) {
|
||||||
InfoLogLine(log) << '\t' << line;
|
InfoLogLine(log)
|
||||||
|
<< '\t' << line;
|
||||||
}
|
}
|
||||||
InfoLogLine(log) << "\n[end: '" << path << "']";
|
|
||||||
|
InfoLogLine(log)
|
||||||
|
<< "\n[end: '" << path << "']";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,19 +350,22 @@ bool TroubleshootCollectCommand::CheckConfig(void)
|
||||||
Utility::LoadExtensionLibrary("icinga");
|
Utility::LoadExtensionLibrary("icinga");
|
||||||
std::vector<std::string> configs;
|
std::vector<std::string> configs;
|
||||||
configs.push_back(Application::GetSysconfDir() + "/icinga2/icinga2.conf");
|
configs.push_back(Application::GetSysconfDir() + "/icinga2/icinga2.conf");
|
||||||
|
|
||||||
return DaemonUtility::ValidateConfigFiles(configs, Application::GetObjectsPath());
|
return DaemonUtility::ValidateConfigFiles(configs, Application::GetObjectsPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TroubleshootCollectCommand::CheckObjectFile(const String& objectfile, InfoLog& log, const bool print,
|
void TroubleshootCollectCommand::CheckObjectFile(const String& objectfile, InfoLog& log, const bool print,
|
||||||
Dictionary::Ptr& logs, std::set<String>& configs)
|
Dictionary::Ptr& logs, std::set<String>& configs)
|
||||||
{
|
{
|
||||||
InfoLogLine(log) << "Checking object file from " << objectfile;
|
InfoLogLine(log)
|
||||||
|
<< "Checking object file from " << objectfile;
|
||||||
|
|
||||||
std::fstream fp;
|
std::fstream fp;
|
||||||
fp.open(objectfile.CStr(), std::ios_base::in);
|
fp.open(objectfile.CStr(), std::ios_base::in);
|
||||||
|
|
||||||
if (!fp.is_open()) {
|
if (!fp.is_open()) {
|
||||||
InfoLogLine(log, LogWarning) << "Could not open object file.";
|
InfoLogLine(log, LogWarning)
|
||||||
|
<< "Could not open object file.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,12 +377,11 @@ void TroubleshootCollectCommand::CheckObjectFile(const String& objectfile, InfoL
|
||||||
StreamReadStatus srs;
|
StreamReadStatus srs;
|
||||||
std::map<String, int> type_count;
|
std::map<String, int> type_count;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
while ((srs = NetString::ReadStringFromStream(sfp, &message, src)) != StatusEof) {
|
while ((srs = NetString::ReadStringFromStream(sfp, &message, src)) != StatusEof) {
|
||||||
if (srs != StatusNewItem)
|
if (srs != StatusNewItem)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool first = true;
|
|
||||||
|
|
||||||
std::stringstream sStream;
|
std::stringstream sStream;
|
||||||
|
|
||||||
ObjectListUtility::PrintObject(sStream, first, message, type_count, "", "");
|
ObjectListUtility::PrintObject(sStream, first, message, type_count, "", "");
|
||||||
|
@ -374,9 +397,9 @@ void TroubleshootCollectCommand::CheckObjectFile(const String& objectfile, InfoL
|
||||||
countTotal++;
|
countTotal++;
|
||||||
|
|
||||||
Array::Ptr debug_info = object->Get("debug_info");
|
Array::Ptr debug_info = object->Get("debug_info");
|
||||||
if (debug_info) {
|
|
||||||
|
if (debug_info)
|
||||||
configs.insert(debug_info->Get(0));
|
configs.insert(debug_info->Get(0));
|
||||||
}
|
|
||||||
|
|
||||||
if (Utility::Match(type, "FileLogger")) {
|
if (Utility::Match(type, "FileLogger")) {
|
||||||
Dictionary::Ptr debug_hints = object->Get("debug_hints");
|
Dictionary::Ptr debug_hints = object->Get("debug_hints");
|
||||||
|
@ -391,16 +414,20 @@ void TroubleshootCollectCommand::CheckObjectFile(const String& objectfile, InfoL
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!countTotal) {
|
if (!countTotal) {
|
||||||
InfoLogLine(log, LogCritical) << "No objects found in objectfile.";
|
InfoLogLine(log, LogCritical)
|
||||||
|
<< "No objects found in objectfile.";
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Print objects with count
|
//Print objects with count
|
||||||
InfoLogLine(log) << "Found the " << countTotal << " objects:"
|
InfoLogLine(log)
|
||||||
|
<< "Found the " << countTotal << " objects:"
|
||||||
<< "\tType" << std::string(typeL-4, ' ') << " : Count";
|
<< "\tType" << std::string(typeL-4, ' ') << " : Count";
|
||||||
|
|
||||||
BOOST_FOREACH(const Dictionary::Pair& kv, type_count) {
|
BOOST_FOREACH(const Dictionary::Pair& kv, type_count) {
|
||||||
InfoLogLine(log) << '\t' << kv.first << std::string(typeL - kv.first.GetLength(), ' ')
|
InfoLogLine(log)
|
||||||
|
<< '\t' << kv.first << std::string(typeL - kv.first.GetLength(), ' ')
|
||||||
<< " : " << kv.second;
|
<< " : " << kv.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -408,25 +435,34 @@ void TroubleshootCollectCommand::CheckObjectFile(const String& objectfile, InfoL
|
||||||
void TroubleshootCollectCommand::PrintLoggers(InfoLog& log, Dictionary::Ptr& logs)
|
void TroubleshootCollectCommand::PrintLoggers(InfoLog& log, Dictionary::Ptr& logs)
|
||||||
{
|
{
|
||||||
if (!logs->GetLength()) {
|
if (!logs->GetLength()) {
|
||||||
InfoLogLine(log, LogWarning) << "No loggers found, check whether you enabled any logging features";
|
InfoLogLine(log, LogWarning)
|
||||||
|
<< "No loggers found, check whether you enabled any logging features";
|
||||||
} else {
|
} else {
|
||||||
InfoLogLine(log) << "Getting the last 20 lines of " << logs->GetLength() << " FileLogger objects.";
|
InfoLogLine(log)
|
||||||
|
<< "Getting the last 20 lines of " << logs->GetLength() << " FileLogger objects.";
|
||||||
|
|
||||||
ObjectLock ulock(logs);
|
ObjectLock ulock(logs);
|
||||||
BOOST_FOREACH(const Dictionary::Pair& kv, logs)
|
BOOST_FOREACH(const Dictionary::Pair& kv, logs) {
|
||||||
{
|
InfoLogLine(log)
|
||||||
InfoLogLine(log) << "\nLogger " << kv.first << " at path: " << kv.second;
|
<< "\nLogger " << kv.first << " at path: " << kv.second;
|
||||||
if (!Tail(kv.second, 20, log))
|
|
||||||
InfoLogLine(log, LogWarning) << kv.second << " either does not exist or is empty";
|
if (!Tail(kv.second, 20, log)) {
|
||||||
|
InfoLogLine(log, LogWarning)
|
||||||
|
<< kv.second << " either does not exist or is empty";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TroubleshootCollectCommand::PrintConfig(InfoLog& log, const std::set<String>& configSet, const String::SizeType& countTotal)
|
void TroubleshootCollectCommand::PrintConfig(InfoLog& log, const std::set<String>& configSet, const String::SizeType& countTotal)
|
||||||
{
|
{
|
||||||
InfoLogLine(log) << countTotal << " objects in total, originating from these files:";
|
InfoLogLine(log)
|
||||||
for (std::set<String>::iterator it = configSet.begin();
|
<< countTotal << " objects in total, originating from these files:";
|
||||||
it != configSet.end(); it++)
|
|
||||||
InfoLogLine(log) << '\t' << *it;
|
for (std::set<String>::iterator it = configSet.begin(); it != configSet.end(); it++) {
|
||||||
|
InfoLogLine(log)
|
||||||
|
<< '\t' << *it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TroubleshootCollectCommand::InitParameters(boost::program_options::options_description& visibleDesc,
|
void TroubleshootCollectCommand::InitParameters(boost::program_options::options_description& visibleDesc,
|
||||||
|
@ -477,19 +513,24 @@ int TroubleshootCollectCommand::Run(const boost::program_options::variables_map&
|
||||||
|
|
||||||
Dictionary::Ptr logs = new Dictionary;
|
Dictionary::Ptr logs = new Dictionary;
|
||||||
|
|
||||||
if (!GeneralInfo(*log, vm)
|
if (!GeneralInfo(*log, vm) ||
|
||||||
|| !FeatureInfo(*log, vm)
|
!FeatureInfo(*log, vm) ||
|
||||||
|| !ObjectInfo(*log, vm, logs)
|
!ObjectInfo(*log, vm, logs) ||
|
||||||
|| !ReportInfo(*log, vm, logs)
|
!ReportInfo(*log, vm, logs) ||
|
||||||
|| !ConfigInfo(*log, vm)) {
|
!ConfigInfo(*log, vm)) {
|
||||||
InfoLogLine(*log, LogCritical) << "Could not recover from critical failure, exiting.";
|
InfoLogLine(*log, LogCritical)
|
||||||
|
<< "Could not recover from critical failure, exiting.";
|
||||||
|
|
||||||
delete log;
|
delete log;
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
double endTime = Utility::GetTime();
|
double endTime = Utility::GetTime();
|
||||||
InfoLogLine(*log) << "\nFinished collection at timestamp " << Convert::ToString(endTime)
|
|
||||||
|
InfoLogLine(*log)
|
||||||
|
<< "\nFinished collection at timestamp " << Convert::ToString(endTime)
|
||||||
<< "\nTook " << Convert::ToString(endTime - goTime) << " seconds\n";
|
<< "\nTook " << Convert::ToString(endTime - goTime) << " seconds\n";
|
||||||
|
|
||||||
if (!vm.count("console")) {
|
if (!vm.count("console")) {
|
||||||
std::cout << "\nFinished collection. See '" << path << "'\n";
|
std::cout << "\nFinished collection. See '" << path << "'\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Icinga 2 *
|
* Icinga 2 *
|
||||||
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
|
* Copyright (C) 2012-2015 Icinga Development Team (https://www.icinga.org) *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or *
|
* This program is free software; you can redistribute it and/or *
|
||||||
* modify it under the terms of the GNU General Public License *
|
* modify it under the terms of the GNU General Public License *
|
||||||
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
namespace icinga
|
namespace icinga
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "troubleshoot collect" command.
|
* The "troubleshoot collect" command.
|
||||||
*
|
*
|
||||||
|
@ -64,5 +65,6 @@ namespace icinga
|
||||||
static void PrintLoggers(InfoLog& log, Dictionary::Ptr& logs);
|
static void PrintLoggers(InfoLog& log, Dictionary::Ptr& logs);
|
||||||
static void PrintConfig(InfoLog& log, const std::set<String>& configSet, const String::SizeType& countTotal);
|
static void PrintConfig(InfoLog& log, const std::set<String>& configSet, const String::SizeType& countTotal);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif /* TROUBLESHOOTCOLLECTCOMMAND_H */
|
#endif /* TROUBLESHOOTCOLLECTCOMMAND_H */
|
||||||
|
|
Loading…
Reference in New Issue