Common System 0.2.0
Common interfaces and patterns for system integration
Loading...
Searching...
No Matches
kcenon::common::config::cli_config_parser Class Reference

Parses command-line arguments for configuration. More...

#include <cli_config_parser.h>

Collaboration diagram for kcenon::common::config::cli_config_parser:
Collaboration graph

Static Public Member Functions

static Result< parsed_argsparse (int argc, char **argv)
 Parse command-line arguments.
 
static Result< unified_configload_with_cli_overrides (int argc, char **argv)
 Load configuration with CLI overrides.
 
static void print_help (const std::string &program_name="program")
 Print help message to stdout.
 
static void print_version (const std::string &version="0.1.0.0")
 Print version information to stdout.
 

Static Private Member Functions

static bool starts_with (const std::string &str, const std::string &prefix)
 Check if a string starts with a prefix.
 
static Result< std::pair< std::string, std::string > > parse_key_value (const std::string &str)
 Parse a key=value string.
 
static VoidResult apply_override (unified_config &config, const std::string &key, const std::string &value)
 Apply a configuration override.
 
static size_t parse_size_t (const std::string &value)
 
static int64_t parse_int64 (const std::string &value)
 
static double parse_double (const std::string &value)
 
static bool parse_bool (const std::string &value)
 

Detailed Description

Parses command-line arguments for configuration.

Usage Example:

int main(int argc, char** argv) {
auto result = cli_config_parser::load_with_cli_overrides(argc, argv);
if (result.is_err()) {
if (result.error().code == cli_error_codes::invalid_argument) {
}
return 1;
}
auto config = result.value();
// Use config...
}
int main()
static Result< unified_config > load_with_cli_overrides(int argc, char **argv)
Load configuration with CLI overrides.
static void print_help(const std::string &program_name="program")
Print help message to stdout.

Definition at line 95 of file cli_config_parser.h.

Member Function Documentation

◆ apply_override()

static VoidResult kcenon::common::config::cli_config_parser::apply_override ( unified_config & config,
const std::string & key,
const std::string & value )
inlinestaticprivate

Apply a configuration override.

Parameters
configConfiguration to modify
keyConfiguration key (dot-separated path)
valueValue to set
Returns
VoidResult indicating success or error

Definition at line 335 of file cli_config_parser.h.

337 {
338 // Thread configuration
339 if (key == "thread.pool_size") {
340 config.thread.pool_size = parse_size_t(value);
341 } else if (key == "thread.queue_type") {
342 config.thread.queue_type = value;
343 } else if (key == "thread.max_queue_size") {
344 config.thread.max_queue_size = parse_size_t(value);
345 } else if (key == "thread.thread_name_prefix") {
346 config.thread.thread_name_prefix = value;
347 }
348 // Logger configuration
349 else if (key == "logger.level") {
350 config.logger.level = value;
351 } else if (key == "logger.async") {
352 config.logger.async = parse_bool(value);
353 } else if (key == "logger.buffer_size") {
354 config.logger.buffer_size = parse_size_t(value);
355 } else if (key == "logger.file_path") {
356 config.logger.file_path = value;
357 } else if (key == "logger.max_file_size") {
358 config.logger.max_file_size = parse_size_t(value);
359 } else if (key == "logger.max_backup_files") {
360 config.logger.max_backup_files = parse_size_t(value);
361 } else if (key == "logger.format_pattern") {
362 config.logger.format_pattern = value;
363 }
364 // Monitoring configuration
365 else if (key == "monitoring.enabled") {
366 config.monitoring.enabled = parse_bool(value);
367 } else if (key == "monitoring.metrics_interval" ||
368 key == "monitoring.metrics_interval_ms") {
369 config.monitoring.metrics_interval = std::chrono::milliseconds{parse_int64(value)};
370 } else if (key == "monitoring.health_check_interval" ||
371 key == "monitoring.health_check_interval_ms") {
372 config.monitoring.health_check_interval = std::chrono::milliseconds{parse_int64(value)};
373 } else if (key == "monitoring.prometheus_port") {
374 config.monitoring.prometheus_port = static_cast<uint16_t>(parse_size_t(value));
375 } else if (key == "monitoring.prometheus_path") {
376 config.monitoring.prometheus_path = value;
377 }
378 // Tracing configuration
379 else if (key == "monitoring.tracing.enabled") {
380 config.monitoring.tracing.enabled = parse_bool(value);
381 } else if (key == "monitoring.tracing.sampling_rate") {
382 config.monitoring.tracing.sampling_rate = parse_double(value);
383 } else if (key == "monitoring.tracing.exporter") {
384 config.monitoring.tracing.exporter = value;
385 } else if (key == "monitoring.tracing.endpoint") {
386 config.monitoring.tracing.endpoint = value;
387 }
388 // Database configuration
389 else if (key == "database.backend") {
390 config.database.backend = value;
391 } else if (key == "database.connection_string") {
392 config.database.connection_string = value;
393 } else if (key == "database.log_queries") {
394 config.database.log_queries = parse_bool(value);
395 } else if (key == "database.slow_query_threshold" ||
396 key == "database.slow_query_threshold_ms") {
397 config.database.slow_query_threshold = std::chrono::milliseconds{parse_int64(value)};
398 } else if (key == "database.pool.min_size") {
399 config.database.pool.min_size = parse_size_t(value);
400 } else if (key == "database.pool.max_size") {
401 config.database.pool.max_size = parse_size_t(value);
402 } else if (key == "database.pool.idle_timeout" ||
403 key == "database.pool.idle_timeout_ms") {
404 config.database.pool.idle_timeout = std::chrono::milliseconds{parse_int64(value)};
405 } else if (key == "database.pool.acquire_timeout" ||
406 key == "database.pool.acquire_timeout_ms") {
407 config.database.pool.acquire_timeout = std::chrono::milliseconds{parse_int64(value)};
408 }
409 // Network configuration
410 else if (key == "network.compression") {
411 config.network.compression = value;
412 } else if (key == "network.buffer_size") {
413 config.network.buffer_size = parse_size_t(value);
414 } else if (key == "network.connect_timeout" ||
415 key == "network.connect_timeout_ms") {
416 config.network.connect_timeout = std::chrono::milliseconds{parse_int64(value)};
417 } else if (key == "network.io_timeout" ||
418 key == "network.io_timeout_ms") {
419 config.network.io_timeout = std::chrono::milliseconds{parse_int64(value)};
420 } else if (key == "network.keepalive_interval" ||
421 key == "network.keepalive_interval_ms") {
422 config.network.keepalive_interval = std::chrono::milliseconds{parse_int64(value)};
423 } else if (key == "network.max_connections") {
424 config.network.max_connections = parse_size_t(value);
425 }
426 // TLS configuration
427 else if (key == "network.tls.enabled") {
428 config.network.tls.enabled = parse_bool(value);
429 } else if (key == "network.tls.version") {
430 config.network.tls.version = value;
431 } else if (key == "network.tls.cert_path") {
432 config.network.tls.cert_path = value;
433 } else if (key == "network.tls.key_path") {
434 config.network.tls.key_path = value;
435 } else if (key == "network.tls.ca_path") {
436 config.network.tls.ca_path = value;
437 } else if (key == "network.tls.verify_peer") {
438 config.network.tls.verify_peer = parse_bool(value);
439 }
440 // Unknown key
441 else {
444 "Unknown configuration key: " + key,
445 "cli_config_parser"
446 );
447 }
448
449 return VoidResult::ok({});
450 }
static Result< T > ok(U &&value)
Create a successful result with value (static factory)
Definition core.h:223
static double parse_double(const std::string &value)
static size_t parse_size_t(const std::string &value)
static bool parse_bool(const std::string &value)
static int64_t parse_int64(const std::string &value)
Result< T > make_error(int code, const std::string &message, const std::string &module="")
Create an error result with code and message.
Definition utilities.h:91

References kcenon::common::config::pool_config::acquire_timeout, kcenon::common::config::logger_config::async, kcenon::common::config::database_config::backend, kcenon::common::config::logger_config::buffer_size, kcenon::common::config::network_config::buffer_size, kcenon::common::config::tls_config::ca_path, kcenon::common::config::tls_config::cert_path, kcenon::common::config::network_config::compression, kcenon::common::config::network_config::connect_timeout, kcenon::common::config::database_config::connection_string, kcenon::common::config::unified_config::database, kcenon::common::config::monitoring_config::enabled, kcenon::common::config::tls_config::enabled, kcenon::common::config::tracing_config::enabled, kcenon::common::config::tracing_config::endpoint, kcenon::common::config::tracing_config::exporter, kcenon::common::config::logger_config::file_path, kcenon::common::config::logger_config::format_pattern, kcenon::common::config::monitoring_config::health_check_interval, kcenon::common::config::pool_config::idle_timeout, kcenon::common::config::cli_error_codes::invalid_key, kcenon::common::config::network_config::io_timeout, kcenon::common::config::network_config::keepalive_interval, kcenon::common::config::tls_config::key_path, kcenon::common::config::logger_config::level, kcenon::common::config::database_config::log_queries, kcenon::common::config::unified_config::logger, kcenon::common::make_error(), kcenon::common::config::logger_config::max_backup_files, kcenon::common::config::network_config::max_connections, kcenon::common::config::logger_config::max_file_size, kcenon::common::config::thread_config::max_queue_size, kcenon::common::config::pool_config::max_size, kcenon::common::config::monitoring_config::metrics_interval, kcenon::common::config::pool_config::min_size, kcenon::common::config::unified_config::monitoring, kcenon::common::config::unified_config::network, kcenon::common::Result< T >::ok(), parse_bool(), parse_double(), parse_int64(), parse_size_t(), kcenon::common::config::database_config::pool, kcenon::common::config::thread_config::pool_size, kcenon::common::config::monitoring_config::prometheus_path, kcenon::common::config::monitoring_config::prometheus_port, kcenon::common::config::thread_config::queue_type, kcenon::common::config::tracing_config::sampling_rate, kcenon::common::config::database_config::slow_query_threshold, kcenon::common::config::unified_config::thread, kcenon::common::config::thread_config::thread_name_prefix, kcenon::common::config::network_config::tls, kcenon::common::config::monitoring_config::tracing, kcenon::common::config::tls_config::verify_peer, and kcenon::common::config::tls_config::version.

Referenced by load_with_cli_overrides().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_with_cli_overrides()

static Result< unified_config > kcenon::common::config::cli_config_parser::load_with_cli_overrides ( int argc,
char ** argv )
inlinestatic

Load configuration with CLI overrides.

Parses CLI arguments, loads configuration from file (if specified), applies environment variable overrides, and then applies CLI overrides.

Priority (highest to lowest):

  1. –set key=value overrides
  2. Environment variables (UNIFIED_*)
  3. Configuration file
  4. Defaults
Parameters
argcNumber of arguments
argvArgument array
Returns
Result containing unified_config or error

Definition at line 183 of file cli_config_parser.h.

183 {
184 // Parse CLI arguments
185 auto parse_result = parse(argc, argv);
186 if (parse_result.is_err()) {
187 return make_error<unified_config>(parse_result.error());
188 }
189
190 auto args = parse_result.value();
191
192 // Handle --help and --version early
193 if (args.show_help || args.show_version) {
194 // Return an "error" to indicate the caller should handle this
197 args.show_help ? "help_requested" : "version_requested",
198 "cli_config_parser"
199 );
200 }
201
202 // Load configuration
203 unified_config config;
204
205 if (!args.config_path.empty()) {
206 // Load from file
207 auto load_result = config_loader::load(args.config_path);
208 if (load_result.is_err()) {
209 return make_error<unified_config>(load_result.error());
210 }
211 config = load_result.value();
212 } else {
213 // Load from environment only
214 auto load_result = config_loader::load_from_env();
215 if (load_result.is_err()) {
216 return make_error<unified_config>(load_result.error());
217 }
218 config = load_result.value();
219 }
220
221 // Apply CLI overrides
222 for (const auto& [key, value] : args.overrides) {
223 auto result = apply_override(config, key, value);
224 if (result.is_err()) {
225 return make_error<unified_config>(result.error());
226 }
227 }
228
229 // Validate final configuration
230 auto validation_result = config_loader::validate(config);
231 if (validation_result.is_err()) {
232 return make_error<unified_config>(validation_result.error());
233 }
234
235 return Result<unified_config>::ok(std::move(config));
236 }
static Result< parsed_args > parse(int argc, char **argv)
Parse command-line arguments.
static VoidResult apply_override(unified_config &config, const std::string &key, const std::string &value)
Apply a configuration override.
static VoidResult validate(const unified_config &config)
Validate a configuration.
static Result< unified_config > load_from_env()
Load configuration from environment variables only.
static Result< unified_config > load(const std::string &path)
Load configuration from a YAML file.

References apply_override(), kcenon::common::config::cli_error_codes::invalid_argument, kcenon::common::config::config_loader::load(), kcenon::common::config::config_loader::load_from_env(), kcenon::common::make_error(), kcenon::common::Result< T >::ok(), parse(), and kcenon::common::config::config_loader::validate().

Here is the call graph for this function:

◆ parse()

static Result< parsed_args > kcenon::common::config::cli_config_parser::parse ( int argc,
char ** argv )
inlinestatic

Parse command-line arguments.

Parses the given arguments and returns a parsed_args structure.

Parameters
argcNumber of arguments
argvArgument array
Returns
Result containing parsed_args or error

Definition at line 106 of file cli_config_parser.h.

106 {
107 parsed_args result;
108
109 for (int i = 1; i < argc; ++i) {
110 std::string arg = argv[i];
111
112 if (arg == "--help" || arg == "-h") {
113 result.show_help = true;
114 } else if (arg == "--version" || arg == "-v") {
115 result.show_version = true;
116 } else if (starts_with(arg, "--config=")) {
117 result.config_path = arg.substr(9);
118 } else if (arg == "--config") {
119 if (i + 1 >= argc) {
122 "Missing value for --config",
123 "cli_config_parser"
124 );
125 }
126 result.config_path = argv[++i];
127 } else if (starts_with(arg, "--set=")) {
128 auto kv_result = parse_key_value(arg.substr(6));
129 if (kv_result.is_err()) {
130 return make_error<parsed_args>(kv_result.error());
131 }
132 result.overrides.push_back(kv_result.value());
133 } else if (arg == "--set") {
134 if (i + 1 >= argc) {
137 "Missing value for --set",
138 "cli_config_parser"
139 );
140 }
141 auto kv_result = parse_key_value(argv[++i]);
142 if (kv_result.is_err()) {
143 return make_error<parsed_args>(kv_result.error());
144 }
145 result.overrides.push_back(kv_result.value());
146 } else if (starts_with(arg, "--")) {
149 "Unknown argument: " + arg,
150 "cli_config_parser"
151 );
152 } else if (starts_with(arg, "-")) {
155 "Unknown short argument: " + arg,
156 "cli_config_parser"
157 );
158 } else {
159 // Positional argument
160 result.positional_args.push_back(arg);
161 }
162 }
163
164 return Result<parsed_args>::ok(std::move(result));
165 }
static bool starts_with(const std::string &str, const std::string &prefix)
Check if a string starts with a prefix.
static Result< std::pair< std::string, std::string > > parse_key_value(const std::string &str)
Parse a key=value string.

References kcenon::common::config::parsed_args::config_path, kcenon::common::config::cli_error_codes::invalid_argument, kcenon::common::make_error(), kcenon::common::config::cli_error_codes::missing_value, kcenon::common::Result< T >::ok(), kcenon::common::config::parsed_args::overrides, parse_key_value(), kcenon::common::config::parsed_args::positional_args, kcenon::common::config::parsed_args::show_help, kcenon::common::config::parsed_args::show_version, and starts_with().

Referenced by load_with_cli_overrides(), and main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_bool()

static bool kcenon::common::config::cli_config_parser::parse_bool ( const std::string & value)
inlinestaticprivate

Definition at line 478 of file cli_config_parser.h.

478 {
479 std::string lower = value;
480 std::transform(lower.begin(), lower.end(), lower.begin(),
481 [](unsigned char c) { return std::tolower(c); });
482 return lower == "true" || lower == "1" || lower == "yes" || lower == "on";
483 }

Referenced by apply_override().

Here is the caller graph for this function:

◆ parse_double()

static double kcenon::common::config::cli_config_parser::parse_double ( const std::string & value)
inlinestaticprivate

Definition at line 470 of file cli_config_parser.h.

470 {
471 try {
472 return std::stod(value);
473 } catch (...) {
474 return 0.0;
475 }
476 }

Referenced by apply_override().

Here is the caller graph for this function:

◆ parse_int64()

static int64_t kcenon::common::config::cli_config_parser::parse_int64 ( const std::string & value)
inlinestaticprivate

Definition at line 462 of file cli_config_parser.h.

462 {
463 try {
464 return std::stoll(value);
465 } catch (...) {
466 return 0;
467 }
468 }

Referenced by apply_override().

Here is the caller graph for this function:

◆ parse_key_value()

static Result< std::pair< std::string, std::string > > kcenon::common::config::cli_config_parser::parse_key_value ( const std::string & str)
inlinestaticprivate

Parse a key=value string.

Definition at line 298 of file cli_config_parser.h.

298 {
299 auto pos = str.find('=');
300 if (pos == std::string::npos) {
303 "Invalid key=value format: " + str,
304 "cli_config_parser"
305 );
306 }
307
308 std::string key = str.substr(0, pos);
309 std::string value = str.substr(pos + 1);
310
311 // Trim whitespace from key
312 key.erase(0, key.find_first_not_of(" \t"));
313 key.erase(key.find_last_not_of(" \t") + 1);
314
315 if (key.empty()) {
318 "Empty key in key=value pair",
319 "cli_config_parser"
320 );
321 }
322
323 return Result<std::pair<std::string, std::string>>::ok(
324 std::make_pair(std::move(key), std::move(value)));
325 }
VoidResult ok()
Create a successful void result.
Definition utilities.h:71

References kcenon::common::config::cli_error_codes::invalid_format, kcenon::common::config::cli_error_codes::invalid_key, kcenon::common::make_error(), and kcenon::common::ok().

Referenced by parse().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_size_t()

static size_t kcenon::common::config::cli_config_parser::parse_size_t ( const std::string & value)
inlinestaticprivate

Definition at line 454 of file cli_config_parser.h.

454 {
455 try {
456 return std::stoull(value);
457 } catch (...) {
458 return 0;
459 }
460 }

Referenced by apply_override().

Here is the caller graph for this function:

◆ print_help()

static void kcenon::common::config::cli_config_parser::print_help ( const std::string & program_name = "program")
inlinestatic

Print help message to stdout.

Parameters
program_nameName of the program (usually argv[0])

Definition at line 243 of file cli_config_parser.h.

243 {
244 std::cout << "Usage: " << program_name << " [OPTIONS]\n\n"
245 << "Options:\n"
246 << " --config=<path> Load configuration from YAML file\n"
247 << " --set <key>=<value> Override a configuration value\n"
248 << " --help, -h Show this help message\n"
249 << " --version, -v Show version information\n\n"
250 << "Configuration keys:\n";
251
252 // Print available configuration keys
253 auto metadata = get_config_metadata();
254 for (const auto& field : metadata) {
255 std::cout << " " << field.path;
256 if (!field.allowed_values.empty()) {
257 std::cout << " (";
258 for (size_t i = 0; i < field.allowed_values.size(); ++i) {
259 if (i > 0) std::cout << "|";
260 std::cout << field.allowed_values[i];
261 }
262 std::cout << ")";
263 }
264 std::cout << "\n " << field.description;
265 if (!field.env_var.empty()) {
266 std::cout << " [env: " << field.env_var << "]";
267 }
268 std::cout << "\n";
269 }
270
271 std::cout << "\nExamples:\n"
272 << " " << program_name << " --config=config.yaml\n"
273 << " " << program_name << " --set logger.level=debug\n"
274 << " " << program_name << " --config=config.yaml --set thread.pool_size=16\n";
275 }
std::vector< field_metadata > get_config_metadata()
Get metadata for all configuration fields.

References kcenon::common::config::get_config_metadata().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ print_version()

static void kcenon::common::config::cli_config_parser::print_version ( const std::string & version = "0.1.0.0")
inlinestatic

Print version information to stdout.

Parameters
versionVersion string

Definition at line 282 of file cli_config_parser.h.

282 {
283 std::cout << "unified_system version " << version << "\n";
284 }

Referenced by main().

Here is the caller graph for this function:

◆ starts_with()

static bool kcenon::common::config::cli_config_parser::starts_with ( const std::string & str,
const std::string & prefix )
inlinestaticprivate

Check if a string starts with a prefix.

Definition at line 290 of file cli_config_parser.h.

290 {
291 return str.size() >= prefix.size() &&
292 str.compare(0, prefix.size(), prefix) == 0;
293 }

Referenced by parse().

Here is the caller graph for this function:

The documentation for this class was generated from the following file: