Common System 0.2.0
Common interfaces and patterns for system integration
Loading...
Searching...
No Matches
config_loader.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
28#pragma once
29
30#include "unified_config.h"
31
33
34#include <cstdlib>
35#include <filesystem>
36#include <fstream>
37#include <regex>
38#include <sstream>
39#include <string>
40#include <unordered_map>
41#include <vector>
42
43#ifdef BUILD_WITH_YAML_CPP
44#include <yaml-cpp/yaml.h>
45#endif
46
47namespace kcenon::common::config {
48
52namespace config_error_codes {
53 constexpr int file_not_found = 1001;
54 constexpr int parse_error = 1002;
55 constexpr int validation_error = 1003;
56 constexpr int invalid_value = 1004;
57 constexpr int io_error = 1005;
58}
59
64 std::string field_path;
65 std::string message;
66 bool is_warning = false; // false = error, true = warning
67};
68
95public:
106 static Result<unified_config> load(const std::string& path) {
107#ifdef BUILD_WITH_YAML_CPP
108 // Check if file exists
109 if (!std::filesystem::exists(path)) {
112 "Configuration file not found: " + path,
113 "config_loader"
114 );
115 }
116
117 try {
118 std::ifstream file(path);
119 if (!file.is_open()) {
122 "Failed to open configuration file: " + path,
123 "config_loader"
124 );
125 }
126
127 std::stringstream buffer;
128 buffer << file.rdbuf();
129 return load_from_string(buffer.str());
130 } catch (const std::exception& e) {
133 std::string("Failed to read configuration file: ") + e.what(),
134 "config_loader"
135 );
136 }
137#else
138 // Without yaml-cpp, we can only load from environment
139 (void)path; // Suppress unused parameter warning
142 "YAML support not available. Build with -DBUILD_WITH_YAML_CPP=ON",
143 "config_loader"
144 );
145#endif
146 }
147
157 static Result<unified_config> load_from_string(const std::string& yaml_content) {
158#ifdef BUILD_WITH_YAML_CPP
159 try {
160 // Expand environment variables in the YAML content
161 std::string expanded = expand_env_vars(yaml_content);
162
163 YAML::Node root = YAML::Load(expanded);
164
165 // Start with defaults
166 unified_config config = defaults();
167
168 // Parse the YAML into config
169 auto parse_result = parse_yaml(root, config);
170 if (parse_result.is_err()) {
171 return make_error<unified_config>(parse_result.error());
172 }
173
174 // Apply environment variable overrides
175 auto env_result = merge_env_overrides(config);
176 if (env_result.is_err()) {
177 return make_error<unified_config>(env_result.error());
178 }
179
180 // Validate the configuration
181 auto validation_result = validate(config);
182 if (validation_result.is_err()) {
183 return make_error<unified_config>(validation_result.error());
184 }
185
186 return Result<unified_config>::ok(std::move(config));
187 } catch (const YAML::ParserException& e) {
190 std::string("YAML parse error: ") + e.what(),
191 "config_loader"
192 );
193 } catch (const std::exception& e) {
196 std::string("Failed to parse configuration: ") + e.what(),
197 "config_loader"
198 );
199 }
200#else
201 (void)yaml_content;
204 "YAML support not available. Build with -DBUILD_WITH_YAML_CPP=ON",
205 "config_loader"
206 );
207#endif
208 }
209
219 unified_config config = defaults();
220
221 auto result = merge_env_overrides(config);
222 if (result.is_err()) {
223 return make_error<unified_config>(result.error());
224 }
225
226 auto validation_result = validate(config);
227 if (validation_result.is_err()) {
228 return make_error<unified_config>(validation_result.error());
229 }
230
231 return Result<unified_config>::ok(std::move(config));
232 }
233
240 }
241
251 static VoidResult validate(const unified_config& config) {
252 std::vector<validation_issue> issues;
253
254 // Validate thread configuration
255 validate_thread_config(config.thread, issues);
256
257 // Validate logger configuration
258 validate_logger_config(config.logger, issues);
259
260 // Validate monitoring configuration
262
263 // Validate database configuration
264 validate_database_config(config.database, issues);
265
266 // Validate network configuration
267 validate_network_config(config.network, issues);
268
269 // Check for errors (not warnings)
270 for (const auto& issue : issues) {
271 if (!issue.is_warning) {
274 "Validation failed for " + issue.field_path + ": " + issue.message,
275 "config_loader"
276 );
277 }
278 }
279
280 return VoidResult::ok({});
281 }
282
291 static std::vector<validation_issue> get_validation_issues(const unified_config& config) {
292 std::vector<validation_issue> issues;
293
294 validate_thread_config(config.thread, issues);
295 validate_logger_config(config.logger, issues);
297 validate_database_config(config.database, issues);
298 validate_network_config(config.network, issues);
299
300 return issues;
301 }
302
313 static std::string expand_env_vars(const std::string& value) {
314 static const std::regex env_pattern(R"(\$\{([^}]+)\})");
315
316 std::string result = value;
317 std::smatch match;
318 std::string::const_iterator search_start = result.cbegin();
319
320 std::string output;
321 size_t last_pos = 0;
322
323 while (std::regex_search(search_start, result.cend(), match, env_pattern)) {
324 size_t match_pos = static_cast<size_t>(match.position()) +
325 static_cast<size_t>(std::distance(result.cbegin(), search_start));
326
327 // Append text before the match
328 output += result.substr(last_pos, match_pos - last_pos);
329
330 // Get environment variable
331 std::string var_name = match[1].str();
332 const char* env_value = std::getenv(var_name.c_str());
333
334 if (env_value != nullptr) {
335 output += env_value;
336 } else {
337 // Keep the original pattern if variable not found
338 output += match[0].str();
339 }
340
341 last_pos = match_pos + match[0].length();
342 search_start = match.suffix().first;
343 }
344
345 // Append remaining text
346 output += result.substr(last_pos);
347
348 return output;
349 }
350
351private:
356 // Thread configuration
357 apply_env_override("UNIFIED_THREAD_POOL_SIZE", config.thread.pool_size);
358 apply_env_override("UNIFIED_THREAD_QUEUE_TYPE", config.thread.queue_type);
359 apply_env_override("UNIFIED_THREAD_MAX_QUEUE_SIZE", config.thread.max_queue_size);
360 apply_env_override("UNIFIED_THREAD_NAME_PREFIX", config.thread.thread_name_prefix);
361
362 // Logger configuration
363 apply_env_override("UNIFIED_LOGGER_LEVEL", config.logger.level);
364 apply_env_override_bool("UNIFIED_LOGGER_ASYNC", config.logger.async);
365 apply_env_override("UNIFIED_LOGGER_BUFFER_SIZE", config.logger.buffer_size);
366 apply_env_override("UNIFIED_LOGGER_FILE_PATH", config.logger.file_path);
367 apply_env_override("UNIFIED_LOGGER_MAX_FILE_SIZE", config.logger.max_file_size);
368 apply_env_override("UNIFIED_LOGGER_MAX_BACKUP_FILES", config.logger.max_backup_files);
369 apply_env_override("UNIFIED_LOGGER_FORMAT_PATTERN", config.logger.format_pattern);
370 apply_env_override_vector("UNIFIED_LOGGER_WRITERS", config.logger.writers);
371
372 // Monitoring configuration
373 apply_env_override_bool("UNIFIED_MONITORING_ENABLED", config.monitoring.enabled);
374 apply_env_override_ms("UNIFIED_MONITORING_METRICS_INTERVAL_MS", config.monitoring.metrics_interval);
375 apply_env_override_ms("UNIFIED_MONITORING_HEALTH_CHECK_INTERVAL_MS", config.monitoring.health_check_interval);
376 apply_env_override("UNIFIED_MONITORING_PROMETHEUS_PORT", config.monitoring.prometheus_port);
377 apply_env_override("UNIFIED_MONITORING_PROMETHEUS_PATH", config.monitoring.prometheus_path);
378
379 // Tracing configuration
380 apply_env_override_bool("UNIFIED_MONITORING_TRACING_ENABLED", config.monitoring.tracing.enabled);
381 apply_env_override_double("UNIFIED_MONITORING_TRACING_SAMPLING_RATE", config.monitoring.tracing.sampling_rate);
382 apply_env_override("UNIFIED_MONITORING_TRACING_EXPORTER", config.monitoring.tracing.exporter);
383 apply_env_override("UNIFIED_MONITORING_TRACING_ENDPOINT", config.monitoring.tracing.endpoint);
384
385 // Database configuration
386 apply_env_override("UNIFIED_DATABASE_BACKEND", config.database.backend);
387 apply_env_override("UNIFIED_DATABASE_CONNECTION_STRING", config.database.connection_string);
388 apply_env_override_bool("UNIFIED_DATABASE_LOG_QUERIES", config.database.log_queries);
389 apply_env_override_ms("UNIFIED_DATABASE_SLOW_QUERY_THRESHOLD_MS", config.database.slow_query_threshold);
390 apply_env_override("UNIFIED_DATABASE_POOL_MIN_SIZE", config.database.pool.min_size);
391 apply_env_override("UNIFIED_DATABASE_POOL_MAX_SIZE", config.database.pool.max_size);
392 apply_env_override_ms("UNIFIED_DATABASE_POOL_IDLE_TIMEOUT_MS", config.database.pool.idle_timeout);
393 apply_env_override_ms("UNIFIED_DATABASE_POOL_ACQUIRE_TIMEOUT_MS", config.database.pool.acquire_timeout);
394
395 // Network configuration
396 apply_env_override("UNIFIED_NETWORK_COMPRESSION", config.network.compression);
397 apply_env_override("UNIFIED_NETWORK_BUFFER_SIZE", config.network.buffer_size);
398 apply_env_override_ms("UNIFIED_NETWORK_CONNECT_TIMEOUT_MS", config.network.connect_timeout);
399 apply_env_override_ms("UNIFIED_NETWORK_IO_TIMEOUT_MS", config.network.io_timeout);
400 apply_env_override_ms("UNIFIED_NETWORK_KEEPALIVE_INTERVAL_MS", config.network.keepalive_interval);
401 apply_env_override("UNIFIED_NETWORK_MAX_CONNECTIONS", config.network.max_connections);
402
403 // TLS configuration
404 apply_env_override_bool("UNIFIED_NETWORK_TLS_ENABLED", config.network.tls.enabled);
405 apply_env_override("UNIFIED_NETWORK_TLS_VERSION", config.network.tls.version);
406 apply_env_override("UNIFIED_NETWORK_TLS_CERT_PATH", config.network.tls.cert_path);
407 apply_env_override("UNIFIED_NETWORK_TLS_KEY_PATH", config.network.tls.key_path);
408 apply_env_override("UNIFIED_NETWORK_TLS_CA_PATH", config.network.tls.ca_path);
409 apply_env_override_bool("UNIFIED_NETWORK_TLS_VERIFY_PEER", config.network.tls.verify_peer);
410
411 return VoidResult::ok({});
412 }
413
414 // Environment variable helpers
415
416 static void apply_env_override(const char* env_name, std::string& target) {
417 const char* value = std::getenv(env_name);
418 if (value != nullptr) {
419 target = value;
420 }
421 }
422
423 static void apply_env_override(const char* env_name, size_t& target) {
424 const char* value = std::getenv(env_name);
425 if (value != nullptr) {
426 try {
427 target = std::stoull(value);
428 } catch (...) {
429 // Ignore invalid values
430 }
431 }
432 }
433
434 static void apply_env_override(const char* env_name, uint16_t& target) {
435 const char* value = std::getenv(env_name);
436 if (value != nullptr) {
437 try {
438 auto parsed = std::stoul(value);
439 if (parsed <= 65535) {
440 target = static_cast<uint16_t>(parsed);
441 }
442 } catch (...) {
443 // Ignore invalid values
444 }
445 }
446 }
447
448 static void apply_env_override_bool(const char* env_name, bool& target) {
449 const char* value = std::getenv(env_name);
450 if (value != nullptr) {
451 std::string str_value(value);
452 // Convert to lowercase for comparison
453 std::transform(str_value.begin(), str_value.end(), str_value.begin(),
454 [](unsigned char c) { return std::tolower(c); });
455
456 if (str_value == "true" || str_value == "1" || str_value == "yes" || str_value == "on") {
457 target = true;
458 } else if (str_value == "false" || str_value == "0" || str_value == "no" || str_value == "off") {
459 target = false;
460 }
461 }
462 }
463
464 static void apply_env_override_double(const char* env_name, double& target) {
465 const char* value = std::getenv(env_name);
466 if (value != nullptr) {
467 try {
468 target = std::stod(value);
469 } catch (...) {
470 // Ignore invalid values
471 }
472 }
473 }
474
475 static void apply_env_override_ms(const char* env_name, std::chrono::milliseconds& target) {
476 const char* value = std::getenv(env_name);
477 if (value != nullptr) {
478 try {
479 target = std::chrono::milliseconds{std::stoll(value)};
480 } catch (...) {
481 // Ignore invalid values
482 }
483 }
484 }
485
486 static void apply_env_override_vector(const char* env_name, std::vector<std::string>& target) {
487 const char* value = std::getenv(env_name);
488 if (value != nullptr) {
489 target.clear();
490 std::string str_value(value);
491 std::stringstream ss(str_value);
492 std::string item;
493 while (std::getline(ss, item, ',')) {
494 // Trim whitespace
495 size_t start = item.find_first_not_of(" \t");
496 size_t end = item.find_last_not_of(" \t");
497 if (start != std::string::npos && end != std::string::npos) {
498 target.push_back(item.substr(start, end - start + 1));
499 }
500 }
501 }
502 }
503
504#ifdef BUILD_WITH_YAML_CPP
508 static VoidResult parse_yaml(const YAML::Node& root, unified_config& config) {
509 try {
510 // Look for unified_system key or use root directly
511 YAML::Node system_node = root["unified_system"];
512 if (!system_node) {
513 system_node = root;
514 }
515
516 // Parse thread configuration
517 if (system_node["thread"]) {
518 parse_thread_config(system_node["thread"], config.thread);
519 }
520
521 // Parse logger configuration
522 if (system_node["logger"]) {
523 parse_logger_config(system_node["logger"], config.logger);
524 }
525
526 // Parse monitoring configuration
527 if (system_node["monitoring"]) {
528 parse_monitoring_config(system_node["monitoring"], config.monitoring);
529 }
530
531 // Parse database configuration
532 if (system_node["database"]) {
533 parse_database_config(system_node["database"], config.database);
534 }
535
536 // Parse network configuration
537 if (system_node["network"]) {
538 parse_network_config(system_node["network"], config.network);
539 }
540
541 return VoidResult::ok({});
542 } catch (const YAML::Exception& e) {
545 std::string("YAML parse error: ") + e.what(),
546 "config_loader"
547 );
548 }
549 }
550
551 static void parse_thread_config(const YAML::Node& node, thread_config& config) {
552 if (node["pool_size"]) {
553 config.pool_size = node["pool_size"].as<size_t>();
554 }
555 if (node["queue_type"]) {
556 config.queue_type = node["queue_type"].as<std::string>();
557 }
558 if (node["max_queue_size"]) {
559 config.max_queue_size = node["max_queue_size"].as<size_t>();
560 }
561 if (node["thread_name_prefix"]) {
562 config.thread_name_prefix = node["thread_name_prefix"].as<std::string>();
563 }
564 }
565
566 static void parse_logger_config(const YAML::Node& node, logger_config& config) {
567 if (node["level"]) {
568 config.level = node["level"].as<std::string>();
569 }
570 if (node["writers"]) {
571 config.writers.clear();
572 for (const auto& writer : node["writers"]) {
573 config.writers.push_back(writer.as<std::string>());
574 }
575 }
576 if (node["async"]) {
577 config.async = node["async"].as<bool>();
578 }
579 if (node["buffer_size"]) {
580 config.buffer_size = node["buffer_size"].as<size_t>();
581 }
582 if (node["file_path"]) {
583 config.file_path = node["file_path"].as<std::string>();
584 }
585 if (node["max_file_size"]) {
586 config.max_file_size = node["max_file_size"].as<size_t>();
587 }
588 if (node["max_backup_files"]) {
589 config.max_backup_files = node["max_backup_files"].as<size_t>();
590 }
591 if (node["format_pattern"]) {
592 config.format_pattern = node["format_pattern"].as<std::string>();
593 }
594 }
595
596 static void parse_monitoring_config(const YAML::Node& node, monitoring_config& config) {
597 if (node["enabled"]) {
598 config.enabled = node["enabled"].as<bool>();
599 }
600 if (node["metrics_interval_ms"]) {
601 config.metrics_interval = std::chrono::milliseconds{node["metrics_interval_ms"].as<int64_t>()};
602 }
603 if (node["health_check_interval_ms"]) {
604 config.health_check_interval = std::chrono::milliseconds{node["health_check_interval_ms"].as<int64_t>()};
605 }
606 if (node["prometheus_port"]) {
607 config.prometheus_port = node["prometheus_port"].as<uint16_t>();
608 }
609 if (node["prometheus_path"]) {
610 config.prometheus_path = node["prometheus_path"].as<std::string>();
611 }
612
613 // Tracing configuration
614 if (node["tracing"]) {
615 auto tracing = node["tracing"];
616 if (tracing["enabled"]) {
617 config.tracing.enabled = tracing["enabled"].as<bool>();
618 }
619 if (tracing["sampling_rate"]) {
620 config.tracing.sampling_rate = tracing["sampling_rate"].as<double>();
621 }
622 if (tracing["exporter"]) {
623 config.tracing.exporter = tracing["exporter"].as<std::string>();
624 }
625 if (tracing["endpoint"]) {
626 config.tracing.endpoint = tracing["endpoint"].as<std::string>();
627 }
628 }
629 }
630
631 static void parse_database_config(const YAML::Node& node, database_config& config) {
632 if (node["backend"]) {
633 config.backend = node["backend"].as<std::string>();
634 }
635 if (node["connection_string"]) {
636 config.connection_string = node["connection_string"].as<std::string>();
637 }
638 if (node["log_queries"]) {
639 config.log_queries = node["log_queries"].as<bool>();
640 }
641 if (node["slow_query_threshold_ms"]) {
642 config.slow_query_threshold = std::chrono::milliseconds{node["slow_query_threshold_ms"].as<int64_t>()};
643 }
644
645 // Pool configuration
646 if (node["pool"]) {
647 auto pool = node["pool"];
648 if (pool["min_size"]) {
649 config.pool.min_size = pool["min_size"].as<size_t>();
650 }
651 if (pool["max_size"]) {
652 config.pool.max_size = pool["max_size"].as<size_t>();
653 }
654 if (pool["idle_timeout_ms"]) {
655 config.pool.idle_timeout = std::chrono::milliseconds{pool["idle_timeout_ms"].as<int64_t>()};
656 }
657 if (pool["acquire_timeout_ms"]) {
658 config.pool.acquire_timeout = std::chrono::milliseconds{pool["acquire_timeout_ms"].as<int64_t>()};
659 }
660 }
661 }
662
663 static void parse_network_config(const YAML::Node& node, network_config& config) {
664 if (node["compression"]) {
665 config.compression = node["compression"].as<std::string>();
666 }
667 if (node["buffer_size"]) {
668 config.buffer_size = node["buffer_size"].as<size_t>();
669 }
670 if (node["connect_timeout_ms"]) {
671 config.connect_timeout = std::chrono::milliseconds{node["connect_timeout_ms"].as<int64_t>()};
672 }
673 if (node["io_timeout_ms"]) {
674 config.io_timeout = std::chrono::milliseconds{node["io_timeout_ms"].as<int64_t>()};
675 }
676 if (node["keepalive_interval_ms"]) {
677 config.keepalive_interval = std::chrono::milliseconds{node["keepalive_interval_ms"].as<int64_t>()};
678 }
679 if (node["max_connections"]) {
680 config.max_connections = node["max_connections"].as<size_t>();
681 }
682
683 // TLS configuration
684 if (node["tls"]) {
685 auto tls = node["tls"];
686 if (tls["enabled"]) {
687 config.tls.enabled = tls["enabled"].as<bool>();
688 }
689 if (tls["version"]) {
690 config.tls.version = tls["version"].as<std::string>();
691 }
692 if (tls["cert_path"]) {
693 config.tls.cert_path = tls["cert_path"].as<std::string>();
694 }
695 if (tls["key_path"]) {
696 config.tls.key_path = tls["key_path"].as<std::string>();
697 }
698 if (tls["ca_path"]) {
699 config.tls.ca_path = tls["ca_path"].as<std::string>();
700 }
701 if (tls["verify_peer"]) {
702 config.tls.verify_peer = tls["verify_peer"].as<bool>();
703 }
704 }
705 }
706#endif
707
708 // Validation helpers
709
710 static void validate_thread_config(const thread_config& config, std::vector<validation_issue>& issues) {
711 // Queue type validation
712 static const std::vector<std::string> valid_queue_types = {"mutex", "lockfree", "bounded"};
713 if (std::find(valid_queue_types.begin(), valid_queue_types.end(), config.queue_type) == valid_queue_types.end()) {
714 issues.push_back({"thread.queue_type",
715 "Invalid queue type: " + config.queue_type + ". Valid values: mutex, lockfree, bounded",
716 false});
717 }
718
719 // Max queue size validation
720 if (config.max_queue_size == 0) {
721 issues.push_back({"thread.max_queue_size", "Queue size must be greater than 0", false});
722 }
723 }
724
725 static void validate_logger_config(const logger_config& config, std::vector<validation_issue>& issues) {
726 // Log level validation
727 static const std::vector<std::string> valid_levels = {"trace", "debug", "info", "warn", "error", "critical", "off"};
728 if (std::find(valid_levels.begin(), valid_levels.end(), config.level) == valid_levels.end()) {
729 issues.push_back({"logger.level",
730 "Invalid log level: " + config.level + ". Valid values: trace, debug, info, warn, error, critical, off",
731 false});
732 }
733
734 // Writers validation
735 static const std::vector<std::string> valid_writers = {"console", "file", "rotating_file", "network", "json"};
736 for (const auto& writer : config.writers) {
737 if (std::find(valid_writers.begin(), valid_writers.end(), writer) == valid_writers.end()) {
738 issues.push_back({"logger.writers",
739 "Invalid writer: " + writer + ". Valid values: console, file, rotating_file, network, json",
740 false});
741 }
742 }
743
744 // Buffer size warning
745 if (config.async && config.buffer_size < 1024) {
746 issues.push_back({"logger.buffer_size",
747 "Buffer size is very small for async logging. Consider using at least 1024 bytes.",
748 true});
749 }
750 }
751
752 static void validate_monitoring_config(const monitoring_config& config, std::vector<validation_issue>& issues) {
753 // Sampling rate validation
754 if (config.tracing.sampling_rate < 0.0 || config.tracing.sampling_rate > 1.0) {
755 issues.push_back({"monitoring.tracing.sampling_rate",
756 "Sampling rate must be between 0.0 and 1.0",
757 false});
758 }
759
760 // Exporter validation
761 static const std::vector<std::string> valid_exporters = {"otlp", "jaeger", "zipkin", "console"};
762 if (std::find(valid_exporters.begin(), valid_exporters.end(), config.tracing.exporter) == valid_exporters.end()) {
763 issues.push_back({"monitoring.tracing.exporter",
764 "Invalid exporter: " + config.tracing.exporter + ". Valid values: otlp, jaeger, zipkin, console",
765 false});
766 }
767
768 // Metrics interval warning
769 if (config.metrics_interval.count() < 1000) {
770 issues.push_back({"monitoring.metrics_interval",
771 "Metrics interval is very short (<1s). This may cause performance issues.",
772 true});
773 }
774 }
775
776 static void validate_database_config(const database_config& config, std::vector<validation_issue>& issues) {
777 // Backend validation (if specified)
778 if (!config.backend.empty()) {
779 static const std::vector<std::string> valid_backends = {"postgresql", "mysql", "sqlite", "mongodb", "redis"};
780 if (std::find(valid_backends.begin(), valid_backends.end(), config.backend) == valid_backends.end()) {
781 issues.push_back({"database.backend",
782 "Invalid backend: " + config.backend + ". Valid values: postgresql, mysql, sqlite, mongodb, redis",
783 false});
784 }
785 }
786
787 // Pool size validation
788 if (config.pool.min_size > config.pool.max_size) {
789 issues.push_back({"database.pool",
790 "min_size cannot be greater than max_size",
791 false});
792 }
793
794 if (config.pool.max_size == 0) {
795 issues.push_back({"database.pool.max_size",
796 "Pool max_size must be greater than 0",
797 false});
798 }
799 }
800
801 static void validate_network_config(const network_config& config, std::vector<validation_issue>& issues) {
802 // Compression validation
803 static const std::vector<std::string> valid_compressions = {"none", "lz4", "gzip", "deflate", "zstd"};
804 if (std::find(valid_compressions.begin(), valid_compressions.end(), config.compression) == valid_compressions.end()) {
805 issues.push_back({"network.compression",
806 "Invalid compression: " + config.compression + ". Valid values: none, lz4, gzip, deflate, zstd",
807 false});
808 }
809
810 // TLS version validation
811 static const std::vector<std::string> valid_tls_versions = {"1.2", "1.3"};
812 if (std::find(valid_tls_versions.begin(), valid_tls_versions.end(), config.tls.version) == valid_tls_versions.end()) {
813 issues.push_back({"network.tls.version",
814 "Invalid TLS version: " + config.tls.version + ". Valid values: 1.2, 1.3",
815 false});
816 }
817
818 // Buffer size warning
819 if (config.buffer_size < 4096) {
820 issues.push_back({"network.buffer_size",
821 "Buffer size is very small (<4KB). This may cause performance issues.",
822 true});
823 }
824
825 // TLS certificate validation
826 if (config.tls.enabled && config.tls.verify_peer && config.tls.ca_path.empty()) {
827 issues.push_back({"network.tls.ca_path",
828 "TLS is enabled with verify_peer but no CA path specified.",
829 true});
830 }
831 }
832};
833
834} // namespace kcenon::common::config
Result type for error handling with member function support.
Definition core.cppm:165
static Result< T > ok(U &&value)
Create a successful result with value (static factory)
Definition core.h:223
Loads and validates unified configuration from various sources.
static unified_config defaults()
Get default configuration.
static std::string expand_env_vars(const std::string &value)
Expand environment variables in a string.
static VoidResult validate(const unified_config &config)
Validate a configuration.
static Result< unified_config > load_from_string(const std::string &yaml_content)
Load configuration from a YAML string.
static std::vector< validation_issue > get_validation_issues(const unified_config &config)
Get all validation issues for a configuration.
static void apply_env_override_bool(const char *env_name, bool &target)
static void apply_env_override_vector(const char *env_name, std::vector< std::string > &target)
static void apply_env_override(const char *env_name, std::string &target)
static void apply_env_override(const char *env_name, size_t &target)
static Result< unified_config > load_from_env()
Load configuration from environment variables only.
static void validate_logger_config(const logger_config &config, std::vector< validation_issue > &issues)
static Result< unified_config > load(const std::string &path)
Load configuration from a YAML file.
static void validate_database_config(const database_config &config, std::vector< validation_issue > &issues)
static VoidResult merge_env_overrides(unified_config &config)
Apply environment variable overrides to configuration.
static void apply_env_override(const char *env_name, uint16_t &target)
static void validate_monitoring_config(const monitoring_config &config, std::vector< validation_issue > &issues)
static void validate_network_config(const network_config &config, std::vector< validation_issue > &issues)
static void validate_thread_config(const thread_config &config, std::vector< validation_issue > &issues)
static void apply_env_override_ms(const char *env_name, std::chrono::milliseconds &target)
static void apply_env_override_double(const char *env_name, double &target)
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
Umbrella header for Result<T> type and related utilities.
Database system configuration.
bool log_queries
Enable query logging.
std::string connection_string
Connection string or URI.
std::string backend
Database backend: "postgresql", "mysql", "sqlite", "mongodb", "redis".
pool_config pool
Connection pool configuration.
std::chrono::milliseconds slow_query_threshold
Slow query threshold.
Logging system configuration.
bool async
Enable async logging.
size_t max_file_size
Maximum file size in bytes (for rotating_file)
std::vector< std::string > writers
List of writers: "console", "file", "rotating_file", "network", "json".
std::string file_path
Log file path (for file writers)
size_t max_backup_files
Maximum number of backup files (for rotating_file)
size_t buffer_size
Async buffer size in bytes.
std::string format_pattern
Log format pattern.
std::string level
Log level: "trace", "debug", "info", "warn", "error", "critical", "off".
Monitoring system configuration.
std::chrono::milliseconds metrics_interval
Metrics collection interval.
uint16_t prometheus_port
Prometheus metrics port (0 to disable)
std::chrono::milliseconds health_check_interval
Health check interval.
std::string prometheus_path
Prometheus metrics path.
tracing_config tracing
Tracing configuration.
Network system configuration.
std::chrono::milliseconds connect_timeout
Connection timeout.
size_t max_connections
Maximum concurrent connections (server)
std::chrono::milliseconds io_timeout
Read/write timeout.
size_t buffer_size
Send/receive buffer size.
tls_config tls
TLS configuration.
std::string compression
Compression type: "none", "lz4", "gzip", "deflate", "zstd".
std::chrono::milliseconds keepalive_interval
Keep-alive interval.
size_t max_size
Maximum pool size.
size_t min_size
Minimum pool size.
std::chrono::milliseconds acquire_timeout
Connection acquisition timeout.
std::chrono::milliseconds idle_timeout
Idle connection timeout.
std::string queue_type
Queue type: "mutex", "lockfree", "bounded".
size_t pool_size
Number of worker threads (default: hardware concurrency)
size_t max_queue_size
Maximum queue size (for bounded queue)
std::string thread_name_prefix
Thread naming prefix.
std::string version
TLS version: "1.2", "1.3".
std::string key_path
Private key file path.
bool verify_peer
Verify peer certificate.
std::string cert_path
Certificate file path.
std::string ca_path
CA certificate path (for client verification)
std::string endpoint
Exporter endpoint.
std::string exporter
Exporter type: "otlp", "jaeger", "zipkin", "console".
double sampling_rate
Sampling rate (0.0 to 1.0)
Root configuration structure for the unified system.
network_config network
Network system configuration.
logger_config logger
Logger system configuration.
static unified_config defaults()
Create a configuration with all default values.
thread_config thread
Thread system configuration.
monitoring_config monitoring
Monitoring system configuration.
database_config database
Database system configuration.
Validation result for a configuration field.
Unified configuration schema for the entire system.