]> granicus.if.org Git - icinga2/commitdiff
Implement support for attaching GDB to the Icinga process on crash
authorGunnar Beutner <gunnar@beutner.name>
Sat, 8 Aug 2015 07:40:16 +0000 (09:40 +0200)
committerMichael Friedrich <michael.friedrich@netways.de>
Sat, 8 Aug 2015 07:41:39 +0000 (09:41 +0200)
fixes #9866

doc/19-language-reference.md
icinga-app/icinga.cpp
lib/base/application.cpp
lib/base/application.hpp

index a63b16e65f21f769393d8dc1ce1bdf2bf596cfcf..e7f039fbdaa58db010a0c5742c72c8745feec45f 100644 (file)
@@ -375,6 +375,7 @@ EnableHostChecks    |**Read-write.** Whether active host checks are globally ena
 EnableServiceChecks |**Read-write.** Whether active service checks are globally enabled. Defaults to true.
 EnablePerfdata      |**Read-write.** Whether performance data processing is globally enabled. Defaults to true.
 UseVfork            |**Read-write.** Whether to use vfork(). Only available on *NIX. Defaults to true.
+AttachDebugger      |**Read-write.** Whether to attach a debugger when Icinga 2 crashes. Defaults to false.
 RunAsUser              |**Read-write.** Defines the user the Icinga 2 daemon is running as. Used in the `init.conf` configuration file.
 RunAsGroup             |**Read-write.** Defines the group the Icinga 2 daemon is running as. Used in the `init.conf` configuration file.
 
index de5aeeebb92cbcb74334b5d938142e7194ff3a1e..de270bc0f1e03d015155e37d8b4843265393c17d 100644 (file)
@@ -173,6 +173,8 @@ int Main(void)
                ScriptGlobal::Set("UseVfork", true);
 #endif /* __APPLE__ */
 
+       ScriptGlobal::Set("AttachDebugger", false);
+
        LogSeverity logLevel = Logger::GetConsoleLogSeverity();
        Logger::SetConsoleLogSeverity(LogWarning);
 
index 628fb5988060ded166246fe0b3742d01702688b6..b32ea4fb8d0241126a7d11b0bcf4ebe4d382f362 100644 (file)
@@ -626,9 +626,9 @@ String Application::GetCrashReportFilename(void)
 }
 
 
-#ifndef _WIN32
-void Application::GetDebuggerBacktrace(const String& filename)
+void Application::AttachDebugger(const String& filename, bool interactive)
 {
+#ifndef _WIN32
 #ifdef __linux__
        prctl(PR_SET_DUMPABLE, 1);
 #endif /* __linux __ */
@@ -644,42 +644,58 @@ void Application::GetDebuggerBacktrace(const String& filename)
        }
 
        if (pid == 0) {
-               int fd = open(filename.CStr(), O_CREAT | O_RDWR | O_APPEND, 0600);
+               if (!interactive) {
+                       int fd = open(filename.CStr(), O_CREAT | O_RDWR | O_APPEND, 0600);
+
+                       if (fd < 0) {
+                               BOOST_THROW_EXCEPTION(posix_error()
+                                   << boost::errinfo_api_function("open")
+                                   << boost::errinfo_errno(errno)
+                                   << boost::errinfo_file_name(filename));
+                       }
 
-               if (fd < 0) {
-                       BOOST_THROW_EXCEPTION(posix_error()
-                           << boost::errinfo_api_function("open")
-                           << boost::errinfo_errno(errno)
-                           << boost::errinfo_file_name(filename));
-               }
+                       if (fd != 1) {
+                               /* redirect stdout to the file */
+                               dup2(fd, 1);
+                               close(fd);
+                       }
+
+                       /* redirect stderr to stdout */
+                       if (fd != 2)
+                               close(2);
 
-               if (fd != 1) {
-                       /* redirect stdout to the file */
-                       dup2(fd, 1);
-                       close(fd);
+                       dup2(1, 2);
                }
 
-               /* redirect stderr to stdout */
-               if (fd != 2)
-                       close(2);
+               char **argv;
+               char *my_pid_str = strdup(my_pid.CStr());
 
-               dup2(1, 2);
+               if (interactive) {
+                       const char *uargv[] = {
+                               "gdb",
+                               "-p",
+                               my_pid_str,
+                               NULL
+                       };
+                       argv = const_cast<char **>(uargv);
+               } else {
+                       const char *uargv[] = {
+                               "gdb",
+                               "--batch",
+                               "-p",
+                               my_pid_str,
+                               "-ex",
+                               "thread apply all bt full",
+                               "-ex",
+                               "detach",
+                               "-ex",
+                               "quit",
+                               NULL
+                       };
+                       argv = const_cast<char **>(uargv);
+               }
 
-               char *my_pid_str = strdup(my_pid.CStr());
-               const char *argv[] = {
-                       "gdb",
-                       "--batch",
-                       "-p",
-                       my_pid_str,
-                       "-ex",
-                       "thread apply all bt full",
-                       "-ex",
-                       "detach",
-                       "-ex",
-                       "quit",
-                       NULL
-               };
-               (void)execvp(argv[0], const_cast<char **>(argv));
+               (void)execvp(argv[0], argv);
                perror("Failed to launch GDB");
                free(my_pid_str);
                _exit(0);
@@ -695,6 +711,9 @@ void Application::GetDebuggerBacktrace(const String& filename)
 #ifdef __linux__
        prctl(PR_SET_DUMPABLE, 0);
 #endif /* __linux __ */
+#else /* _WIN32 */
+       DebugBreak();
+#endif /* _WIN32 */
 }
 
 /**
@@ -750,30 +769,33 @@ void Application::SigAbrtHandler(int)
        String fname = GetCrashReportFilename();
        Utility::MkDir(Utility::DirName(fname), 0750);
 
-       std::ofstream ofs;
-       ofs.open(fname.CStr());
+       bool interactive_debugger = Convert::ToBool(ScriptGlobal::Get("AttachDebugger"));
 
-       Log(LogCritical, "Application")
-           << "Icinga 2 has terminated unexpectedly. Additional information can be found in '" << fname << "'" << "\n";
+       if (!interactive_debugger) {
+               std::ofstream ofs;
+               ofs.open(fname.CStr());
 
-       DisplayInfoMessage(ofs);
+               Log(LogCritical, "Application")
+                   << "Icinga 2 has terminated unexpectedly. Additional information can be found in '" << fname << "'" << "\n";
 
-       StackTrace trace;
-       ofs << "Stacktrace:" << "\n";
-       trace.Print(ofs, 1);
+               DisplayInfoMessage(ofs);
 
-       DisplayBugMessage(ofs);
+               StackTrace trace;
+               ofs << "Stacktrace:" << "\n";
+               trace.Print(ofs, 1);
 
-#ifndef _WIN32
-       ofs << "\n";
-       ofs.close();
+               DisplayBugMessage(ofs);
 
-       GetDebuggerBacktrace(fname);
-#else /* _WIN32 */
-       ofs.close();
-#endif /* _WIN32 */
+               ofs << "\n";
+               ofs.close();
+       } else {
+               Log(LogCritical, "Application", "Icinga 2 has terminated unexpeectedly. Attaching debugger...");
+       }
+
+       AttachDebugger(fname, interactive_debugger);
 }
-#else /* _WIN32 */
+
+#ifdef _WIN32
 /**
  * Console control handler. Prepares the application for cleanly
  * shutting down during the next execution of the event loop.
@@ -813,35 +835,37 @@ void Application::ExceptionHandler(void)
        String fname = GetCrashReportFilename();
        Utility::MkDir(Utility::DirName(fname), 0750);
 
-       std::ofstream ofs;
-       ofs.open(fname.CStr());
+       bool interactive_debugger = Convert::ToBool(ScriptGlobal::Get("AttachDebugger"));
 
-       ofs << "Caught unhandled exception." << "\n"
-           << "Current time: " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", Utility::GetTime()) << "\n"
-           << "\n";
+       if (interactive_debugger) {
+               std::ofstream ofs;
+               ofs.open(fname.CStr());
 
-       DisplayInfoMessage(ofs);
+               ofs << "Caught unhandled exception." << "\n"
+                   << "Current time: " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", Utility::GetTime()) << "\n"
+                   << "\n";
 
-       try {
-               RethrowUncaughtException();
-       } catch (const std::exception& ex) {
-               Log(LogCritical, "Application")
-                   << DiagnosticInformation(ex, false) << "\n"
-                   << "\n"
-                   << "Additional information is available in '" << fname << "'" << "\n";
+               DisplayInfoMessage(ofs);
 
-               ofs << "\n"
-                   << DiagnosticInformation(ex)
-                   << "\n";
-       }
+               try {
+                       RethrowUncaughtException();
+               } catch (const std::exception& ex) {
+                       Log(LogCritical, "Application")
+                           << DiagnosticInformation(ex, false) << "\n"
+                           << "\n"
+                           << "Additional information is available in '" << fname << "'" << "\n";
+
+                       ofs << "\n"
+                           << DiagnosticInformation(ex)
+                           << "\n";
+               }
 
-       DisplayBugMessage(ofs);
+               DisplayBugMessage(ofs);
 
-       ofs.close();
+               ofs.close();
+       }
 
-#ifndef _WIN32
-       GetDebuggerBacktrace(fname);
-#endif /* _WIN32 */
+       AttachDebugger(fname, interactive_debugger);
 
        abort();
 }
index ffcfacefa8c77ff5f7c029017cdf6b4a629f5564..a874db9c0f5f61e14bbab5d698edadd197a9bb0a 100644 (file)
@@ -175,9 +175,7 @@ private:
 
        static String GetCrashReportFilename(void);
 
-#ifndef _WIN32
-       static void GetDebuggerBacktrace(const String& filename);
-#endif /* _WIN32 */
+       static void AttachDebugger(const String& filename, bool interactive);
 };
 
 }