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:
parent
58b9c45ff2
commit
9154f9b719
8
.arclint
8
.arclint
@ -1,8 +0,0 @@
|
||||
{
|
||||
"linters": {
|
||||
"cppcheck": {
|
||||
"type": "cppcheck",
|
||||
"include": ["(\\.cpp$)", "(\\.hpp$)"]
|
||||
}
|
||||
}
|
||||
}
|
41
include/utils/signals/handler.hpp
Normal file
41
include/utils/signals/handler.hpp
Normal 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_ = {};
|
@ -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); }
|
||||
|
@ -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;
|
||||
}
|
||||
|
27
tests/unit/signal_handler.cpp
Normal file
27
tests/unit/signal_handler.cpp
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user