Added signal handler and refactored exception handler

Summary: Added signal handler and refactored exception handler

Test Plan: manual

Reviewers: buda

Subscribers: buda

Differential Revision: https://memgraph.phacility.com/D17
This commit is contained in:
sale 2016-12-16 12:56:36 +00:00
parent 58b9c45ff2
commit 9154f9b719
5 changed files with 158 additions and 101 deletions

View File

@ -1,8 +0,0 @@
{
"linters": {
"cppcheck": {
"type": "cppcheck",
"include": ["(\\.cpp$)", "(\\.hpp$)"]
}
}
}

View File

@ -0,0 +1,41 @@
#include <csignal>
#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>
using Function = std::function<void()>;
enum class Signal : int {
Terminate = SIGTERM,
SegmentationFault = SIGSEGV,
Interupt = SIGINT,
Quit = SIGQUIT,
Abort = SIGABRT
};
class SignalHandler {
private:
static std::map<int, std::function<void()>> handlers_;
static void handle(int signal) { handlers_[signal](); }
public:
static void register_handler(Signal signal, Function func) {
int signal_number = static_cast<int>(signal);
handlers_[signal_number] = func;
std::signal(signal_number, SignalHandler::handle);
}
// TODO possible changes if signelton needed later
/*
static SignalHandler& instance() {
static SignalHandler instance;
return instance;
}
*/
};
std::map<int, std::function<void()>> SignalHandler::handlers_ = {};

View File

@ -1,48 +1,35 @@
#pragma once
#include "utils/auto_scope.hpp"
#include "utils/stacktrace.hpp"
#include <iostream>
#include <execinfo.h>
#include <iostream>
// TODO: log to local file or remote database
void stacktrace(std::ostream& stream) noexcept
{
void* array[50];
int size = backtrace(array, 50);
void stacktrace(std::ostream& stream) noexcept {
Stacktrace stacktrace;
stream << __FUNCTION__ << " backtrace returned "
<< size << " frames." << std::endl;
std::string message;
char** messages = backtrace_symbols(array, size);
Auto(free(messages));
for (int i = 0; i < size && messages != NULL; ++i)
stream << "[bt]: (" << i << ") " << messages[i] << std::endl;
stream << std::endl;
for (int i = 0; i < stacktrace.size(); i++) {
message.append(fmt::format("\n at {} ({})", stacktrace[i].function,
stacktrace[i].location));
}
stream << message << std::endl;
}
// TODO: log to local file or remote database
void terminate_handler(std::ostream& stream) noexcept
{
if (auto exc = std::current_exception())
{
try
{
std::rethrow_exception(exc);
}
catch(std::exception& ex)
{
stream << ex.what() << std::endl << std::endl;
stacktrace(stream);
}
void terminate_handler(std::ostream& stream) noexcept {
if (auto exc = std::current_exception()) {
try {
std::rethrow_exception(exc);
} catch (std::exception& ex) {
stream << ex.what() << std::endl << std::endl;
stacktrace(stream);
}
std::abort();
}
std::abort();
}
void terminate_handler() noexcept
{
terminate_handler(std::cout);
}
void terminate_handler() noexcept { terminate_handler(std::cout); }

View File

@ -1,5 +1,5 @@
#include <iostream>
#include <signal.h>
#include <iostream>
#include "communication/bolt/v1/server/server.hpp"
#include "communication/bolt/v1/server/worker.hpp"
@ -9,74 +9,84 @@
#include "logging/default.hpp"
#include "logging/streams/stdout.hpp"
#include "utils/signals/handler.hpp"
#include "utils/stacktrace.hpp"
#include "utils/terminate_handler.hpp"
static bolt::Server<bolt::Worker>* serverptr;
Logger logger;
void sigint_handler(int s)
{
auto signal = s == SIGINT ? "SIGINT" : "SIGABRT";
logger.info("Recieved signal {}", signal);
logger.info("Shutting down...");
std::exit(EXIT_SUCCESS);
}
static constexpr const char* interface = "0.0.0.0";
static constexpr const char* port = "7687";
int main(void)
{
// TODO figure out what is the relationship between this and signals
// that are configured below
std::set_terminate(&terminate_handler);
void throw_and_stacktace(std::string message) {
Stacktrace stacktrace;
// logger init
#ifdef SYNC_LOGGER
logging::init_sync();
#else
logging::init_async();
#endif
logging::log->pipe(std::make_unique<Stdout>());
for (int i = 0; i < stacktrace.size(); i++)
message.append(fmt::format("\n at {} ({})", stacktrace[i].function,
stacktrace[i].location));
// get Main logger
logger = logging::log->logger("Main");
logger.info("{}", logging::log->type());
signal(SIGINT, sigint_handler);
signal(SIGABRT, sigint_handler);
io::Socket socket;
try
{
socket = io::Socket::bind(interface, port);
}
catch(io::NetworkError e)
{
logger.error("Cannot bind to socket on {} at {}", interface, port);
logger.error("{}", e.what());
std::exit(EXIT_FAILURE);
}
socket.set_non_blocking();
socket.listen(1024);
logger.info("Listening on {} at {}", interface, port);
bolt::Server<bolt::Worker> server(std::move(socket));
serverptr = &server;
// TODO: N should be configurable
auto N = std::thread::hardware_concurrency();
logger.info("Starting {} workers", N);
server.start(N);
logger.info("Shutting down...");
return EXIT_SUCCESS;
logger.info(message);
}
int main(void) {
// TODO figure out what is the relationship between this and signals
// that are configured below
std::set_terminate(&terminate_handler);
// logger init
#ifdef SYNC_LOGGER
logging::init_sync();
#else
logging::init_async();
#endif
logging::log->pipe(std::make_unique<Stdout>());
// get Main logger
logger = logging::log->logger("Main");
logger.info("{}", logging::log->type());
SignalHandler::register_handler(Signal::SegmentationFault, []() {
throw_and_stacktace("SegmentationFault signal raised");
exit(1);
});
SignalHandler::register_handler(Signal::Terminate, []() {
throw_and_stacktace("Terminate signal raised");
exit(1);
});
SignalHandler::register_handler(Signal::Abort, []() {
throw_and_stacktace("Abort signal raised");
exit(1);
});
io::Socket socket;
try {
socket = io::Socket::bind(interface, port);
} catch (io::NetworkError e) {
logger.error("Cannot bind to socket on {} at {}", interface, port);
logger.error("{}", e.what());
std::exit(EXIT_FAILURE);
}
socket.set_non_blocking();
socket.listen(1024);
logger.info("Listening on {} at {}", interface, port);
bolt::Server<bolt::Worker> server(std::move(socket));
serverptr = &server;
// TODO: N should be configurable
auto N = std::thread::hardware_concurrency();
logger.info("Starting {} workers", N);
server.start(N);
logger.info("Shutting down...");
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,27 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <iostream>
#include <string>
#include <utility>
#include "utils/signals/handler.hpp"
#include "utils/stacktrace.hpp"
TEST_CASE("SignalHandler Segmentation Fault Test") {
SignalHandler::register_handler(Signal::SegmentationFault, []() {
std::cout << "Segmentation Fault" << std::endl;
Stacktrace stacktrace;
int size = 10;
std::string message;
for (int i = 0; i < size; i++) {
message.append(fmt::format("\n at {} ({})", stacktrace[i].function,
stacktrace[i].location));
}
std::cout << message << std::endl;
});
std::raise(SIGSEGV);
}