-
Notifications
You must be signed in to change notification settings - Fork 106
fix: configuration parsing error mmap_log_buffer_size #2363
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
fix: configuration parsing error mmap_log_buffer_size #2363
Conversation
I have been starting work on 2313. |
c93a0ef
to
c6560d8
Compare
c6560d8
to
117cd6d
Compare
@krizhanovsky I slightly modified tfw_logger to make it work with JSON files. I also did some refactoring on it. Could you please assign someone to review these changes? |
TFW_CFG_CHECK_NO_ATTRS(cs, ce); | ||
|
||
// Check for logger_config attribute | ||
const char *logger_config = tfw_cfg_get_attr(ce, "logger_config", NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please delete this code, tfw_logger_config_path
is not used now, there is no sense to keep it. If it become necessary in future it's not a big deal to add it.
@@ -596,6 +611,19 @@ cfg_access_log_set(TfwCfgSpec *cs, TfwCfgEntry *ce) | |||
return -EINVAL; | |||
} | |||
|
|||
// Parse other attributes if using mmap | |||
if (access_log_type & ACCESS_LOG_MMAP) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this part. For tfw_logger
we do validation only in tempesta.sh
file, but now we must do it in tfw_logger.
uint16_t port{9000}; // ClickHouse server port | ||
std::optional<std::string> user; // Optional username | ||
std::optional<std::string> password; // Optional password | ||
std::string table_name{"access_log"}; // Table name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no sense to add table name to config, anyway we create table using hardcoded name. Even if change this behavior, I think we not need to have this in the configuration file, at least now. The same for database name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, quite a good question: we supposed that Clickhouse is installed solely for us, but a user might want to use existing database instance for the logs. I.e. web frameworks typicallay provide not only database credentials and IP with port, but also database name and probably a table name.
} | ||
else | ||
{ | ||
cpu_cnt = std::thread::hardware_concurrency(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to not use std::thread::hardware_concurrency
and always use sysconf
as reliable source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@const-t What's wrong with std::thread::hardware_concurrency
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Kutumov I'm not sure that it works well with NUMA and with machines that has 100+ cpus. It may return invalid cpu count, but not zero and in this case we even can't fallback to sysconf
. Even cppref describes it as: The value should be considered only a hint
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This must be commented in the source code - I was also thinking that std::thread::hardware_concurrency
is good
fs::path config_path = "/etc/tempesta/tfw_logger.json"; | ||
|
||
try | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ | |
{ |
std::shared_ptr<spdlog::logger> logger = nullptr; | ||
fs::path config_path = "/etc/tempesta/tfw_logger.json"; | ||
|
||
try |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try | |
try { |
Please have a look on our codingstyle, it not covers c++ completely, but we follow it where it's possible. For instance indentations.
{ | ||
int fd = -1, res = 0; | ||
std::shared_ptr<spdlog::logger> logger = nullptr; | ||
fs::path config_path = "/etc/tempesta/tfw_logger.json"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoding the config path doesn't look good. You've done a great job adding a configuration file, and I believe we should use its benefits. My suggestion:
- Pass
config_path
as CLI argument into tfw_logger, but constructconfig_path
intempesta.sh
usingTFW_ROOT
constant. Just as we do fortfw_cfg_path
andtfw_cfg_temp
. - Remove from
tempesta.sh
parsing ofmmap_*
directives, you moved them to tfw_logger let validate them there. Therefore do not passmmap_*
parameters from tempesta's config to tfw_logger, they are already there. - Give CLI arguments higher precedence over config file. To be able to override params defined in config using CLI.
@MorganaFuture If you need some clarifications, feel free to ask.
size_t buffer_size{4 * 1024 * 1024}; // 4MB default buffer size | ||
size_t cpu_count{0}; // 0 means auto-detect | ||
ClickHouseConfig clickhouse; // ClickHouse configuration | ||
bool debug{false}; // Debug mode flag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like unused flag, delete it please.
ch_cfg.password ? *ch_cfg.password : "", | ||
make_block()); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary blank line, please delete them in other places as well.
@@ -266,6 +288,7 @@ run_thread(const int ncpu, const int fd, const std::string &host, | |||
break; | |||
} | |||
catch (const Exception &e) { | |||
std::cerr << "Exception in run_thread: " << e.what() << std::endl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need the second error message?
std::shared_ptr<spdlog::logger> | ||
setup_logger(const TfwLoggerConfig &config) | ||
{ | ||
try |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reduce try area to the lines that may throw spdlog::spdlog_ex
else | ||
{ | ||
// If config file not found or invalid, use command line args | ||
std::cout << "Could not load configuration from file, using command line arguments" << std::endl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion if expected configuration fails(or its part) it is better to exit in order not to execute the service with undesirable settings. @const-t FYI
return std::nullopt; | ||
} | ||
|
||
try |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reduce the try area to the lines that may throw
|
||
TfwLoggerConfig config; | ||
config.parse_from_ptree(tree); | ||
return config; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not std::move(config)
?
std::cerr << "Error parsing command line: " << e.what() << std::endl; | ||
std::cerr << "Use --help for usage information" << std::endl; | ||
result = CommandResult::ERROR; | ||
parse_error = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just return here and no need in parse_error
?
|
||
for (size_t i = 0; i < cpu_count; ++i) | ||
{ | ||
std::packaged_task<void(int, int, TfwLoggerConfig)> task(run_thread); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
packaged_task
is redundant here. We can just wait when threads finish using std::thread::join
@@ -576,7 +577,21 @@ cfg_access_log_set(TfwCfgSpec *cs, TfwCfgEntry *ce) | |||
bool off = false; | |||
|
|||
TFW_CFG_CHECK_VAL_N(>, 0, cs, ce); | |||
TFW_CFG_CHECK_NO_ATTRS(cs, ce); | |||
|
|||
// Check for logger_config attribute |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use C++ style comments in C, https://github.com/tempesta-tech/tempesta/blob/master/CodingStyle . In general https://tempesta-tech.com/knowledge-base/Development-guidelines/ is worth reading
while (!stop_flag) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while (!stop_flag) | |
{ | |
while (!stop_flag) { |
try | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try | |
{ | |
try { |
TfwClickhouse clickhouse(ch_cfg.host, ch_cfg.table_name, | ||
ch_cfg.user ? *ch_cfg.user : "", | ||
ch_cfg.password ? *ch_cfg.password : "", | ||
make_block()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
too wide line and something is broken with identation
if (fs::exists(config_path)) | ||
{ | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (fs::exists(config_path)) | |
{ | |
return; | |
} | |
if (fs::exists(config_path)) | |
return; |
{ | ||
spdlog::info("Starting in handle (foreground) mode"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need daemonization. The modern Linux environments provide this out of the box and in the modern our projects we don't daemonize servers
throw Except("Failed to open PID file"); | ||
pid_file << getpid(); | ||
pid_file.close(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the purpose of the pid file? Typically in Linux we also should lock it and set the right permissions. @ttaym you recently worked with a nice small library for PID files, could you please reference it that we can borrow it's code here as well?
|
||
spdlog::info("Daemon stopped"); | ||
// Open the device | ||
fd = open_device(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably the comment is redundant - basically the function name is just the same as the comment
uint16_t port{9000}; // ClickHouse server port | ||
std::optional<std::string> user; // Optional username | ||
std::optional<std::string> password; // Optional password | ||
std::string table_name{"access_log"}; // Table name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, quite a good question: we supposed that Clickhouse is installed solely for us, but a user might want to use existing database instance for the logs. I.e. web frameworks typicallay provide not only database credentials and IP with port, but also database name and probably a table name.
fs::path pid_file{"/var/run/tfw_logger.pid"}; // PID file path | ||
size_t buffer_size{4 * 1024 * 1024}; // 4MB default buffer size | ||
size_t cpu_count{0}; // 0 means auto-detect | ||
ClickHouseConfig clickhouse; // ClickHouse configuration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issues with identation and usually we name members as clickhouse_
, with _
suffix
The pull request is being moved here #2428 |
What
This PR introduces a JSON-based configuration system for the Tempesta FW logger daemon with:
Why
The Tempesta logger configuration is currently scattered across multiple parameters, making it hard to manage. A dedicated JSON file provides a cleaner approach that separates logger settings from the main configuration. This structured format improves error handling and simplifies troubleshooting with the new foreground mode.
Links
2313