Using terminate handler [#CONV-2807].

This commit is contained in:
Alexey Milovidov 2013-01-13 21:02:41 +00:00
parent d726110f17
commit 0d99e28531
2 changed files with 81 additions and 5 deletions

View File

@ -249,7 +249,7 @@ void TCPHandler::receiveHello()
<< "." << client_version_minor << "." << client_version_minor
<< "." << client_revision << "." << client_revision
<< (!default_database.empty() ? ", database: " + default_database : "") << (!default_database.empty() ? ", database: " + default_database : "")
<< ".") << ".");
} }

View File

@ -1,7 +1,10 @@
#include <Yandex/daemon.h> #include <Yandex/daemon.h>
#include <signal.h> #include <signal.h>
#include <cxxabi.h>
#include <typeinfo>
#include <Yandex/logger_useful.h> #include <Yandex/logger_useful.h>
#include <Yandex/mkdir.h> #include <Yandex/mkdir.h>
#include <Yandex/KillingErrorHandler.h> #include <Yandex/KillingErrorHandler.h>
@ -82,6 +85,76 @@ public:
}; };
/** Для использования с помощью std::set_terminate.
* Выводит чуть больше информации, чем __gnu_cxx::__verbose_terminate_handler,
* и выводит её в лог, а не в stderr.
* См. исходники в libstdc++-v3/libsupc++/vterminate.cc
*/
void terminate_handler()
{
Logger * log = &Logger::get("Daemon");
static bool terminating = false;
if (terminating)
{
LOG_ERROR(log, "Terminate called recursively");
abort();
}
terminating = true;
std::type_info * t = abi::__cxa_current_exception_type();
if (t)
{
// Note that "name" is the mangled name.
char const * name = t->name();
{
int status = -1;
char * dem = 0;
dem = abi::__cxa_demangle(name, 0, 0, &status);
LOG_ERROR(log, "Terminate called after throwing an instance of " << (status == 0 ? dem : name));
if (status == 0)
free(dem);
}
// If the exception is derived from std::exception, we can
// give more information.
try
{
throw;
}
catch (DB::Exception & e)
{
LOG_ERROR(log, "Code: " << e.code() << ", e.displayText() = " << e.displayText() << ", e.what() = " << e.what());
LOG_ERROR(log, "Stack trace:\n\n" << DB::StackTrace().toString());
}
catch (Poco::Exception & e)
{
LOG_ERROR(log, "Code: " << e.code() << ", e.displayText() = " << e.displayText() << ", e.what() = " << e.what());
LOG_ERROR(log, "Stack trace:\n\n" << DB::StackTrace().toString());
}
catch (const std::exception & e)
{
LOG_ERROR(log, "what(): " << e.what());
LOG_ERROR(log, "Stack trace:\n\n" << DB::StackTrace().toString());
}
catch (...)
{
LOG_ERROR(log, "Stack trace:\n\n" << DB::StackTrace().toString());
}
}
else
{
LOG_ERROR(log, "Terminate called without an active exception");
}
abort();
}
void Daemon::reloadConfiguration() void Daemon::reloadConfiguration()
{ {
/** Если программа запущена не в режиме демона, и не указан параметр config-file, /** Если программа запущена не в режиме демона, и не указан параметр config-file,
@ -227,13 +300,16 @@ void Daemon::initialize(Application& self)
m_Pid.seed(config().getString("pid")); m_Pid.seed(config().getString("pid"));
} }
// Считаем конфигурацию /// Считаем конфигурацию
reloadConfiguration(); reloadConfiguration();
// Ставим ErrorHandler для потоков /// Ставим terminate_handler
std::set_terminate(terminate_handler);
/// Ставим ErrorHandler для потоков
Poco::ErrorHandler::set(new Yandex::KillingErrorHandler()); Poco::ErrorHandler::set(new Yandex::KillingErrorHandler());
// Выведем ревизию демона /// Выведем ревизию демона
Logger::root().information("Starting daemon with svn revision " + Poco::NumberFormatter::format(SVN_REVISION)); Logger::root().information("Starting daemon with svn revision " + Poco::NumberFormatter::format(SVN_REVISION));
/// Порт, при получении датаграммы на котором, будить демон. /// Порт, при получении датаграммы на котором, будить демон.