在Linux上使用C ++记录进程终止的原因

时间:2012-04-11 22:12:47

标签: c++ linux logging handle terminate

有没有办法记录,处理或以其他方式留下关于进程终止的原因,包括尽可能多的终止事件?

我的应用程序有一个日志记录工具,每分钟都会记录许多消息。我在一个超级try-catch块中运行几乎整个程序,所以我可以记录任何未处理的异常。我最近还尝试为可能终止该过程的各种过程信号注册处理程序。但是,应用程序每天仍然会崩溃几次,我不明白为什么。

我可能无法记录或处理多少其他致命事件?我希望有一种正确的方法可以做到这一点,而不是一直处于黑暗中,当这个过程为一些我尚未意识到的新事件而死时。

非常感谢。

5 个答案:

答案 0 :(得分:2)

拥有超级try/catch块意味着可捕获的异常不会被处理。请注意,对于所有已启动的线程,您将需要这些块。

除此之外,您可以使用signal来捕获终止信号。这些是:

  • SIGABRT(信号中止)异常终止,例如由中止功能启动。
  • SIGFPE(信号浮点异常)错误的算术运算,例如零分频或导致溢出的操作(不一定是浮点运算)。
  • SIGILL(信号非法指令)无效的功能图像,例如非法指令。这通常是由于代码中的损坏或尝试执行数据。
  • SIGINT(信号中断)交互式注意信号。通常由应用程序用户生成。
  • SIGSEGV(信号分段违规)对存储的无效访问:当程序尝试在内存外读取或写入时,会为其分配。 SIGTERM(信号终止)终止请求发送到程序。
  • 由实现定义的信号,但大多数崩溃原因都应该包括在内。

同样,可能是程序没有崩溃,但是通过从main返回(但我猜你已经有了覆盖)或通过调用exit来终止。在这种情况下,您可以检查程序的返回值并记录该。

答案 1 :(得分:2)

您可以注册一个函数来处理意外异常:

set_unexpected()

如果没有delt将导致应用程序调用terminat()。

您可以注册一个函数来记录终止事项:

set_terminate()

你可以添加你自己的atexit()日志记录函数来做东西(设置一个标志,这样只有在退出异常时才会执行操作然后在离开main之前设置标志)。

信号处理程序可能很棘手(特别是如果您希望它们是可移植的)。如果您使用它们,那么您可以安全地在内部进行限制,因此我通常将自己限制为设置全局标志,以便可以通过普通代码处理它们(当然,如果您要终止,那么这是非常有限的)。

答案 2 :(得分:2)

这是我在我的程序中使用的,它对我有用....每当我的程序崩溃时,它会将崩溃站点的堆栈跟踪打印到stdout(可能会重定向到文件或其他以后可以读取的文件) )。

请注意,您可能需要将-dynamic作为标志传递到Makefile中的CXXFLAGS和/或LFLAGS中,以确保堆栈跟踪包含人类可读的函数名称。

#include <stdio.h>
#include <signal.h>
#include <execinfo.h>

void PrintStackTrace()
{
   void *array[256];
   size_t size = backtrace(array, 256);
   char ** strings = backtrace_symbols(array, 256);
   if (strings)
   {
      printf("--Stack trace follows (%zd frames):\n", size);
      for (size_t i = 0; i < size; i++) printf("  %s\n", strings[i]);
      printf("--End Stack trace\n");
      free(strings);
   }
   else printf("PrintStackTrace:  Error, could not generate stack trace!\n");
}

static void CrashSignalHandler(int sig)
{
   // Uninstall this handler, to avoid the possibility of an infinite regress
   signal(SIGSEGV, SIG_DFL);
   signal(SIGBUS,  SIG_DFL);
   signal(SIGILL,  SIG_DFL);
   signal(SIGABRT, SIG_DFL);
   signal(SIGFPE,  SIG_DFL);

   printf("CrashSignalHandler called with signal %i... I'm going to print a stack trace, then kill the process.\n", sig);
   PrintStackTrace();
   printf("Crashed process aborting now.... bye!\n");
   fflush(stdout);
   abort();
}

int main(int argc, char ** argv)
{
   signal(SIGSEGV, CrashSignalHandler);
   signal(SIGBUS,  CrashSignalHandler);
   signal(SIGILL,  CrashSignalHandler);
   signal(SIGABRT, CrashSignalHandler);
   signal(SIGFPE,  CrashSignalHandler);

   [...remainder of your program goes here...]
}

答案 3 :(得分:0)

一个代码值得多说:

#include <iostream>
#include <signal.h>

sigint_handler(int s) {
    std::cout<<"signal caught: "<<s<<std::endl;
    ::exit(-1);
}

void setup_signal() {
    struct sigaction sigIntHandler;
    sigIntHandler.sa_handler = sigint_handler;
    sigemptyset(&sigIntHandler.sa_mask);
    sigIntHandler.sa_flags = 0;
    sigaction(SIGINT, &sigIntHandler, NULL);
    sigaction(SIGTERM, &sigIntHandler, NULL);
}

int main() {
    setup_signal();
    /* do stuff */
    return 0;
}

当然,这只会处理SIGINT / SIGTERM信号。您还必须使用所有atexit(),set_terminate,super try / catch等更新此代码。您可以找到。如果您遇到段错误/总线错误/无论如何......那么你注定要失败:)

答案 4 :(得分:0)

看看这个问题。 How to find the reason for a dead process without log file on unix?

在那里你会看到使用bash获取进程的退出代码比使用信号处理程序或任何类型的退出回调更容易