Fix SHOW CONFIG to show the run-time flag status (#1278)
This commit is contained in:
parent
3ff2c72db9
commit
26e31ca06f
@ -36,7 +36,3 @@ DEFINE_VALIDATED_int32(bolt_session_inactivity_timeout, 1800,
|
|||||||
DEFINE_string(bolt_cert_file, "", "Certificate file which should be used for the Bolt server.");
|
DEFINE_string(bolt_cert_file, "", "Certificate file which should be used for the Bolt server.");
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
DEFINE_string(bolt_key_file, "", "Key file which should be used for the Bolt server.");
|
DEFINE_string(bolt_key_file, "", "Key file which should be used for the Bolt server.");
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
DEFINE_string(bolt_server_name_for_init, "",
|
|
||||||
"Server name which the database should send to the client in the "
|
|
||||||
"Bolt INIT message.");
|
|
||||||
|
@ -26,4 +26,4 @@ DECLARE_string(bolt_cert_file);
|
|||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
DECLARE_string(bolt_key_file);
|
DECLARE_string(bolt_key_file);
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
DECLARE_string(bolt_server_name_for_init);
|
// DECLARE_string(bolt_server_name_for_init); Moved to run_time_configurable
|
||||||
|
@ -145,11 +145,6 @@ DEFINE_string(pulsar_service_url, "", "Default URL used while connecting to Puls
|
|||||||
|
|
||||||
// Query flags.
|
// Query flags.
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
DEFINE_double(query_execution_timeout_sec, -1,
|
|
||||||
"Maximum allowed query execution time. Queries exceeding this "
|
|
||||||
"limit will be aborted. Value of 0 means no limit.");
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
DEFINE_uint64(replication_replica_check_frequency_sec, 1,
|
DEFINE_uint64(replication_replica_check_frequency_sec, 1,
|
||||||
"The time duration between two replica checks/pings. If < 1, replicas will NOT be checked at all. NOTE: "
|
"The time duration between two replica checks/pings. If < 1, replicas will NOT be checked at all. NOTE: "
|
||||||
|
@ -100,7 +100,7 @@ DECLARE_string(pulsar_service_url);
|
|||||||
// Query flags.
|
// Query flags.
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
DECLARE_double(query_execution_timeout_sec);
|
// DECLARE_double(query_execution_timeout_sec); Moved to run_time_configurable
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
DECLARE_string(query_modules_directory);
|
DECLARE_string(query_modules_directory);
|
||||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
@ -26,7 +26,6 @@ using namespace std::string_view_literals;
|
|||||||
|
|
||||||
// Logging flags
|
// Logging flags
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
DEFINE_HIDDEN_bool(also_log_to_stderr, false, "Log messages go to stderr in addition to logfiles");
|
|
||||||
DEFINE_string(log_file, "", "Path to where the log should be stored.");
|
DEFINE_string(log_file, "", "Path to where the log should be stored.");
|
||||||
|
|
||||||
inline constexpr std::array log_level_mappings{
|
inline constexpr std::array log_level_mappings{
|
||||||
@ -34,11 +33,8 @@ inline constexpr std::array log_level_mappings{
|
|||||||
std::pair{"INFO"sv, spdlog::level::info}, std::pair{"WARNING"sv, spdlog::level::warn},
|
std::pair{"INFO"sv, spdlog::level::info}, std::pair{"WARNING"sv, spdlog::level::warn},
|
||||||
std::pair{"ERROR"sv, spdlog::level::err}, std::pair{"CRITICAL"sv, spdlog::level::critical}};
|
std::pair{"ERROR"sv, spdlog::level::err}, std::pair{"CRITICAL"sv, spdlog::level::critical}};
|
||||||
|
|
||||||
const std::string log_level_help_string = fmt::format("Minimum log level. Allowed values: {}",
|
const std::string memgraph::flags::log_level_help_string = fmt::format(
|
||||||
memgraph::utils::GetAllowedEnumValuesString(log_level_mappings));
|
"Minimum log level. Allowed values: {}", memgraph::utils::GetAllowedEnumValuesString(log_level_mappings));
|
||||||
|
|
||||||
DEFINE_VALIDATED_string(log_level, "WARNING", log_level_help_string.c_str(),
|
|
||||||
{ return memgraph::flags::ValidLogLevel(value); });
|
|
||||||
|
|
||||||
bool memgraph::flags::ValidLogLevel(std::string_view value) {
|
bool memgraph::flags::ValidLogLevel(std::string_view value) {
|
||||||
if (const auto result = memgraph::utils::IsValidEnumValueString(value, log_level_mappings); result.HasError()) {
|
if (const auto result = memgraph::utils::IsValidEnumValueString(value, log_level_mappings); result.HasError()) {
|
||||||
@ -65,7 +61,9 @@ std::optional<spdlog::level::level_enum> memgraph::flags::LogLevelToEnum(std::st
|
|||||||
}
|
}
|
||||||
|
|
||||||
spdlog::level::level_enum ParseLogLevel() {
|
spdlog::level::level_enum ParseLogLevel() {
|
||||||
const auto log_level = memgraph::flags::LogLevelToEnum(FLAGS_log_level);
|
std::string ll;
|
||||||
|
gflags::GetCommandLineOption("log_level", &ll);
|
||||||
|
const auto log_level = memgraph::flags::LogLevelToEnum(ll);
|
||||||
MG_ASSERT(log_level, "Invalid log level");
|
MG_ASSERT(log_level, "Invalid log level");
|
||||||
return *log_level;
|
return *log_level;
|
||||||
}
|
}
|
||||||
@ -77,10 +75,6 @@ void CreateLoggerFromSink(const auto &sinks, const auto log_level) {
|
|||||||
logger->set_level(log_level);
|
logger->set_level(log_level);
|
||||||
logger->flush_on(spdlog::level::trace);
|
logger->flush_on(spdlog::level::trace);
|
||||||
spdlog::set_default_logger(std::move(logger));
|
spdlog::set_default_logger(std::move(logger));
|
||||||
// Enable stderr sink
|
|
||||||
if (FLAGS_also_log_to_stderr) {
|
|
||||||
memgraph::flags::LogToStderr(log_level);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void memgraph::flags::InitializeLogger() {
|
void memgraph::flags::InitializeLogger() {
|
||||||
@ -117,6 +111,14 @@ void memgraph::flags::AddLoggerSink(spdlog::sink_ptr new_sink) {
|
|||||||
// NOTE: default_logger is not thread-safe and shouldn't be changed during application lifetime
|
// NOTE: default_logger is not thread-safe and shouldn't be changed during application lifetime
|
||||||
void memgraph::flags::LogToStderr(spdlog::level::level_enum log_level) {
|
void memgraph::flags::LogToStderr(spdlog::level::level_enum log_level) {
|
||||||
auto default_logger = spdlog::default_logger();
|
auto default_logger = spdlog::default_logger();
|
||||||
auto sink = default_logger->sinks().front();
|
auto stderr = default_logger->sinks().front();
|
||||||
sink->set_level(log_level);
|
stderr->set_level(log_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void memgraph::flags::UpdateStderr(spdlog::level::level_enum log_level) {
|
||||||
|
auto default_logger = spdlog::default_logger();
|
||||||
|
auto stderr = default_logger->sinks().front();
|
||||||
|
if (stderr->level() != spdlog::level::off) {
|
||||||
|
stderr->set_level(log_level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,16 +14,19 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include "gflags/gflags.h"
|
#include "gflags/gflags.h"
|
||||||
|
|
||||||
DECLARE_string(log_level);
|
// DECLARE_string(log_level); Moved to run_time_configurable
|
||||||
DECLARE_bool(also_log_to_stderr);
|
// DECLARE_bool(also_log_to_stderr); Moved to run_time_configurable
|
||||||
|
|
||||||
namespace memgraph::flags {
|
namespace memgraph::flags {
|
||||||
|
|
||||||
|
extern const std::string log_level_help_string;
|
||||||
|
|
||||||
bool ValidLogLevel(std::string_view value);
|
bool ValidLogLevel(std::string_view value);
|
||||||
std::optional<spdlog::level::level_enum> LogLevelToEnum(std::string_view value);
|
std::optional<spdlog::level::level_enum> LogLevelToEnum(std::string_view value);
|
||||||
|
|
||||||
void InitializeLogger();
|
void InitializeLogger();
|
||||||
void AddLoggerSink(spdlog::sink_ptr new_sink);
|
void AddLoggerSink(spdlog::sink_ptr new_sink);
|
||||||
void LogToStderr(spdlog::level::level_enum log_level);
|
void LogToStderr(spdlog::level::level_enum log_level);
|
||||||
|
void UpdateStderr(spdlog::level::level_enum log_level);
|
||||||
|
|
||||||
} // namespace memgraph::flags
|
} // namespace memgraph::flags
|
||||||
|
@ -10,102 +10,176 @@
|
|||||||
// licenses/APL.txt.
|
// licenses/APL.txt.
|
||||||
|
|
||||||
#include "flags/run_time_configurable.hpp"
|
#include "flags/run_time_configurable.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "gflags/gflags.h"
|
||||||
|
|
||||||
#include "flags/bolt.hpp"
|
#include "flags/bolt.hpp"
|
||||||
#include "flags/general.hpp"
|
#include "flags/general.hpp"
|
||||||
#include "flags/log_level.hpp"
|
#include "flags/log_level.hpp"
|
||||||
#include "spdlog/cfg/helpers-inl.h"
|
#include "spdlog/cfg/helpers-inl.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include "utils/exceptions.hpp"
|
#include "utils/exceptions.hpp"
|
||||||
|
#include "utils/flag_validation.hpp"
|
||||||
#include "utils/settings.hpp"
|
#include "utils/settings.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup GFlags
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Bolt server flags.
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
DEFINE_string(bolt_server_name_for_init, "Neo4j/v5.11.0 compatible graph database server - Memgraph",
|
||||||
|
"Server name which the database should send to the client in the "
|
||||||
|
"Bolt INIT message.");
|
||||||
|
|
||||||
|
// Logging flags
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
DEFINE_HIDDEN_bool(also_log_to_stderr, false, "Log messages go to stderr in addition to logfiles");
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables, misc-unused-parameters)
|
||||||
|
DEFINE_VALIDATED_string(log_level, "WARNING", memgraph::flags::log_level_help_string.c_str(),
|
||||||
|
{ return memgraph::flags::ValidLogLevel(value); });
|
||||||
|
|
||||||
|
// Query flags
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
DEFINE_double(query_execution_timeout_sec, 600,
|
||||||
|
"Maximum allowed query execution time. Queries exceeding this "
|
||||||
|
"limit will be aborted. Value of 0 means no limit.");
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Bolt server name
|
// Bolt server name
|
||||||
constexpr auto kServerNameSettingKey = "server.name";
|
constexpr auto kServerNameSettingKey = "server.name";
|
||||||
constexpr auto kDefaultServerName = "Neo4j/v5.11.0 compatible graph database server - Memgraph";
|
constexpr auto kServerNameGFlagsKey = "bolt_server_name_for_init";
|
||||||
// Query timeout
|
// Query timeout
|
||||||
constexpr auto kQueryTxSettingKey = "query.timeout";
|
constexpr auto kQueryTxSettingKey = "query.timeout";
|
||||||
constexpr auto kDefaultQueryTx = "600"; // seconds
|
constexpr auto kQueryTxGFlagsKey = "query_execution_timeout_sec";
|
||||||
// Log level
|
// Log level
|
||||||
// No default value because it is not persistent
|
// No default value because it is not persistent
|
||||||
constexpr auto kLogLevelSettingKey = "log.level";
|
constexpr auto kLogLevelSettingKey = "log.level";
|
||||||
|
constexpr auto kLogLevelGFlagsKey = "log_level";
|
||||||
// Log to stderr
|
// Log to stderr
|
||||||
// No default value because it is not persistent
|
// No default value because it is not persistent
|
||||||
constexpr auto kLogToStderrSettingKey = "log.to_stderr";
|
constexpr auto kLogToStderrSettingKey = "log.to_stderr";
|
||||||
|
constexpr auto kLogToStderrGFlagsKey = "also_log_to_stderr";
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
std::atomic<double> execution_timeout_sec_; // Local cache-like thing
|
||||||
|
|
||||||
|
auto ToLLEnum(std::string_view val) {
|
||||||
|
const auto ll_enum = memgraph::flags::LogLevelToEnum(val);
|
||||||
|
if (!ll_enum) {
|
||||||
|
throw memgraph::utils::BasicException("Unsupported log level {}", val);
|
||||||
|
}
|
||||||
|
return *ll_enum;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValidBoolStr(std::string_view in) {
|
||||||
|
const auto lc = memgraph::utils::ToLowerCase(in);
|
||||||
|
return lc == "false" || lc == "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GenHandler(std::string flag, std::string key) {
|
||||||
|
return [key = std::move(key), flag = std::move(flag)]() -> std::string {
|
||||||
|
const auto &val = memgraph::utils::global_settings.GetValue(key);
|
||||||
|
MG_ASSERT(val, "Failed to read value at '{}' from settings.", key);
|
||||||
|
gflags::SetCommandLineOption(flag.c_str(), val->c_str());
|
||||||
|
return *val;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace memgraph::flags::run_time {
|
namespace memgraph::flags::run_time {
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
memgraph::utils::Synchronized<std::string, memgraph::utils::SpinLock> bolt_server_name_;
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
std::atomic<double> execution_timeout_sec_;
|
|
||||||
|
|
||||||
void Initialize() {
|
void Initialize() {
|
||||||
// Register bolt server name settings
|
constexpr bool kRestore = true; //!< run-time flag is persistent between Memgraph restarts
|
||||||
memgraph::utils::global_settings.RegisterSetting(kServerNameSettingKey, kDefaultServerName, [&] {
|
|
||||||
const auto server_name = memgraph::utils::global_settings.GetValue(kServerNameSettingKey);
|
|
||||||
MG_ASSERT(server_name, "Bolt server name is missing from the settings");
|
|
||||||
*(bolt_server_name_.Lock()) = *server_name;
|
|
||||||
});
|
|
||||||
// Update value from read settings
|
|
||||||
const auto &name = memgraph::utils::global_settings.GetValue(kServerNameSettingKey);
|
|
||||||
MG_ASSERT(name, "Failed to read server name from settings.");
|
|
||||||
*(bolt_server_name_.Lock()) = *name;
|
|
||||||
// Override server name if passed via command line argument
|
|
||||||
if (!FLAGS_bolt_server_name_for_init.empty()) {
|
|
||||||
memgraph::utils::global_settings.SetValue(kServerNameSettingKey, FLAGS_bolt_server_name_for_init);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register query timeout
|
/**
|
||||||
memgraph::utils::global_settings.RegisterSetting(kQueryTxSettingKey, kDefaultQueryTx, [&] {
|
* @brief Helper function that registers a run-time flag
|
||||||
const auto query_tx = memgraph::utils::global_settings.GetValue(kQueryTxSettingKey);
|
*
|
||||||
MG_ASSERT(query_tx, "Query timeout is missing from the settings");
|
* @param flag - GFlag name
|
||||||
execution_timeout_sec_ = std::stod(*query_tx);
|
* @param key - Settings key used to store the flag
|
||||||
});
|
* @param restore - true if the flag is persistent between restarts
|
||||||
// Update value from read settings
|
* @param post_update - user defined callback executed post flag update
|
||||||
const auto &tx = memgraph::utils::global_settings.GetValue(kQueryTxSettingKey);
|
* @param validator - user defined value correctness checker
|
||||||
MG_ASSERT(tx, "Failed to read query timeout from settings.");
|
*/
|
||||||
execution_timeout_sec_ = std::stod(*tx);
|
auto register_flag = [&](
|
||||||
// Override query timeout if passed via command line argument
|
const std::string &flag, const std::string &key, bool restore,
|
||||||
if (FLAGS_query_execution_timeout_sec != -1) {
|
std::function<void(const std::string &)> post_update = [](auto) {},
|
||||||
memgraph::utils::global_settings.SetValue(kQueryTxSettingKey, std::to_string(FLAGS_query_execution_timeout_sec));
|
std::function<bool(std::string_view)> validator = [](std::string_view) { return true; }) {
|
||||||
}
|
// Get flag info
|
||||||
|
gflags::CommandLineFlagInfo info;
|
||||||
|
gflags::GetCommandLineFlagInfo(flag.c_str(), &info);
|
||||||
|
// Register setting
|
||||||
|
auto update = GenHandler(flag, key);
|
||||||
|
memgraph::utils::global_settings.RegisterSetting(
|
||||||
|
key, info.default_value,
|
||||||
|
[update, post_update = std::move(post_update)] {
|
||||||
|
const auto &val = update();
|
||||||
|
post_update(val);
|
||||||
|
},
|
||||||
|
validator);
|
||||||
|
|
||||||
// Register log level
|
if (restore && info.is_default) {
|
||||||
auto get_global_log_level = []() {
|
// No input from the user, restore persistent value from settings
|
||||||
const auto log_level = memgraph::utils::global_settings.GetValue(kLogLevelSettingKey);
|
update();
|
||||||
MG_ASSERT(log_level, "Log level is missing from the settings");
|
} else {
|
||||||
const auto ll_enum = memgraph::flags::LogLevelToEnum(*log_level);
|
// Override with current value - user defined a new value or the run-time flag is not persistent between starts
|
||||||
if (!ll_enum) {
|
memgraph::utils::global_settings.SetValue(key, info.current_value);
|
||||||
throw utils::BasicException("Unsupported log level {}", *log_level);
|
|
||||||
}
|
}
|
||||||
return *ll_enum;
|
|
||||||
};
|
};
|
||||||
memgraph::utils::global_settings.RegisterSetting(
|
|
||||||
kLogLevelSettingKey, FLAGS_log_level, [&] { spdlog::set_level(get_global_log_level()); },
|
|
||||||
memgraph::flags::ValidLogLevel);
|
|
||||||
// Always override log level with command line argument
|
|
||||||
memgraph::utils::global_settings.SetValue(kLogLevelSettingKey, FLAGS_log_level);
|
|
||||||
|
|
||||||
// Register logging to stderr
|
/*
|
||||||
auto bool_to_str = [](bool in) { return in ? "true" : "false"; };
|
* Register bolt server name settings
|
||||||
const std::string log_to_stderr_s = bool_to_str(FLAGS_also_log_to_stderr);
|
*/
|
||||||
memgraph::utils::global_settings.RegisterSetting(
|
register_flag(kServerNameGFlagsKey, kServerNameSettingKey, kRestore);
|
||||||
kLogToStderrSettingKey, log_to_stderr_s,
|
|
||||||
[&] {
|
/*
|
||||||
const auto enable = memgraph::utils::global_settings.GetValue(kLogToStderrSettingKey);
|
* Register query timeout
|
||||||
if (enable == "true") {
|
*/
|
||||||
LogToStderr(get_global_log_level());
|
register_flag(kQueryTxGFlagsKey, kQueryTxSettingKey, !kRestore, [&](const std::string &val) {
|
||||||
|
execution_timeout_sec_ = std::stod(val); // Cache for faster reads
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register log level
|
||||||
|
*/
|
||||||
|
register_flag(
|
||||||
|
kLogLevelGFlagsKey, kLogLevelSettingKey, !kRestore,
|
||||||
|
[](const std::string &val) {
|
||||||
|
const auto ll_enum = ToLLEnum(val);
|
||||||
|
spdlog::set_level(ll_enum);
|
||||||
|
UpdateStderr(ll_enum); // Updates level if active
|
||||||
|
},
|
||||||
|
memgraph::flags::ValidLogLevel);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register logging to stderr
|
||||||
|
*/
|
||||||
|
register_flag(
|
||||||
|
kLogToStderrGFlagsKey, kLogToStderrSettingKey, !kRestore,
|
||||||
|
[](const std::string &val) {
|
||||||
|
if (val == "true") {
|
||||||
|
// No need to check if ll_val exists, we got here, so the log_level must exist already
|
||||||
|
const auto &ll_val = memgraph::utils::global_settings.GetValue(kLogLevelSettingKey);
|
||||||
|
LogToStderr(ToLLEnum(*ll_val));
|
||||||
} else {
|
} else {
|
||||||
LogToStderr(spdlog::level::off);
|
LogToStderr(spdlog::level::off);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[](std::string_view in) {
|
ValidBoolStr);
|
||||||
const auto lc = memgraph::utils::ToLowerCase(in);
|
|
||||||
return lc == "false" || lc == "true";
|
|
||||||
});
|
|
||||||
// Always override log to stderr with command line argument
|
|
||||||
memgraph::utils::global_settings.SetValue(kLogToStderrSettingKey, log_to_stderr_s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetServerName() {
|
||||||
|
std::string s;
|
||||||
|
// Thread safe read of gflag
|
||||||
|
gflags::GetCommandLineOption(kServerNameGFlagsKey, &s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
double GetExecutionTimeout() { return execution_timeout_sec_; }
|
||||||
|
|
||||||
} // namespace memgraph::flags::run_time
|
} // namespace memgraph::flags::run_time
|
||||||
|
@ -15,12 +15,24 @@
|
|||||||
|
|
||||||
namespace memgraph::flags::run_time {
|
namespace memgraph::flags::run_time {
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
/**
|
||||||
extern utils::Synchronized<std::string, utils::SpinLock> bolt_server_name_;
|
* @brief Initialize the run-time flags (must be done before run-time flags are used).
|
||||||
|
*
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
*/
|
||||||
extern std::atomic<double> execution_timeout_sec_;
|
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the bolt server name value
|
||||||
|
*
|
||||||
|
* @return std::string
|
||||||
|
*/
|
||||||
|
std::string GetServerName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the query execution timeout value
|
||||||
|
*
|
||||||
|
* @return double
|
||||||
|
*/
|
||||||
|
double GetExecutionTimeout();
|
||||||
|
|
||||||
} // namespace memgraph::flags::run_time
|
} // namespace memgraph::flags::run_time
|
||||||
|
@ -7,5 +7,5 @@ target_sources(mg-glue PRIVATE auth.cpp
|
|||||||
ServerT.cpp
|
ServerT.cpp
|
||||||
MonitoringServerT.cpp
|
MonitoringServerT.cpp
|
||||||
run_id.cpp)
|
run_id.cpp)
|
||||||
target_link_libraries(mg-glue mg-query mg-auth mg-audit)
|
target_link_libraries(mg-glue mg-query mg-auth mg-audit mg-flags)
|
||||||
target_precompile_headers(mg-glue INTERFACE auth_checker.hpp auth_handler.hpp)
|
target_precompile_headers(mg-glue INTERFACE auth_checker.hpp auth_handler.hpp)
|
||||||
|
@ -122,8 +122,8 @@ std::string SessionHL::GetCurrentDB() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> SessionHL::GetServerNameForInit() {
|
std::optional<std::string> SessionHL::GetServerNameForInit() {
|
||||||
auto locked_name = flags::run_time::bolt_server_name_.Lock();
|
const auto &name = flags::run_time::GetServerName();
|
||||||
return locked_name->empty() ? std::nullopt : std::make_optional(*locked_name);
|
return name.empty() ? std::nullopt : std::make_optional(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SessionHL::Authenticate(const std::string &username, const std::string &password) {
|
bool SessionHL::Authenticate(const std::string &username, const std::string &password) {
|
||||||
|
@ -1433,7 +1433,7 @@ Interpreter::Interpreter(InterpreterContext *interpreter_context, memgraph::dbms
|
|||||||
auto DetermineTxTimeout(std::optional<int64_t> tx_timeout_ms, InterpreterConfig const &config) -> TxTimeout {
|
auto DetermineTxTimeout(std::optional<int64_t> tx_timeout_ms, InterpreterConfig const &config) -> TxTimeout {
|
||||||
using double_seconds = std::chrono::duration<double>;
|
using double_seconds = std::chrono::duration<double>;
|
||||||
|
|
||||||
auto const global_tx_timeout = double_seconds{flags::run_time::execution_timeout_sec_};
|
auto const global_tx_timeout = double_seconds{flags::run_time::GetExecutionTimeout()};
|
||||||
auto const valid_global_tx_timeout = global_tx_timeout > double_seconds{0};
|
auto const valid_global_tx_timeout = global_tx_timeout > double_seconds{0};
|
||||||
|
|
||||||
if (tx_timeout_ms) {
|
if (tx_timeout_ms) {
|
||||||
@ -3918,7 +3918,7 @@ void RunTriggersAfterCommit(dbms::DatabaseAccess db_acc, InterpreterContext *int
|
|||||||
auto trigger_context = original_trigger_context;
|
auto trigger_context = original_trigger_context;
|
||||||
trigger_context.AdaptForAccessor(&db_accessor);
|
trigger_context.AdaptForAccessor(&db_accessor);
|
||||||
try {
|
try {
|
||||||
trigger.Execute(&db_accessor, &execution_memory, flags::run_time::execution_timeout_sec_,
|
trigger.Execute(&db_accessor, &execution_memory, flags::run_time::GetExecutionTimeout(),
|
||||||
&interpreter_context->is_shutting_down, transaction_status, trigger_context,
|
&interpreter_context->is_shutting_down, transaction_status, trigger_context,
|
||||||
interpreter_context->auth_checker);
|
interpreter_context->auth_checker);
|
||||||
} catch (const utils::BasicException &exception) {
|
} catch (const utils::BasicException &exception) {
|
||||||
@ -4032,9 +4032,9 @@ void Interpreter::Commit() {
|
|||||||
utils::MonotonicBufferResource execution_memory{kExecutionMemoryBlockSize};
|
utils::MonotonicBufferResource execution_memory{kExecutionMemoryBlockSize};
|
||||||
AdvanceCommand();
|
AdvanceCommand();
|
||||||
try {
|
try {
|
||||||
trigger.Execute(&*current_db_.execution_db_accessor_, &execution_memory,
|
trigger.Execute(&*current_db_.execution_db_accessor_, &execution_memory, flags::run_time::GetExecutionTimeout(),
|
||||||
flags::run_time::execution_timeout_sec_, &interpreter_context_->is_shutting_down,
|
&interpreter_context_->is_shutting_down, &transaction_status_, *trigger_context,
|
||||||
&transaction_status_, *trigger_context, interpreter_context_->auth_checker);
|
interpreter_context_->auth_checker);
|
||||||
} catch (const utils::BasicException &e) {
|
} catch (const utils::BasicException &e) {
|
||||||
throw utils::BasicException(
|
throw utils::BasicException(
|
||||||
fmt::format("Trigger '{}' caused the transaction to fail.\nException: {}", trigger.Name(), e.what()));
|
fmt::format("Trigger '{}' caused the transaction to fail.\nException: {}", trigger.Name(), e.what()));
|
||||||
|
@ -56,8 +56,8 @@ startup_config_dict = {
|
|||||||
),
|
),
|
||||||
"bolt_port": ("7687", "7687", "Port on which the Bolt server should listen."),
|
"bolt_port": ("7687", "7687", "Port on which the Bolt server should listen."),
|
||||||
"bolt_server_name_for_init": (
|
"bolt_server_name_for_init": (
|
||||||
"",
|
"Neo4j/v5.11.0 compatible graph database server - Memgraph",
|
||||||
"",
|
"Neo4j/v5.11.0 compatible graph database server - Memgraph",
|
||||||
"Server name which the database should send to the client in the Bolt INIT message.",
|
"Server name which the database should send to the client in the Bolt INIT message.",
|
||||||
),
|
),
|
||||||
"bolt_session_inactivity_timeout": (
|
"bolt_session_inactivity_timeout": (
|
||||||
@ -117,8 +117,8 @@ startup_config_dict = {
|
|||||||
"password_encryption_algorithm": ("bcrypt", "bcrypt", "The password encryption algorithm used for authentication."),
|
"password_encryption_algorithm": ("bcrypt", "bcrypt", "The password encryption algorithm used for authentication."),
|
||||||
"pulsar_service_url": ("", "", "Default URL used while connecting to Pulsar brokers."),
|
"pulsar_service_url": ("", "", "Default URL used while connecting to Pulsar brokers."),
|
||||||
"query_execution_timeout_sec": (
|
"query_execution_timeout_sec": (
|
||||||
"-1",
|
"600",
|
||||||
"-1",
|
"600",
|
||||||
"Maximum allowed query execution time. Queries exceeding this limit will be aborted. Value of 0 means no limit.",
|
"Maximum allowed query execution time. Queries exceeding this limit will be aborted. Value of 0 means no limit.",
|
||||||
),
|
),
|
||||||
"query_modules_directory": (
|
"query_modules_directory": (
|
||||||
|
@ -2,6 +2,7 @@ set(target_name memgraph__integration__executor)
|
|||||||
set(tester_target_name ${target_name}__tester)
|
set(tester_target_name ${target_name}__tester)
|
||||||
set(flag_tester_target_name ${target_name}__flag_tester)
|
set(flag_tester_target_name ${target_name}__flag_tester)
|
||||||
set(executor_target_name ${target_name}__executor)
|
set(executor_target_name ${target_name}__executor)
|
||||||
|
set(config_checker_target_name ${target_name}__config_checker)
|
||||||
|
|
||||||
add_executable(${tester_target_name} tester.cpp)
|
add_executable(${tester_target_name} tester.cpp)
|
||||||
set_target_properties(${tester_target_name} PROPERTIES OUTPUT_NAME tester)
|
set_target_properties(${tester_target_name} PROPERTIES OUTPUT_NAME tester)
|
||||||
@ -14,3 +15,7 @@ target_link_libraries(${flag_tester_target_name} mg-communication)
|
|||||||
add_executable(${executor_target_name} executor.cpp)
|
add_executable(${executor_target_name} executor.cpp)
|
||||||
set_target_properties(${executor_target_name} PROPERTIES OUTPUT_NAME executor)
|
set_target_properties(${executor_target_name} PROPERTIES OUTPUT_NAME executor)
|
||||||
target_link_libraries(${executor_target_name} mg-communication)
|
target_link_libraries(${executor_target_name} mg-communication)
|
||||||
|
|
||||||
|
add_executable(${config_checker_target_name} config_checker.cpp)
|
||||||
|
set_target_properties(${config_checker_target_name} PROPERTIES OUTPUT_NAME config_checker)
|
||||||
|
target_link_libraries(${config_checker_target_name} mg-communication)
|
||||||
|
70
tests/integration/run_time_settings/config_checker.cpp
Normal file
70
tests/integration/run_time_settings/config_checker.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2023 Memgraph Ltd.
|
||||||
|
//
|
||||||
|
// Use of this software is governed by the Business Source License
|
||||||
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
|
// License, and you may not use this file except in compliance with the Business Source License.
|
||||||
|
//
|
||||||
|
// As of the Change Date specified in that file, in accordance with
|
||||||
|
// the Business Source License, use of this software will be governed
|
||||||
|
// by the Apache License, Version 2.0, included in the file
|
||||||
|
// licenses/APL.txt.
|
||||||
|
|
||||||
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
|
#include "communication/bolt/client.hpp"
|
||||||
|
#include "communication/bolt/v1/value.hpp"
|
||||||
|
#include "io/network/endpoint.hpp"
|
||||||
|
#include "io/network/utils.hpp"
|
||||||
|
#include "utils/logging.hpp"
|
||||||
|
|
||||||
|
DEFINE_string(address, "127.0.0.1", "Server address");
|
||||||
|
DEFINE_int32(port, 7687, "Server port");
|
||||||
|
DEFINE_string(config, "", "Expected config field to check");
|
||||||
|
DEFINE_string(value, "", "Expected string result from field");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes queries passed as positional arguments and verifies whether they
|
||||||
|
* succeeded, failed, failed with a specific error message or executed without a
|
||||||
|
* specific error occurring.
|
||||||
|
*/
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||||
|
|
||||||
|
memgraph::communication::SSLInit sslInit;
|
||||||
|
|
||||||
|
memgraph::io::network::Endpoint endpoint(memgraph::io::network::ResolveHostname(FLAGS_address), FLAGS_port);
|
||||||
|
|
||||||
|
memgraph::communication::ClientContext context(false);
|
||||||
|
memgraph::communication::bolt::Client client(context);
|
||||||
|
|
||||||
|
try {
|
||||||
|
client.Connect(endpoint, "", "");
|
||||||
|
} catch (const memgraph::utils::BasicException &e) {
|
||||||
|
LOG_FATAL("");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &res = client.Execute("SHOW CONFIG", {});
|
||||||
|
constexpr int kNameIdx = 0;
|
||||||
|
constexpr int kValueIdx = 2;
|
||||||
|
MG_ASSERT(res.fields[kNameIdx] == "name", "Expected \"name\" field in the query result.");
|
||||||
|
MG_ASSERT(res.fields[kValueIdx] == "current_value", "Expected \"current_value\" field in the query result.");
|
||||||
|
|
||||||
|
for (const auto &record : res.records) {
|
||||||
|
const auto &settings_name = record[kNameIdx].ValueString();
|
||||||
|
if (settings_name == FLAGS_config) {
|
||||||
|
const auto &settings_value = record[kValueIdx].ValueString();
|
||||||
|
// First try to encode the flags as float; if that fails just compare the raw strings
|
||||||
|
try {
|
||||||
|
MG_ASSERT(std::stof(settings_value) == std::stof(FLAGS_value),
|
||||||
|
"Failed when checking \"{}\"; expected \"{}\", found \"{}\"!", FLAGS_config, FLAGS_value,
|
||||||
|
settings_value);
|
||||||
|
} catch (const std::invalid_argument &) {
|
||||||
|
MG_ASSERT(settings_value == FLAGS_value, "Failed when checking \"{}\"; expected \"{}\", found \"{}\"!",
|
||||||
|
FLAGS_config, FLAGS_value, settings_value);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_FATAL("No setting named \"{}\" found!", FLAGS_config);
|
||||||
|
}
|
@ -84,6 +84,11 @@ def check_flag(tester_binary: str, flag: str, value: str) -> None:
|
|||||||
subprocess.run(args).check_returncode()
|
subprocess.run(args).check_returncode()
|
||||||
|
|
||||||
|
|
||||||
|
def check_config(tester_binary: str, flag: str, value: str) -> None:
|
||||||
|
args = [tester_binary, "--config", flag, "--value", value]
|
||||||
|
subprocess.run(args).check_returncode()
|
||||||
|
|
||||||
|
|
||||||
def cleanup(memgraph: subprocess):
|
def cleanup(memgraph: subprocess):
|
||||||
if memgraph.poll() is None:
|
if memgraph.poll() is None:
|
||||||
memgraph.terminate()
|
memgraph.terminate()
|
||||||
@ -156,7 +161,22 @@ def run_log_test(tester_binary: str, memgraph_args: List[str], executor_binary:
|
|||||||
atexit.unregister(cleanup)
|
atexit.unregister(cleanup)
|
||||||
|
|
||||||
|
|
||||||
def execute_test(memgraph_binary: str, tester_binary: str, flag_tester_binary: str, executor_binary: str) -> None:
|
def run_check_config(tester_binary: str, memgraph_args: List[str], executor_binary: str):
|
||||||
|
memgraph = start_memgraph(memgraph_args)
|
||||||
|
atexit.register(cleanup, memgraph)
|
||||||
|
execute_query(executor_binary, ["SET DATABASE SETTING 'server.name' TO 'New Name';"])
|
||||||
|
execute_query(executor_binary, ["SET DATABASE SETTING 'query.timeout' TO '123';"])
|
||||||
|
execute_query(executor_binary, ["SET DATABASE SETTING 'log.level' TO 'CRITICAL';"])
|
||||||
|
check_config(tester_binary, "bolt_server_name_for_init", "New Name")
|
||||||
|
check_config(tester_binary, "query_execution_timeout_sec", "123")
|
||||||
|
check_config(tester_binary, "log_level", "CRITICAL")
|
||||||
|
cleanup(memgraph)
|
||||||
|
atexit.unregister(cleanup)
|
||||||
|
|
||||||
|
|
||||||
|
def execute_test(
|
||||||
|
memgraph_binary: str, tester_binary: str, flag_tester_binary: str, executor_binary: str, test_config_binary: str
|
||||||
|
) -> None:
|
||||||
storage_directory = tempfile.TemporaryDirectory()
|
storage_directory = tempfile.TemporaryDirectory()
|
||||||
memgraph_args = [memgraph_binary, "--data-directory", storage_directory.name]
|
memgraph_args = [memgraph_binary, "--data-directory", storage_directory.name]
|
||||||
|
|
||||||
@ -181,6 +201,10 @@ def execute_test(memgraph_binary: str, tester_binary: str, flag_tester_binary: s
|
|||||||
# Check log settings
|
# Check log settings
|
||||||
run_log_test(tester_binary, memgraph_args, executor_binary)
|
run_log_test(tester_binary, memgraph_args, executor_binary)
|
||||||
|
|
||||||
|
print("\033[1;34m~~ check show config ~~\033[0m")
|
||||||
|
# Check log settings
|
||||||
|
run_check_config(test_config_binary, memgraph_args, executor_binary)
|
||||||
|
|
||||||
print("\033[1;36m~~ Finished run-time settings check test ~~\033[0m")
|
print("\033[1;36m~~ Finished run-time settings check test ~~\033[0m")
|
||||||
|
|
||||||
|
|
||||||
@ -189,14 +213,18 @@ if __name__ == "__main__":
|
|||||||
tester_binary = os.path.join(PROJECT_DIR, "build", "tests", "integration", "run_time_settings", "tester")
|
tester_binary = os.path.join(PROJECT_DIR, "build", "tests", "integration", "run_time_settings", "tester")
|
||||||
flag_tester_binary = os.path.join(PROJECT_DIR, "build", "tests", "integration", "run_time_settings", "flag_tester")
|
flag_tester_binary = os.path.join(PROJECT_DIR, "build", "tests", "integration", "run_time_settings", "flag_tester")
|
||||||
executor_binary = os.path.join(PROJECT_DIR, "build", "tests", "integration", "run_time_settings", "executor")
|
executor_binary = os.path.join(PROJECT_DIR, "build", "tests", "integration", "run_time_settings", "executor")
|
||||||
|
config_checker_binary = os.path.join(
|
||||||
|
PROJECT_DIR, "build", "tests", "integration", "run_time_settings", "config_checker"
|
||||||
|
)
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--memgraph", default=memgraph_binary)
|
parser.add_argument("--memgraph", default=memgraph_binary)
|
||||||
parser.add_argument("--tester", default=tester_binary)
|
parser.add_argument("--tester", default=tester_binary)
|
||||||
parser.add_argument("--flag_tester", default=flag_tester_binary)
|
parser.add_argument("--flag_tester", default=flag_tester_binary)
|
||||||
parser.add_argument("--executor", default=executor_binary)
|
parser.add_argument("--executor", default=executor_binary)
|
||||||
|
parser.add_argument("--config_checker", default=config_checker_binary)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
execute_test(args.memgraph, args.tester, args.flag_tester, args.executor)
|
execute_test(args.memgraph, args.tester, args.flag_tester, args.executor, args.config_checker)
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
@ -60,7 +60,7 @@ class InterpreterTest : public ::testing::Test {
|
|||||||
const std::string testSuiteCsv = "interpreter_csv";
|
const std::string testSuiteCsv = "interpreter_csv";
|
||||||
std::filesystem::path data_directory = std::filesystem::temp_directory_path() / "MG_tests_unit_interpreter";
|
std::filesystem::path data_directory = std::filesystem::temp_directory_path() / "MG_tests_unit_interpreter";
|
||||||
|
|
||||||
InterpreterTest() : interpreter_context({}, kNoHandler) { memgraph::flags::run_time::execution_timeout_sec_ = 600.0; }
|
InterpreterTest() : interpreter_context({}, kNoHandler) {}
|
||||||
|
|
||||||
memgraph::utils::Gatekeeper<memgraph::dbms::Database> db_gk{
|
memgraph::utils::Gatekeeper<memgraph::dbms::Database> db_gk{
|
||||||
[&]() {
|
[&]() {
|
||||||
|
Loading…
Reference in New Issue
Block a user