Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic config for log #11

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions be/src/common/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,15 @@ namespace config {
CONF_String(sys_log_dir, "${DORIS_HOME}/log");
CONF_String(user_function_dir, "${DORIS_HOME}/lib/udf");
// INFO, WARNING, ERROR, FATAL
CONF_String(sys_log_level, "INFO");
CONF_mString(sys_log_level, "INFO");
// TIME-DAY, TIME-HOUR, SIZE-MB-nnn
CONF_String(sys_log_roll_mode, "SIZE-MB-1024");
// log roll num
CONF_Int32(sys_log_roll_num, "10");
// verbose log
CONF_Strings(sys_log_verbose_modules, "");
CONF_mStrings(sys_log_verbose_modules, "");
// verbose log level
CONF_Int32(sys_log_verbose_level, "10");
CONF_mInt32(sys_log_verbose_level, "10");
// log buffer level
CONF_String(log_buffer_level, "");

Expand Down
26 changes: 23 additions & 3 deletions be/src/common/configbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <iostream>
#include <list>
#include <map>
#include <mutex>
#include <sstream>

#define __IN_CONFIGBASE_CPP__
Expand All @@ -30,11 +31,15 @@

#include "common/status.h"
#include "gutil/strings/substitute.h"
#include "util/spinlock.h"

namespace doris {
namespace config {

std::map<std::string, Register::Field>* Register::_s_field_map = nullptr;

// full configurations.
SpinLock full_conf_map_lock;
std::map<std::string, std::string>* full_conf_map = nullptr;

Properties props;
Expand Down Expand Up @@ -98,8 +103,11 @@ bool strtox(const std::string& valstr, std::vector<T>& retval) {
std::stringstream ss(valstr);
std::string item;
T t;
std::vector<T> oldval = retval;
retval.clear();
while (std::getline(ss, item, ',')) {
if (!strtox(trim(item), t)) {
retval = oldval;
return false;
}
retval.push_back(t);
Expand Down Expand Up @@ -130,10 +138,10 @@ bool strtointeger(const std::string& valstr, T& retval) {
if (errno || end != valcstr + strlen(valcstr)) {
return false; // bad parse
}
T tmp = retval;
T oldval = retval;
retval = static_cast<T>(ret64);
if (retval != ret64) {
retval = tmp;
retval = oldval;
return false;
}
return true;
Expand Down Expand Up @@ -258,6 +266,7 @@ std::ostream& operator<<(std::ostream& out, const std::vector<T>& v) {
if (FILL_CONFMAP) { \
std::ostringstream oss; \
oss << (*reinterpret_cast<TYPE*>((FIELD).storage)); \
std::lock_guard<SpinLock> l(full_conf_map_lock); \
(*full_conf_map)[(FIELD).name] = oss.str(); \
} \
continue; \
Expand Down Expand Up @@ -302,6 +311,7 @@ bool init(const char* filename, bool fillconfmap) {
if (full_conf_map != nullptr) { \
std::ostringstream oss; \
oss << (*reinterpret_cast<TYPE*>((FIELD).storage)); \
std::lock_guard<SpinLock> l(full_conf_map_lock); \
(*full_conf_map)[(FIELD).name] = oss.str(); \
} \
return Status::OK(); \
Expand All @@ -322,11 +332,21 @@ Status set_config(const std::string& field, const std::string& value) {
UPDATE_FIELD(it->second, value, int32_t);
UPDATE_FIELD(it->second, value, int64_t);
UPDATE_FIELD(it->second, value, double);
UPDATE_FIELD(it->second, value, std::string);
UPDATE_FIELD(it->second, value, std::vector<std::string>);

// The other types are not thread safe to change dynamically.
return Status::NotSupported(strings::Substitute(
"'$0' is type of '$1' which is not support to modify", field, it->second.type));
}

std::string dump_full_configs() {
std::lock_guard<SpinLock> l(full_conf_map_lock);
std::stringstream ss;
for (const auto& it : *full_conf_map) {
ss << it.first << "=" << it.second << std::endl;
}
return ss.str();
}

} // namespace config
} // namespace doris
9 changes: 7 additions & 2 deletions be/src/common/configbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ class Register {
#define CONF_mInt32(name, defaultstr) DEFINE_FIELD(int32_t, name, defaultstr, true)
#define CONF_mInt64(name, defaultstr) DEFINE_FIELD(int64_t, name, defaultstr, true)
#define CONF_mDouble(name, defaultstr) DEFINE_FIELD(double, name, defaultstr, true)
#define CONF_mString(name, defaultstr) DEFINE_FIELD(std::string, name, defaultstr, true)
#define CONF_mStrings(name, defaultstr) \
DEFINE_FIELD(std::vector<std::string>, name, defaultstr, true)
#else
#define CONF_Bool(name, defaultstr) DECLARE_FIELD(bool, name)
#define CONF_Int16(name, defaultstr) DECLARE_FIELD(int16_t, name)
Expand All @@ -104,6 +107,8 @@ class Register {
#define CONF_mInt32(name, defaultstr) DECLARE_FIELD(int32_t, name)
#define CONF_mInt64(name, defaultstr) DECLARE_FIELD(int64_t, name)
#define CONF_mDouble(name, defaultstr) DECLARE_FIELD(double, name)
#define CONF_mString(name, defaultstr) DECLARE_FIELD(std::string, name)
#define CONF_mStrings(name, defaultstr) DECLARE_FIELD(std::vector<std::string>, name)
#endif

// configuration properties load from config file.
Expand All @@ -119,8 +124,8 @@ class Properties {

extern Properties props;

// full configurations.
extern std::map<std::string, std::string>* full_conf_map;
// Dump full configurations.
std::string dump_full_configs();

bool init(const char* filename, bool fillconfmap = false);

Expand Down
73 changes: 42 additions & 31 deletions be/src/common/logconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,25 @@
// specific language governing permissions and limitations
// under the License.

#include <iostream>
#include <glog/logging.h>
#include <glog/vlog_is_on.h>

#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <mutex>
#include <glog/logging.h>
#include <glog/vlog_is_on.h>

#include "common/config.h"
#include "util/logging.h"

namespace doris {

static bool logging_initialized = false;

static std::mutex logging_mutex;

static bool iequals(const std::string& a, const std::string& b)
{
static bool iequals(const std::string& a, const std::string& b) {
unsigned int sz = a.size();
if (b.size() != sz) {
return false;
Expand All @@ -42,10 +44,9 @@ static bool iequals(const std::string& a, const std::string& b)
}
}
return true;
}
}

bool init_glog(const char* basename, bool install_signal_handler) {

std::lock_guard<std::mutex> logging_lock(logging_mutex);

if (logging_initialized) {
Expand All @@ -63,22 +64,13 @@ bool init_glog(const char* basename, bool install_signal_handler) {
// 0 means buffer INFO only
FLAGS_logbuflevel = 0;
// buffer log messages for at most this many seconds
FLAGS_logbufsecs = 30;
FLAGS_logbufsecs = 30;
// set roll num
FLAGS_log_filenum_quota = config::sys_log_roll_num;

// set log level
std::string& loglevel = config::sys_log_level;
if (iequals(loglevel, "INFO")) {
FLAGS_minloglevel = 0;
} else if (iequals(loglevel, "WARNING")) {
FLAGS_minloglevel = 1;
} else if (iequals(loglevel, "ERROR")) {
FLAGS_minloglevel = 2;
} else if (iequals(loglevel, "FATAL")) {
FLAGS_minloglevel = 3;
} else {
std::cerr << "sys_log_level needs to be INFO, WARNING, ERROR, FATAL" << std::endl;
if (!convert_log_level(config::sys_log_level, &FLAGS_minloglevel)) {
std::cerr << "sys_log_level needs to be INFO, WARNING, ERROR or FATAL" << std::endl;
return false;
}

Expand All @@ -104,7 +96,7 @@ bool init_glog(const char* basename, bool install_signal_handler) {
} else if (rollmode.substr(0, sizeflag.length()).compare(sizeflag) == 0) {
FLAGS_log_split_method = "size";
std::string sizestr = rollmode.substr(sizeflag.size(), rollmode.size() - sizeflag.size());
if (sizestr.size() != 0) {
if (sizestr.size() != 0) {
char* end = NULL;
errno = 0;
const char* sizecstr = sizestr.c_str();
Expand All @@ -127,25 +119,44 @@ bool init_glog(const char* basename, bool install_signal_handler) {

// set verbose modules.
FLAGS_v = -1;
std::vector<std::string>& verbose_modules = config::sys_log_verbose_modules;
int32_t vlog_level = config::sys_log_verbose_level;
for (size_t i = 0; i < verbose_modules.size(); i++) {
if (verbose_modules[i].size() != 0) {
google::SetVLOGLevel(verbose_modules[i].c_str(), vlog_level);
}
}
update_modules_log_level(config::sys_log_verbose_modules, config::sys_log_verbose_level);

google::InitGoogleLogging(basename);

logging_initialized = true;

return true;

return true;
}

void shutdown_logging() {
std::lock_guard<std::mutex> logging_lock(logging_mutex);
google::ShutdownGoogleLogging();
}

bool convert_log_level(const std::string& str, int32_t* level) {
if (iequals(str, "INFO")) {
*level = 0;
return true;
} else if (iequals(str, "WARNING")) {
*level = 1;
return true;
} else if (iequals(str, "ERROR")) {
*level = 2;
return true;
} else if (iequals(str, "FATAL")) {
*level = 3;
return true;
} else {
return false;
}
}

void update_modules_log_level(const std::vector<std::string>& modules, int32_t level) {
for (const auto& module : modules) {
if (!module.empty()) {
google::SetVLOGLevel(module.c_str(), level);
}
}
}

} // namespace doris
80 changes: 60 additions & 20 deletions be/src/http/action/update_config_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,19 @@
#include <rapidjson/rapidjson.h>
#include <rapidjson/stringbuffer.h>

#include <mutex>
#include <string>

#include "common/config.h"
#include "common/configbase.h"
#include "common/logging.h"
#include "common/status.h"
#include "gutil/strings/substitute.h"
#include "http/http_channel.h"
#include "http/http_headers.h"
#include "http/http_request.h"
#include "http/http_response.h"
#include "http/http_status.h"
#include "util/logging.h"

namespace doris {

Expand All @@ -41,26 +43,10 @@ const static std::string HEADER_JSON = "application/json";
void UpdateConfigAction::handle(HttpRequest* req) {
LOG(INFO) << req->debug_string();

Status s;
std::string msg;
if (req->params()->size() != 1) {
s = Status::InvalidArgument("");
msg = "Now only support to set a single config once, via 'config_name=new_value'";
} else {
DCHECK(req->params()->size() == 1);
const std::string& config = req->params()->begin()->first;
const std::string& new_value = req->params()->begin()->second;
s = config::set_config(config, new_value);
if (s.ok()) {
LOG(INFO) << "set_config " << config << "=" << new_value << " success";
} else {
LOG(WARNING) << "set_config " << config << "=" << new_value << " failed";
msg = strings::Substitute("set $0=$1 failed, reason: $2", config, new_value,
s.to_string());
}
}

Status s = _update_config(*(req->params()));
std::string status(s.ok() ? "OK" : "BAD");
std::string msg = s.to_string();

rapidjson::Document root;
root.SetObject();
root.AddMember("status", rapidjson::Value(status.c_str(), status.size()), root.GetAllocator());
Expand All @@ -73,4 +59,58 @@ void UpdateConfigAction::handle(HttpRequest* req) {
HttpChannel::send_reply(req, HttpStatus::OK, strbuf.GetString());
}

Status UpdateConfigAction::_update_config(const std::map<std::string, std::string>& params) {
if (params.size() != 1) {
return Status::InvalidArgument("now only support to set a single config once");
}

DCHECK(params.size() == 1);
const std::string& config = params.begin()->first;
const std::string& new_value = params.begin()->second;
Status s;
if (config == "sys_log_level" || config == "sys_log_verbose_modules" ||
config == "sys_log_verbose_level") {
// Update glog configs.
s = _update_log_config(config, new_value);
} else {
// The other configs can be updated by config::set_config directly.
s = config::set_config(config, new_value);
}
if (s.ok()) {
LOG(INFO) << "update config " << config << "=" << new_value << " success";
} else {
LOG(WARNING) << "update config " << config << "=" << new_value
<< " failed, reason: " << s.to_string();
}
return s;
}

Status UpdateConfigAction::_update_log_config(const std::string& config,
const std::string& new_value) {
std::lock_guard<SpinLock> l(_lock);
if (config == "sys_log_level") {
int32_t new_level = 0;
if (!convert_log_level(new_value, &new_level)) {
return Status::InvalidArgument(
"invalid sys_log_level, valid value should be INFO, WARNING, ERROR or FATAL");
}
string result =
google::SetCommandLineOption("minloglevel", std::to_string(new_level).c_str());
// result is not empty when SetCommandLineOption success.
// Now SetCommandLineOption parameters are valid and the result should be success.
DCHECK(!result.empty());
Status s = config::set_config(config, new_value);
DCHECK(s.ok()); // Status is definity ok when set 'sys_log_level'
return s;
} else if (config == "sys_log_verbose_modules" || config == "sys_log_verbose_level") {
// ATTN: google::SetVLOGLevel in update_modules_log_level can not be called in runtime, because a static local variable in VLOG_IS_ON has been initilized!!!
update_modules_log_level(config::sys_log_verbose_modules, config::sys_log_verbose_level);
Status s = config::set_config(config, new_value);
DCHECK(s.ok()); // Status is definity ok when set 'sys_log_verbose_modules' or 'sys_log_verbose_level'
return s;
}

return Status::NotSupported(strings::Substitute("not support to update config $0", config));
}

} // namespace doris
Loading