Skip to content

Commit

Permalink
Print changed settings on fatal errors
Browse files Browse the repository at this point in the history
porting ClickHouse/ClickHouse#51138 on Jun19 ,2023
  • Loading branch information
yokofly committed Feb 27, 2024
1 parent 8cc457b commit a0c6451
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 59 deletions.
2 changes: 1 addition & 1 deletion src/Access/ContextAccess.cpp
Expand Up @@ -256,7 +256,7 @@ void ContextAccess::calculateAccessRights() const
boost::algorithm::join(roles_info->getCurrentRolesNames(), ", "),
boost::algorithm::join(roles_info->getEnabledRolesNames(), ", "));
}
LOG_TRACE(trace_log, "Settings: readonly={}, allow_ddl={}, allow_introspection_functions={}", params.readonly, params.allow_ddl, params.allow_introspection);
LOG_TRACE(trace_log, "Settings: readonly = {}, allow_ddl = {}, allow_introspection_functions = {}", params.readonly, params.allow_ddl, params.allow_introspection);
LOG_TRACE(trace_log, "List of all grants: {}", access->toString());
LOG_TRACE(trace_log, "List of all grants including implicit: {}", access_with_implicit->toString());
}
Expand Down
16 changes: 10 additions & 6 deletions src/Core/BaseSettings.h
Expand Up @@ -2,6 +2,8 @@

#include <Core/SettingsFields.h>
#include <Common/SettingsChanges.h>
#include <Common/FieldVisitorToString.h>
#include <IO/Operators.h>
#include <base/range.h>
#include <boost/blank.hpp>
#include <unordered_map>
Expand Down Expand Up @@ -501,14 +503,16 @@ void BaseSettings<Traits_>::read(ReadBuffer & in, SettingsWriteFormat format)
template <typename Traits_>
String BaseSettings<Traits_>::toString() const
{
String res;
for (const auto & field : *this)
WriteBufferFromOwnString out;
bool first = true;
for (const auto & setting : *this)
{
if (!res.empty())
res += ", ";
res += field.getName() + " = " + field.getValueString();
if (!first)
out << ", ";
out << setting.getName() << " = " << applyVisitor(FieldVisitorToString(), setting.getValue());
first = false;
}
return res;
return out.str();
}

template <typename Traits_>
Expand Down
122 changes: 70 additions & 52 deletions src/Daemon/BaseDaemon.cpp
Expand Up @@ -54,6 +54,7 @@
#include <Common/Elf.h>
#include <Common/setThreadName.h>
#include <Common/logger_useful.h>
#include <Interpreters/Context.h>
#include <filesystem>

#include <Loggers/OwnFormattingChannel.h>
Expand All @@ -79,7 +80,9 @@ namespace DB
}
}

DB::PipeFDs signal_pipe;
using namespace DB;

PipeFDs signal_pipe;


/** Reset signal handler to the default and send signal to itself.
Expand All @@ -88,10 +91,10 @@ DB::PipeFDs signal_pipe;
static void call_default_signal_handler(int sig)
{
if (SIG_ERR == signal(sig, SIG_DFL))
DB::throwFromErrno("Cannot set signal handler.", DB::ErrorCodes::CANNOT_SET_SIGNAL_HANDLER);
throwFromErrno("Cannot set signal handler.", ErrorCodes::CANNOT_SET_SIGNAL_HANDLER);

if (0 != raise(sig))
DB::throwFromErrno("Cannot send signal.", DB::ErrorCodes::CANNOT_SEND_SIGNAL);
throwFromErrno("Cannot send signal.", ErrorCodes::CANNOT_SEND_SIGNAL);
}

static const size_t signal_pipe_buf_size =
Expand All @@ -109,8 +112,8 @@ static void writeSignalIDtoSignalPipe(int sig)
auto saved_errno = errno; /// We must restore previous value of errno in signal handler.

char buf[signal_pipe_buf_size];
DB::WriteBufferFromFileDescriptor out(signal_pipe.fds_rw[1], signal_pipe_buf_size, buf);
DB::writeBinary(sig, out);
WriteBufferFromFileDescriptor out(signal_pipe.fds_rw[1], signal_pipe_buf_size, buf);
writeBinary(sig, out);
out.next();

errno = saved_errno;
Expand Down Expand Up @@ -139,17 +142,17 @@ static void signalHandler(int sig, siginfo_t * info, void * context)
auto saved_errno = errno; /// We must restore previous value of errno in signal handler.

char buf[signal_pipe_buf_size];
DB::WriteBufferFromFileDescriptorDiscardOnFailure out(signal_pipe.fds_rw[1], signal_pipe_buf_size, buf);
WriteBufferFromFileDescriptorDiscardOnFailure out(signal_pipe.fds_rw[1], signal_pipe_buf_size, buf);

const ucontext_t * signal_context = reinterpret_cast<ucontext_t *>(context);
const StackTrace stack_trace(*signal_context);

DB::writeBinary(sig, out);
DB::writePODBinary(*info, out);
DB::writePODBinary(signal_context, out);
DB::writePODBinary(stack_trace, out);
DB::writeBinary(static_cast<UInt32>(getThreadId()), out);
DB::writePODBinary(DB::current_thread, out);
writeBinary(sig, out);
writePODBinary(*info, out);
writePODBinary(signal_context, out);
writePODBinary(stack_trace, out);
writeBinary(static_cast<UInt32>(getThreadId()), out);
writePODBinary(current_thread, out);

out.next();

Expand Down Expand Up @@ -201,12 +204,12 @@ class SignalListener : public Poco::Runnable
static_assert(PIPE_BUF >= 512);
static_assert(signal_pipe_buf_size <= PIPE_BUF, "Only write of PIPE_BUF to pipe is atomic and the minimal known PIPE_BUF across supported platforms is 512");
char buf[signal_pipe_buf_size];
DB::ReadBufferFromFileDescriptor in(signal_pipe.fds_rw[0], signal_pipe_buf_size, buf);
ReadBufferFromFileDescriptor in(signal_pipe.fds_rw[0], signal_pipe_buf_size, buf);

while (!in.eof())
{
int sig = 0;
DB::readBinary(sig, in);
readBinary(sig, in);
// We may log some specific signals afterwards, with different log
// levels and more info, but for completeness we log all signals
// here at trace level.
Expand All @@ -229,8 +232,8 @@ class SignalListener : public Poco::Runnable
UInt32 thread_num;
std::string message;

DB::readBinary(thread_num, in);
DB::readBinary(message, in);
readBinary(thread_num, in);
readBinary(message, in);

onTerminate(message, thread_num);
}
Expand All @@ -246,17 +249,17 @@ class SignalListener : public Poco::Runnable
ucontext_t * context{};
StackTrace stack_trace(NoCapture{});
UInt32 thread_num{};
DB::ThreadStatus * thread_ptr{};
ThreadStatus * thread_ptr{};

if (sig != SanitizerTrap)
{
DB::readPODBinary(info, in);
DB::readPODBinary(context, in);
readPODBinary(info, in);
readPODBinary(context, in);
}

DB::readPODBinary(stack_trace, in);
DB::readBinary(thread_num, in);
DB::readPODBinary(thread_ptr, in);
readPODBinary(stack_trace, in);
readBinary(thread_num, in);
readPODBinary(thread_ptr, in);

/// This allows to receive more signals if failure happens inside onFault function.
/// Example: segfault while symbolizing stack trace.
Expand Down Expand Up @@ -304,9 +307,9 @@ class SignalListener : public Poco::Runnable
ucontext_t * context,
const StackTrace & stack_trace,
UInt32 thread_num,
DB::ThreadStatus * thread_ptr) const
ThreadStatus * thread_ptr) const
{
DB::ThreadStatus thread_status;
ThreadStatus thread_status;

/// First log those fields that are safe to access and that should not cause new fault.
/// That way we will have some duplicated info in the log but we don't loose important info
Expand Down Expand Up @@ -345,12 +348,12 @@ class SignalListener : public Poco::Runnable
/// NOTE: This still require memory allocations and mutex lock inside logger.
/// BTW we can also print it to stderr using write syscalls.

DB::WriteBufferFromOwnString bare_stacktrace;
DB::writeString("Stack trace:", bare_stacktrace);
WriteBufferFromOwnString bare_stacktrace;
writeString("Stack trace:", bare_stacktrace);
for (size_t i = stack_trace.getOffset(); i < stack_trace.getSize(); ++i)
{
DB::writeChar(' ', bare_stacktrace);
DB::writePointerHex(stack_trace.getFramePointers()[i], bare_stacktrace);
writeChar(' ', bare_stacktrace);
writePointerHex(stack_trace.getFramePointers()[i], bare_stacktrace);
}

LOG_FATAL(log, fmt::runtime(bare_stacktrace.str()));
Expand All @@ -375,7 +378,7 @@ class SignalListener : public Poco::Runnable

if (auto logs_queue = thread_ptr->getInternalTextLogsQueue())
{
DB::CurrentThread::attachInternalTextLogsQueue(logs_queue, DB::LogsLevel::trace);
CurrentThread::attachInternalTextLogsQueue(logs_queue, LogsLevel::trace);
}
}

Expand Down Expand Up @@ -445,6 +448,21 @@ class SignalListener : public Poco::Runnable
if (sig != SanitizerTrap)
SentryWriter::onFault(sig, error_message, stack_trace);

/// List changed settings.
if (!query_id.empty())
{
ContextPtr query_context = thread_ptr->getQueryContext();
if (query_context)
{
String changed_settings = query_context->getSettingsRef().toString();

if (changed_settings.empty())
LOG_FATAL(log, "No settings were changed");
else
LOG_FATAL(log, "Changed settings: {}", changed_settings);
}
}

/// When everything is done, we will try to send these error messages to client.
if (thread_ptr)
thread_ptr->onFatalError();
Expand All @@ -468,15 +486,15 @@ static DISABLE_SANITIZER_INSTRUMENTATION void sanitizerDeathCallback()
/// Also need to send data via pipe. Otherwise it may lead to deadlocks or failures in printing diagnostic info.

char buf[signal_pipe_buf_size];
DB::WriteBufferFromFileDescriptorDiscardOnFailure out(signal_pipe.fds_rw[1], signal_pipe_buf_size, buf);
WriteBufferFromFileDescriptorDiscardOnFailure out(signal_pipe.fds_rw[1], signal_pipe_buf_size, buf);

const StackTrace stack_trace;

int sig = SignalListener::SanitizerTrap;
DB::writeBinary(sig, out);
DB::writePODBinary(stack_trace, out);
DB::writeBinary(UInt32(getThreadId()), out);
DB::writePODBinary(DB::current_thread, out);
writeBinary(sig, out);
writePODBinary(stack_trace, out);
writeBinary(UInt32(getThreadId()), out);
writePODBinary(current_thread, out);

out.next();

Expand All @@ -502,7 +520,7 @@ static DISABLE_SANITIZER_INSTRUMENTATION void sanitizerDeathCallback()
std::string log_message;

if (std::current_exception())
log_message = "Terminate called for uncaught exception:\n" + DB::getCurrentExceptionMessage(true);
log_message = "Terminate called for uncaught exception:\n" + getCurrentExceptionMessage(true);
else
log_message = "Terminate called without an active exception";

Expand All @@ -514,11 +532,11 @@ static DISABLE_SANITIZER_INSTRUMENTATION void sanitizerDeathCallback()
log_message.resize(buf_size - 16);

char buf[buf_size];
DB::WriteBufferFromFileDescriptor out(signal_pipe.fds_rw[1], buf_size, buf);
WriteBufferFromFileDescriptor out(signal_pipe.fds_rw[1], buf_size, buf);

DB::writeBinary(static_cast<int>(SignalListener::StdTerminate), out);
DB::writeBinary(static_cast<UInt32>(getThreadId()), out);
DB::writeBinary(log_message, out);
writeBinary(static_cast<int>(SignalListener::StdTerminate), out);
writeBinary(static_cast<UInt32>(getThreadId()), out);
writeBinary(log_message, out);
out.next();

abort();
Expand All @@ -544,7 +562,7 @@ static bool tryCreateDirectories(Poco::Logger * logger, const std::string & path
}
catch (...)
{
LOG_WARNING(logger, "{}: when creating {}, {}", __PRETTY_FUNCTION__, path, DB::getCurrentExceptionMessage(true));
LOG_WARNING(logger, "{}: when creating {}, {}", __PRETTY_FUNCTION__, path, getCurrentExceptionMessage(true));
}
return false;
}
Expand All @@ -559,7 +577,7 @@ void BaseDaemon::reloadConfiguration()
* (It's convenient to log in console when you start server without any command line parameters.)
*/
config_path = config().getString("config-file", getDefaultConfigFileName());
DB::ConfigProcessor config_processor(config_path, false, true);
ConfigProcessor config_processor(config_path, false, true);
config_processor.setConfigPath(fs::path(config_path).parent_path());
loaded_config = config_processor.loadConfig();

Expand All @@ -580,7 +598,7 @@ BaseDaemon::~BaseDaemon()
/// Reset signals to SIG_DFL to avoid trying to write to the signal_pipe that will be closed after.
for (int sig : handled_signals)
if (SIG_ERR == signal(sig, SIG_DFL))
DB::throwFromErrno("Cannot set signal handler.", DB::ErrorCodes::CANNOT_SET_SIGNAL_HANDLER);
throwFromErrno("Cannot set signal handler.", ErrorCodes::CANNOT_SET_SIGNAL_HANDLER);
signal_pipe.close();
}

Expand Down Expand Up @@ -623,7 +641,7 @@ void BaseDaemon::closeFDs()
/// Iterate directory separately from closing fds to avoid closing iterated directory fd.
std::vector<int> fds;
for (const auto & path : fs::directory_iterator(proc_path))
fds.push_back(DB::parse<int>(path.path().filename()));
fds.push_back(parse<int>(path.path().filename()));

for (const auto & fd : fds)
{
Expand Down Expand Up @@ -679,7 +697,7 @@ void BaseDaemon::initialize(Application & self)
}
umask(umask_num);

DB::ConfigProcessor(config_path).savePreprocessedConfig(loaded_config, "");
ConfigProcessor(config_path).savePreprocessedConfig(loaded_config, "");

/// Write core dump on crash.
{
Expand Down Expand Up @@ -730,12 +748,12 @@ void BaseDaemon::initialize(Application & self)
/// {
/// try
/// {
/// DB::SomeApp app;
/// SomeApp app;
/// return app.run(argc, argv);
/// }
/// catch (...)
/// {
/// std::cerr << DB::getCurrentExceptionMessage(true) << "\n";
/// std::cerr << getCurrentExceptionMessage(true) << "\n";
/// return 1;
/// }
/// }
Expand Down Expand Up @@ -786,7 +804,7 @@ void BaseDaemon::initialize(Application & self)

/// Create pid file.
if (config().has("pid"))
pid_file.emplace(config().getString("pid"), DB::StatusFile::write_pid);
pid_file.emplace(config().getString("pid"), StatusFile::write_pid);

if (is_daemon)
{
Expand All @@ -813,7 +831,7 @@ void BaseDaemon::initialize(Application & self)
initializeTerminationAndSignalProcessing();
logRevision();

for (const auto & key : DB::getMultipleKeysFromConfig(config(), "", "graphite"))
for (const auto & key : getMultipleKeysFromConfig(config(), "", "graphite"))
{
graphite_writers.emplace(key, std::make_unique<GraphiteWriter>(key));
}
Expand Down Expand Up @@ -901,7 +919,7 @@ void BaseDaemon::initializeTerminationAndSignalProcessing()
signal_listener_thread.start(*signal_listener);

#if defined(__ELF__) && !defined(OS_FREEBSD)
String build_id_hex = DB::SymbolIndex::instance()->getBuildIDHex();
String build_id_hex = SymbolIndex::instance()->getBuildIDHex();
if (build_id_hex.empty())
build_id = "";
else
Expand All @@ -916,7 +934,7 @@ void BaseDaemon::initializeTerminationAndSignalProcessing()
std::string executable_path = getExecutablePath();

if (!executable_path.empty())
stored_binary_hash = DB::Elf(executable_path).getStoredBinaryHash();
stored_binary_hash = Elf(executable_path).getStoredBinaryHash();
#endif
}

Expand Down Expand Up @@ -977,7 +995,7 @@ void BaseDaemon::handleSignal(int signal_id)
onInterruptSignals(signal_id);
}
else
throw DB::Exception(std::string("Unsupported signal: ") + strsignal(signal_id), 0); // NOLINT(concurrency-mt-unsafe) // it is not thread-safe but ok in this context
throw Exception(std::string("Unsupported signal: ") + strsignal(signal_id), 0); // NOLINT(concurrency-mt-unsafe) // it is not thread-safe but ok in this context
}

void BaseDaemon::onInterruptSignals(int signal_id)
Expand Down Expand Up @@ -1051,7 +1069,7 @@ void BaseDaemon::setupWatchdog()
if (config().getRawString("logger.stream_compress", "false") == "true")
{
Poco::AutoPtr<OwnPatternFormatter> pf = new OwnPatternFormatter;
Poco::AutoPtr<DB::OwnFormattingChannel> log = new DB::OwnFormattingChannel(pf, new Poco::ConsoleChannel(std::cerr));
Poco::AutoPtr<OwnFormattingChannel> log = new OwnFormattingChannel(pf, new Poco::ConsoleChannel(std::cerr));
logger().setChannel(log);
}

Expand Down

0 comments on commit a0c6451

Please sign in to comment.