2015-01-22 12:10:32 +01:00
/*****************************************************************************
* Icinga 2 *
2015-02-20 15:27:10 +01:00
* Copyright ( C ) 2012 - 2015 Icinga Development Team ( https : //www.icinga.org) *
2015-01-22 12:10:32 +01:00
* *
* 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 . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-02-25 09:51:31 +01:00
# include "cli/troubleshootcommand.hpp"
2015-02-19 17:12:32 +01:00
# include "cli/objectlistutility.hpp"
2015-01-22 12:10:32 +01:00
# include "cli/featureutility.hpp"
# include "cli/daemonutility.hpp"
# include "base/netstring.hpp"
# include "base/application.hpp"
# include "base/stdiostream.hpp"
# include "base/json.hpp"
# include "base/objectlock.hpp"
2015-02-19 17:12:32 +01:00
# include "base/convert.hpp"
2015-01-22 12:10:32 +01:00
# include "config/configitembuilder.hpp"
# include <boost/circular_buffer.hpp>
# include <boost/foreach.hpp>
# include <boost/algorithm/string/join.hpp>
# include <iostream>
# include <fstream>
using namespace icinga ;
namespace po = boost : : program_options ;
2015-02-25 09:51:31 +01:00
REGISTER_CLICOMMAND ( " troubleshoot " , TroubleshootCommand ) ;
2015-01-22 12:10:32 +01:00
2015-02-25 09:51:31 +01:00
String TroubleshootCommand : : GetDescription ( void ) const
2015-01-22 12:10:32 +01:00
{
return " Collect logs and other relevant information for troubleshooting purposes. " ;
}
2015-02-25 09:51:31 +01:00
String TroubleshootCommand : : GetShortDescription ( void ) const
2015-01-22 12:10:32 +01:00
{
return " Collect information for troubleshooting " ;
}
2015-02-25 09:51:31 +01:00
class TroubleshootCommand : : InfoLog
2015-01-22 12:10:32 +01:00
{
2015-02-19 17:12:32 +01:00
public :
InfoLog ( const String & path , const bool cons )
{
2015-02-20 14:14:34 +01:00
m_Console = cons ;
if ( m_Console )
m_Stream = new std : : ostream ( std : : cout . rdbuf ( ) ) ;
else {
2015-02-20 13:40:08 +01:00
std : : ofstream * ofs = new std : : ofstream ( ) ;
ofs - > open ( path . CStr ( ) , std : : ios : : out | std : : ios : : trunc ) ;
2015-02-20 14:14:34 +01:00
m_Stream = ofs ;
2015-02-19 17:12:32 +01:00
}
2015-02-20 14:14:34 +01:00
}
2015-02-19 17:12:32 +01:00
2015-02-25 11:08:05 +01:00
~ InfoLog ( void )
{
delete m_Stream ;
}
2015-02-20 14:14:34 +01:00
void WriteLine ( const LogSeverity sev , const String & str )
2015-02-19 17:12:32 +01:00
{
2015-02-20 14:14:34 +01:00
if ( ! m_Console )
2015-02-19 17:12:32 +01:00
Log ( sev , " troubleshoot " , str ) ;
if ( sev = = LogCritical | | sev = = LogWarning ) {
2015-02-20 16:13:25 +01:00
* m_Stream
< < std : : string ( 24 , ' # ' ) < < ' \n '
< < " # " < < str < < ' \n '
< < std : : string ( 24 , ' # ' ) < < ' \n ' ;
2015-02-19 17:12:32 +01:00
} else
2015-02-20 16:13:25 +01:00
* m_Stream
< < str < < ' \n ' ;
2015-01-22 12:10:32 +01:00
}
2015-02-20 14:14:34 +01:00
bool GetStreamHealth ( void ) const
2015-02-19 17:12:32 +01:00
{
2015-02-20 16:59:10 +01:00
return m_Stream - > good ( ) ;
2015-02-19 17:12:32 +01:00
}
2015-02-20 14:14:34 +01:00
private :
bool m_Console ;
std : : ostream * m_Stream ;
2015-02-19 17:12:32 +01:00
} ;
2015-02-25 09:51:31 +01:00
class TroubleshootCommand : : InfoLogLine
2015-01-22 12:10:32 +01:00
{
2015-02-19 17:12:32 +01:00
public :
InfoLogLine ( InfoLog & log , LogSeverity sev = LogInformation )
2015-02-20 14:14:34 +01:00
: m_Log ( log ) , m_Sev ( sev ) { }
2015-01-22 12:10:32 +01:00
2015-02-25 11:08:05 +01:00
~ InfoLogLine ( void )
2015-02-19 17:12:32 +01:00
{
2015-02-20 14:14:34 +01:00
m_Log . WriteLine ( m_Sev , m_String . str ( ) ) ;
2015-01-22 12:10:32 +01:00
}
2015-02-19 17:12:32 +01:00
template < typename T >
InfoLogLine & operator < < ( const T & info )
{
2015-02-20 14:14:34 +01:00
m_String < < info ;
2015-02-19 17:12:32 +01:00
return * this ;
2015-01-22 12:10:32 +01:00
}
2015-02-19 17:12:32 +01:00
private :
2015-02-20 14:14:34 +01:00
std : : ostringstream m_String ;
InfoLog & m_Log ;
LogSeverity m_Sev ;
2015-02-19 17:12:32 +01:00
} ;
2015-02-25 09:51:31 +01:00
bool TroubleshootCommand : : GeneralInfo ( InfoLog & log , const boost : : program_options : : variables_map & vm )
2015-02-19 17:12:32 +01:00
{
2015-02-20 16:13:25 +01:00
InfoLogLine ( log )
< < ' \n ' < < std : : string ( 14 , ' = ' ) < < " GENERAL INFORMATION " < < std : : string ( 14 , ' = ' ) < < ' \n ' ;
2015-02-19 17:12:32 +01:00
2015-02-20 15:27:10 +01:00
//Application::DisplayInfoMessage() but formatted
2015-02-19 17:12:32 +01:00
InfoLogLine ( log )
2015-02-20 15:27:10 +01:00
< < " \t Application version: " < < Application : : GetVersion ( ) < < ' \n '
< < " \t Installation root: " < < Application : : GetPrefixDir ( ) < < ' \n '
< < " \t Sysconf directory: " < < Application : : GetSysconfDir ( ) < < ' \n '
< < " \t Run directory: " < < Application : : GetRunDir ( ) < < ' \n '
< < " \t Local state directory: " < < Application : : GetLocalStateDir ( ) < < ' \n '
< < " \t Package data directory: " < < Application : : GetPkgDataDir ( ) < < ' \n '
< < " \t State path: " < < Application : : GetStatePath ( ) < < ' \n '
< < " \t Objects path: " < < Application : : GetObjectsPath ( ) < < ' \n '
< < " \t Vars path: " < < Application : : GetVarsPath ( ) < < ' \n '
< < " \t PID path: " < < Application : : GetPidPath ( ) < < ' \n '
< < " \t Application type: " < < Application : : GetApplicationType ( ) < < ' \n ' ;
2015-02-19 17:12:32 +01:00
return true ;
}
2015-02-25 09:51:31 +01:00
bool TroubleshootCommand : : FeatureInfo ( InfoLog & log , const boost : : program_options : : variables_map & vm )
2015-02-19 17:12:32 +01:00
{
2015-02-25 09:51:31 +01:00
TroubleshootCommand : : CheckFeatures ( log ) ;
2015-02-25 11:08:05 +01:00
//TODO Check whether active features are operational.
2015-02-19 17:12:32 +01:00
return true ;
}
2015-02-25 09:51:31 +01:00
bool TroubleshootCommand : : ObjectInfo ( InfoLog & log , const boost : : program_options : : variables_map & vm , Dictionary : : Ptr & logs )
2015-02-19 17:12:32 +01:00
{
2015-02-20 16:13:25 +01:00
InfoLogLine ( log )
< < ' \n ' < < std : : string ( 14 , ' = ' ) < < " OBJECT INFORMATION " < < std : : string ( 14 , ' = ' ) < < ' \n ' ;
2015-02-19 17:12:32 +01:00
String objectfile = Application : : GetObjectsPath ( ) ;
std : : set < String > configs ;
if ( ! Utility : : PathExists ( objectfile ) ) {
2015-02-20 16:13:25 +01:00
InfoLogLine ( log , LogCritical )
< < " Cannot open object file ' " < < objectfile < < " '. \n "
< < " FAILED: This probably means you have a fault configuration. " ;
2015-02-19 17:12:32 +01:00
return false ;
} else
CheckObjectFile ( objectfile , log , vm . count ( " include-objects " ) , logs , configs ) ;
return true ;
}
2015-02-25 09:51:31 +01:00
bool TroubleshootCommand : : ReportInfo ( InfoLog & log , const boost : : program_options : : variables_map & vm , Dictionary : : Ptr & logs )
2015-02-19 17:12:32 +01:00
{
2015-02-20 16:13:25 +01:00
InfoLogLine ( log )
< < ' \n ' < < std : : string ( 14 , ' = ' ) < < " LOGS AND CRASH REPORTS " < < std : : string ( 14 , ' = ' ) < < ' \n ' ;
2015-02-19 17:12:32 +01:00
PrintLoggers ( log , logs ) ;
PrintCrashReports ( log ) ;
return true ;
}
2015-02-25 09:51:31 +01:00
bool TroubleshootCommand : : ConfigInfo ( InfoLog & log , const boost : : program_options : : variables_map & vm )
2015-02-19 17:12:32 +01:00
{
2015-02-20 16:13:25 +01:00
InfoLogLine ( log )
< < ' \n ' < < std : : string ( 14 , ' = ' ) < < " CONFIGURATION FILES " < < std : : string ( 14 , ' = ' ) < < ' \n ' ;
InfoLogLine ( log )
< < " A collection of important configuration files follows, please make sure to remove any sensitive data such as credentials, internal company names, etc " ;
2015-02-19 17:12:32 +01:00
if ( ! PrintConf ( log , Application : : GetSysconfDir ( ) + " /icinga2/icinga2.conf " ) ) {
2015-02-20 15:27:10 +01:00
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 \t o/icinga2.conf \" ' \n "
< < " and provide it with your support request. " ;
2015-01-22 12:10:32 +01:00
}
2015-02-19 17:12:32 +01:00
if ( ! PrintConf ( log , Application : : GetSysconfDir ( ) + " /icinga2/zones.conf " ) ) {
2015-02-20 15:27:10 +01:00
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 " ;
2015-01-22 12:10:32 +01:00
}
2015-02-19 17:12:32 +01:00
return true ;
2015-01-22 12:10:32 +01:00
}
/*Print the last *numLines* of *file* to *os* */
2015-02-25 09:51:31 +01:00
int TroubleshootCommand : : Tail ( const String & file , int numLines , InfoLog & log )
2015-01-22 12:10:32 +01:00
{
boost : : circular_buffer < std : : string > ringBuf ( numLines ) ;
std : : ifstream text ;
text . open ( file . CStr ( ) , std : : ifstream : : in ) ;
if ( ! text . good ( ) )
return 0 ;
std : : string line ;
int lines = 0 ;
while ( std : : getline ( text , line ) ) {
ringBuf . push_back ( line ) ;
lines + + ;
}
if ( lines < numLines )
numLines = lines ;
2015-02-25 09:51:31 +01:00
InfoLogLine ( log )
< < " [begin: ' " < < file < < " ' line: " < < numLines - lines < < ' ] ' ;
2015-01-22 12:10:32 +01:00
2015-02-20 15:27:10 +01:00
for ( int k = 0 ; k < numLines ; k + + ) {
InfoLogLine ( log )
< < ' \t ' < < ringBuf [ k ] ;
}
2015-01-22 12:10:32 +01:00
text . close ( ) ;
2015-02-20 15:27:10 +01:00
2015-02-20 16:13:25 +01:00
InfoLogLine ( log )
2015-02-20 15:27:10 +01:00
< < " [end: ' " < < file < < " ' line: " < < lines < < ' ] ' ;
2015-01-22 12:10:32 +01:00
return numLines ;
}
2015-02-25 09:51:31 +01:00
bool TroubleshootCommand : : CheckFeatures ( InfoLog & log )
2015-01-22 12:10:32 +01:00
{
2015-02-19 17:12:32 +01:00
Dictionary : : Ptr features = new Dictionary ;
std : : vector < String > disabled_features ;
std : : vector < String > enabled_features ;
2015-01-22 12:10:32 +01:00
2015-02-20 15:27:10 +01:00
if ( ! FeatureUtility : : GetFeatures ( disabled_features , true ) | |
! FeatureUtility : : GetFeatures ( enabled_features , false ) ) {
InfoLogLine ( log , LogCritical )
< < " Failed to collect enabled and/or disabled features. Check \n "
< < FeatureUtility : : GetFeaturesAvailablePath ( ) < < ' \n '
< < FeatureUtility : : GetFeaturesEnabledPath ( ) ;
2015-01-22 12:10:32 +01:00
return false ;
}
2015-02-19 17:12:32 +01:00
BOOST_FOREACH ( const String feature , disabled_features )
features - > Set ( feature , false ) ;
BOOST_FOREACH ( const String feature , enabled_features )
features - > Set ( feature , true ) ;
2015-02-20 15:27:10 +01:00
InfoLogLine ( log )
< < " Enabled features: \n \t " < < boost : : algorithm : : join ( enabled_features , " " ) < < ' \n '
< < " Disabled features: \n \t " < < boost : : algorithm : : join ( disabled_features , " " ) < < ' \n ' ;
2015-02-19 17:12:32 +01:00
if ( ! features - > Get ( " checker " ) . ToBool ( ) )
2015-02-20 16:13:25 +01:00
InfoLogLine ( log , LogWarning )
< < " checker is disabled, no checks can be run from this instance " ;
2015-02-19 17:12:32 +01:00
if ( ! features - > Get ( " mainlog " ) . ToBool ( ) )
2015-02-20 16:13:25 +01:00
InfoLogLine ( log , LogWarning )
< < " mainlog is disabled, please activate it and rerun icinga2 " ;
2015-02-19 17:12:32 +01:00
if ( ! features - > Get ( " debuglog " ) . ToBool ( ) )
2015-02-20 16:13:25 +01:00
InfoLogLine ( log , LogWarning )
< < " debuglog is disabled, please activate it and rerun icinga2 " ;
2015-02-20 15:27:10 +01:00
2015-01-22 12:10:32 +01:00
return true ;
}
2015-02-25 09:51:31 +01:00
void TroubleshootCommand : : GetLatestReport ( const String & filename , time_t & bestTimestamp , String & bestFilename )
2015-02-19 17:12:32 +01:00
{
# ifdef _WIN32
struct _stat buf ;
if ( _stat ( filename . CStr ( ) , & buf ) )
return ;
# else
struct stat buf ;
if ( stat ( filename . CStr ( ) , & buf ) )
return ;
# endif /*_WIN32*/
if ( buf . st_mtime > bestTimestamp ) {
bestTimestamp = buf . st_mtime ;
bestFilename = filename ;
}
}
2015-02-25 09:51:31 +01:00
bool TroubleshootCommand : : PrintCrashReports ( InfoLog & log )
2015-01-22 12:10:32 +01:00
{
2015-02-19 17:12:32 +01:00
String spath = Application : : GetLocalStateDir ( ) + " /log/icinga2/crash/report.* " ;
time_t bestTimestamp = 0 ;
String bestFilename ;
2015-01-22 12:10:32 +01:00
2015-02-19 17:12:32 +01:00
try {
2015-02-20 15:27:10 +01:00
Utility : : Glob ( spath , boost : : bind ( & GetLatestReport , _1 , boost : : ref ( bestTimestamp ) ,
boost : : ref ( bestFilename ) ) , GlobFile ) ;
2015-02-19 17:12:32 +01:00
}
# ifdef _WIN32
catch ( 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
2015-02-20 15:27:10 +01:00
InfoLogLine ( log , LogWarning )
< < Application : : GetLocalStateDir ( ) < < " /log/icinga2/crash/ does not exist " ;
2015-02-19 17:12:32 +01:00
return false ;
}
2015-02-20 15:27:10 +01:00
}
2015-02-20 16:13:25 +01:00
InfoLogLine ( log , LogWarning )
2015-02-20 15:27:10 +01:00
< < " Error printing crash reports " ;
2015-02-19 17:12:32 +01:00
return false ;
}
# else
catch ( . . . ) {
2015-02-20 16:13:25 +01:00
InfoLogLine ( log , LogWarning ) < < " Error printing crash reports. \n "
< < " Does " < < Application : : GetLocalStateDir ( ) < < " /log/icinga2/crash/ exist? " ;
2015-02-20 15:27:10 +01:00
return false ;
2015-02-19 17:12:32 +01:00
}
# endif /*_WIN32*/
if ( ! bestTimestamp )
2015-02-20 15:27:10 +01:00
InfoLogLine ( log )
< < " No crash logs found in " < < Application : : GetLocalStateDir ( ) . CStr ( ) < < " /log/icinga2/crash/ " ;
2015-02-19 17:12:32 +01:00
else {
2015-02-20 15:27:10 +01:00
InfoLogLine ( log )
< < " Latest crash report is from " < < Utility : : FormatDateTime ( " %Y-%m-%d %H:%M:%S " , Utility : : GetTime ( ) )
< < " \n File: " < < bestFilename ;
2015-02-20 14:14:34 +01:00
Tail ( bestFilename , 20 , log ) ;
2015-02-19 17:12:32 +01:00
}
2015-02-20 15:27:10 +01:00
2015-02-19 17:12:32 +01:00
return true ;
}
2015-02-25 09:51:31 +01:00
bool TroubleshootCommand : : PrintConf ( InfoLog & log , const String & path )
2015-02-19 17:12:32 +01:00
{
2015-01-22 12:10:32 +01:00
std : : ifstream text ;
text . open ( path . CStr ( ) , std : : ifstream : : in ) ;
2015-02-19 17:12:32 +01:00
if ( ! text . is_open ( ) )
2015-01-22 12:10:32 +01:00
return false ;
2015-02-19 17:12:32 +01:00
2015-01-22 12:10:32 +01:00
std : : string line ;
2015-02-20 16:13:25 +01:00
InfoLogLine ( log )
2015-02-25 09:51:31 +01:00
< < " [begin: ' " < < path < < " '] " ;
2015-02-20 15:27:10 +01:00
2015-01-22 12:10:32 +01:00
while ( std : : getline ( text , line ) ) {
2015-02-20 16:13:25 +01:00
InfoLogLine ( log )
2015-02-20 15:27:10 +01:00
< < ' \t ' < < line ;
2015-01-22 12:10:32 +01:00
}
2015-02-20 15:27:10 +01:00
InfoLogLine ( log )
2015-02-25 09:51:31 +01:00
< < " [end: ' " < < path < < " '] " ;
2015-02-20 15:27:10 +01:00
2015-01-22 12:10:32 +01:00
return true ;
}
2015-02-25 09:51:31 +01:00
bool TroubleshootCommand : : CheckConfig ( void )
2015-01-22 12:10:32 +01:00
{
/* Not loading the icinga library would make config validation fail.
2015-02-20 15:27:10 +01:00
* ( Depending on the configuration and the speed of your machine . )
2015-02-19 17:12:32 +01:00
*/
2015-01-22 12:10:32 +01:00
Utility : : LoadExtensionLibrary ( " icinga " ) ;
std : : vector < std : : string > configs ;
configs . push_back ( Application : : GetSysconfDir ( ) + " /icinga2/icinga2.conf " ) ;
2015-02-20 15:27:10 +01:00
2015-02-19 17:12:32 +01:00
return DaemonUtility : : ValidateConfigFiles ( configs , Application : : GetObjectsPath ( ) ) ;
2015-01-22 12:10:32 +01:00
}
2015-02-25 09:51:31 +01:00
void TroubleshootCommand : : CheckObjectFile ( const String & objectfile , InfoLog & log , const bool print ,
2015-02-20 15:27:10 +01:00
Dictionary : : Ptr & logs , std : : set < String > & configs )
2015-01-22 12:10:32 +01:00
{
2015-02-20 15:27:10 +01:00
InfoLogLine ( log )
< < " Checking object file from " < < objectfile ;
2015-01-22 12:10:32 +01:00
std : : fstream fp ;
fp . open ( objectfile . CStr ( ) , std : : ios_base : : in ) ;
if ( ! fp . is_open ( ) ) {
2015-02-20 15:27:10 +01:00
InfoLogLine ( log , LogWarning )
< < " Could not open object file. " ;
2015-01-22 12:10:32 +01:00
return ;
}
2015-02-20 15:27:10 +01:00
2015-01-22 12:10:32 +01:00
StdioStream : : Ptr sfp = new StdioStream ( & fp , false ) ;
2015-02-19 17:12:32 +01:00
String : : SizeType typeL = 0 , countTotal = 0 ;
2015-02-15 14:42:53 +01:00
2015-01-22 12:10:32 +01:00
String message ;
StreamReadContext src ;
2015-02-19 17:12:32 +01:00
StreamReadStatus srs ;
std : : map < String , int > type_count ;
bool first = true ;
2015-02-20 15:27:10 +01:00
2015-02-19 17:12:32 +01:00
while ( ( srs = NetString : : ReadStringFromStream ( sfp , & message , src ) ) ! = StatusEof ) {
2015-02-15 14:42:53 +01:00
if ( srs ! = StatusNewItem )
continue ;
2015-01-22 12:10:32 +01:00
2015-02-20 09:55:07 +01:00
std : : stringstream sStream ;
2015-02-20 15:27:10 +01:00
2015-02-20 09:55:07 +01:00
ObjectListUtility : : PrintObject ( sStream , first , message , type_count , " " , " " ) ;
2015-02-20 15:27:10 +01:00
2015-01-22 12:10:32 +01:00
Dictionary : : Ptr object = JsonDecode ( message ) ;
Dictionary : : Ptr properties = object - > Get ( " properties " ) ;
String name = object - > Get ( " name " ) ;
String type = object - > Get ( " type " ) ;
//Find longest typename for padding
typeL = type . GetLength ( ) > typeL ? type . GetLength ( ) : typeL ;
countTotal + + ;
Array : : Ptr debug_info = object - > Get ( " debug_info " ) ;
2015-02-20 15:27:10 +01:00
if ( debug_info )
2015-02-19 17:12:32 +01:00
configs . insert ( debug_info - > Get ( 0 ) ) ;
2015-01-22 12:10:32 +01:00
if ( Utility : : Match ( type , " FileLogger " ) ) {
Dictionary : : Ptr debug_hints = object - > Get ( " debug_hints " ) ;
Dictionary : : Ptr properties = object - > Get ( " properties " ) ;
ObjectLock olock ( properties ) ;
BOOST_FOREACH ( const Dictionary : : Pair & kv , properties ) {
if ( Utility : : Match ( kv . first , " path " ) )
2015-02-19 17:12:32 +01:00
logs - > Set ( name , kv . second ) ;
2015-01-22 12:10:32 +01:00
}
}
}
if ( ! countTotal ) {
2015-02-20 15:27:10 +01:00
InfoLogLine ( log , LogCritical )
< < " No objects found in objectfile. " ;
2015-01-22 12:10:32 +01:00
return ;
}
//Print objects with count
2015-02-20 15:27:10 +01:00
InfoLogLine ( log )
< < " Found the " < < countTotal < < " objects: "
< < " \t Type " < < std : : string ( typeL - 4 , ' ' ) < < " : Count " ;
2015-01-22 12:10:32 +01:00
2015-02-19 17:12:32 +01:00
BOOST_FOREACH ( const Dictionary : : Pair & kv , type_count ) {
2015-02-20 15:27:10 +01:00
InfoLogLine ( log )
< < ' \t ' < < kv . first < < std : : string ( typeL - kv . first . GetLength ( ) , ' ' )
< < " : " < < kv . second ;
2015-02-19 17:12:32 +01:00
}
}
2015-01-22 12:10:32 +01:00
2015-02-25 09:51:31 +01:00
void TroubleshootCommand : : PrintLoggers ( InfoLog & log , Dictionary : : Ptr & logs )
2015-02-19 17:12:32 +01:00
{
if ( ! logs - > GetLength ( ) ) {
2015-02-20 15:27:10 +01:00
InfoLogLine ( log , LogWarning )
< < " No loggers found, check whether you enabled any logging features " ;
2015-01-22 12:10:32 +01:00
} else {
2015-02-20 15:27:10 +01:00
InfoLogLine ( log )
< < " Getting the last 20 lines of " < < logs - > GetLength ( ) < < " FileLogger objects. " ;
2015-02-19 17:12:32 +01:00
ObjectLock ulock ( logs ) ;
2015-02-20 15:27:10 +01:00
BOOST_FOREACH ( const Dictionary : : Pair & kv , logs ) {
InfoLogLine ( log )
2015-02-25 09:51:31 +01:00
< < " Logger " < < kv . first < < " at path: " < < kv . second ;
2015-02-20 15:27:10 +01:00
if ( ! Tail ( kv . second , 20 , log ) ) {
InfoLogLine ( log , LogWarning )
< < kv . second < < " either does not exist or is empty " ;
}
2015-01-22 12:10:32 +01:00
}
}
}
2015-02-25 09:51:31 +01:00
void TroubleshootCommand : : PrintConfig ( InfoLog & log , const std : : set < String > & configSet , const String : : SizeType & countTotal )
2015-02-19 17:12:32 +01:00
{
2015-02-20 15:27:10 +01:00
InfoLogLine ( log )
< < countTotal < < " objects in total, originating from these files: " ;
for ( std : : set < String > : : iterator it = configSet . begin ( ) ; it ! = configSet . end ( ) ; it + + ) {
InfoLogLine ( log )
< < ' \t ' < < * it ;
}
2015-02-19 17:12:32 +01:00
}
2015-02-25 09:51:31 +01:00
void TroubleshootCommand : : InitParameters ( boost : : program_options : : options_description & visibleDesc ,
2015-02-20 15:27:10 +01:00
boost : : program_options : : options_description & hiddenDesc ) const
2015-01-22 12:10:32 +01:00
{
visibleDesc . add_options ( )
( " console,c " , " print to console instead of file " )
2015-02-19 17:12:32 +01:00
( " output,o " , boost : : program_options : : value < std : : string > ( ) , " path to output file " )
( " include-objects " , " Print the whole objectfile (like `object list`) " )
2015-01-22 12:10:32 +01:00
;
}
2015-02-25 09:51:31 +01:00
int TroubleshootCommand : : Run ( const boost : : program_options : : variables_map & vm , const std : : vector < std : : string > & ap ) const
2015-01-22 12:10:32 +01:00
{
String path ;
2015-02-19 17:12:32 +01:00
InfoLog * log ;
Logger : : SetConsoleLogSeverity ( LogWarning ) ;
2015-01-22 12:10:32 +01:00
if ( vm . count ( " console " ) ) {
2015-02-19 17:12:32 +01:00
log = new InfoLog ( " " , true ) ;
2015-01-22 12:10:32 +01:00
} else {
2015-02-19 17:12:32 +01:00
if ( vm . count ( " output " ) )
path = vm [ " output " ] . as < std : : string > ( ) ;
else {
# ifdef _WIN32 //Dislikes ':' in filenames
path = Application : : GetLocalStateDir ( ) + " /log/icinga2/troubleshooting- "
2015-02-20 15:27:10 +01:00
+ Utility : : FormatDateTime ( " %Y-%m-%d_%H-%M-%S " , Utility : : GetTime ( ) ) + " .log " ;
2015-02-19 17:12:32 +01:00
# else
2015-02-20 15:27:10 +01:00
path = Application : : GetLocalStateDir ( ) + " /log/icinga2/troubleshooting- "
+ Utility : : FormatDateTime ( " %Y-%m-%d_%H:%M:%S " , Utility : : GetTime ( ) ) + " .log " ;
2015-02-19 17:12:32 +01:00
# endif /*_WIN32*/
}
log = new InfoLog ( path , false ) ;
if ( ! log - > GetStreamHealth ( ) ) {
2015-01-22 12:10:32 +01:00
Log ( LogCritical , " troubleshoot " , " Failed to open file to write: " + path ) ;
return 3 ;
}
2015-02-20 15:27:10 +01:00
}
2015-01-22 12:10:32 +01:00
String appName = Utility : : BaseName ( Application : : GetArgV ( ) [ 0 ] ) ;
2015-02-19 17:12:32 +01:00
double goTime = Utility : : GetTime ( ) ;
2015-01-22 12:10:32 +01:00
2015-02-20 16:13:25 +01:00
InfoLogLine ( * log )
< < appName < < " -- Troubleshooting help: \n "
< < " Should you run into problems with Icinga please add this file to your help request \n "
< < " Began procedure at timestamp " < < Convert : : ToString ( goTime ) < < ' \n ' ;
2015-01-22 12:10:32 +01:00
if ( appName . GetLength ( ) > 3 & & appName . SubStr ( 0 , 3 ) = = " lt- " )
appName = appName . SubStr ( 3 , appName . GetLength ( ) - 3 ) ;
2015-02-19 17:12:32 +01:00
Dictionary : : Ptr logs = new Dictionary ;
2015-01-22 12:10:32 +01:00
2015-02-20 15:27:10 +01:00
if ( ! GeneralInfo ( * log , vm ) | |
! FeatureInfo ( * log , vm ) | |
! ObjectInfo ( * log , vm , logs ) | |
! ReportInfo ( * log , vm , logs ) | |
! ConfigInfo ( * log , vm ) ) {
InfoLogLine ( * log , LogCritical )
< < " Could not recover from critical failure, exiting. " ;
2015-02-19 17:12:32 +01:00
delete log ;
return 3 ;
2015-01-22 12:10:32 +01:00
}
2015-02-20 15:27:10 +01:00
2015-02-19 17:12:32 +01:00
double endTime = Utility : : GetTime ( ) ;
2015-02-20 15:27:10 +01:00
InfoLogLine ( * log )
< < " \n Finished collection at timestamp " < < Convert : : ToString ( endTime )
< < " \n Took " < < Convert : : ToString ( endTime - goTime ) < < " seconds \n " ;
2015-01-22 12:10:32 +01:00
if ( ! vm . count ( " console " ) ) {
2015-02-20 16:13:25 +01:00
std : : cout
< < " \n Finished collection. See ' " < < path < < " ' \n " ;
2015-01-22 12:10:32 +01:00
}
2015-02-19 17:12:32 +01:00
delete log ;
2015-01-22 12:10:32 +01:00
return 0 ;
}