Parse section configurations

本文介绍了Fluentd中解析配置的使用方法,包括如何指定解析插件类型、配置解析参数等。通过示例展示了不同解析插件的应用场景,如正则表达式解析、CSV解析等,并解释了如何处理时间字段。

Some of Fluentd’s plugins support the <parse> section to specify how to parse raw data.

Table of Contents

Parse section overview

Parse section can be in <source><match> or <filter> sections. It’s enabled for plugins which support parser plugin features.

<source>
  @type tail
  # parameters for input plugin
  <parse>
    # parse section parameters
  </parse>
</source>

parser plugin type

<parse> section requires @type parameter to specify the type of parser plugin. Fluentd core bundles a lot of useful parser plugins. 3rd party plugins are also available when installed.

<parse>
  @type apache2
</parse>

For more details, see plugins documentation.

Parameters

@type

@type key is to specify the type of parser plugin.

<parse>
  @type regexp
  # ...
</parse>

These parsers are built-in by default.

Parse parameters

These parameters default value will be overwritten by individual parser plugins.

  • types (hash) (optional): Specify types for converting field into other type. See below “The detail of types parameter” section.
    • Default: nil
    • string-based hash: field1:type, field2:type, field3:type:option, field4:type:option
    • JSON format:{"field1":"type", "field2":"type", "field3":"type:option", "field4":"type:option"}
    • example: types user_id:integer,paid:bool,paid_usd_amount:float
  • time_key (string) (optional): Specify time field for event time. If the event doesn’t have this field, current time is used.
    • Default: nil
  • null_value_pattern (string) (optional): Specify null value pattern.
    • Default: nil
  • null_empty_string (bool) (optional): If true, empty string field is replaced with nil.
    • Default: false
  • estimate_current_event (bool) (optional): If true, use Fluent::EventTime.now(current time) as a timestamp when time_key is specified.
    • Default: false
  • keep_time_key (bool) (optional): If true, keep time field in the record.
    • Default: false
The detail of types parameter

The list of supported types are shown below:

  • string

Convert field into String type. This uses to_s method for conversion.

  • bool

Convert "true""yes" or "1" string into true. Otherwise, false.

  • integer (“int” would NOT work!)

Convert field into Integer type. This uses to_i method for conversion. For example, "1000" string is converted into 1000.

  • float

Convert field into Float type. This uses to_f method for conversion. For example, "7.45" string is converted into 7.45.

  • time

Convert field into Fluent::EventTime type. This uses Fluentd’s time parser for conversion. For time type, the third field specifies a time format you would in time_format.

date:time:%d/%b/%Y:%H:%M:%S %z # for string with time format
date:time:unixtime             # for integer time
date:time:float                # for float time

See time_type and time_format parameters in Time parameters section.

  • array

Convert string field into Array type. For the “array” type, the third field specifies the delimiter (the default is “,”). For example, if a field called “item_ids” contains the value "3,4,5"types item_ids:array parses it as ["3", "4", "5"]. Alternatively, if the value is "Adam|Alice|Bob"types item_ids:array:| parses it as ["Adam", "Alice", "Bob"].

Time parameters

  • time_type (enum) (optional): parse/format value according to this type
    • Default: float
    • Available values: floatunixtimestring
      • float: seconds from Epoch + nano seconds (e.g. 1510544836.154709804)
      • unixtime: seconds from Epoch (e.g. 1510544815)
      • string: use format specified by time_format, local time or time zone
  • time_format (string) (optional): process value using specified format. This is available only when time_type is string
    • Default: nil
    • Available time format:
      • For more details about formatting, see Time#strftime
      • For more details about parsing, see Time.strptime
      • %iso8601 (only for parsing)
  • localtime (bool) (optional): if true, use local time. Otherwise, UTC is used. This is exclusive with utc.
    • Default: true
  • utc (bool) (optional): if true, use UTC. Otherwise, local time is used. This is exclusive with localtime.
    • Default: false
  • timezone (string) (optional): use specified timezone. one can parse/format the time value in the specified timezone.
    • Default: nil
    • Available time zone format:
      1. [+-]HH:MM (e.g. “+09:00”) (recommended)
      2. [+-]HHMM (e.g. “+0900”)
      3. [+-]HH (e.g. “+09”)
      4. Region/Zone (e.g. “Asia/Tokyo”)
      5. Region/Zone/Zone (e.g. “America/Argentina/Buenos_Aires”)
int rtsps_read_metadataconf() { struct uci_context *ctx = NULL; struct uci_package *pkg = NULL; struct uci_element *e, *e1; int ret = -1; int chn = 0; int g_metadata_config_count = 0; // Initialize UCI context ctx = uci_alloc_context(); if (!ctx) { CHM_DPRINTF(MSG_ERROR, "Failed to allocate UCI context\n"); goto cleanup; } // lookuo package pkg = uci_lookup_package(ctx, METADATA_CONF_FILE); if (NULL != pkg) { goto cleanup; } // Load the package if (uci_load(ctx, METADATA_CONF_FILE, &pkg) != 0) { printf("Failed to load UCI package: %s\n", METADATA_CONF_FILE); goto cleanup; } // Reset global config count g_metadata_config_count = 0; // Iterate through all sections in the package uci_foreach_element(&pkg->sections, e) { struct uci_section *s = uci_to_section(e); // Only process metadatacf sections if (strcmp(s->type, METADATA_CONF_SEC_TYPE) != 0) { continue; } // Check if we have space in our global array if (g_metadata_config_count >= MAX_METADATA_SECTIONS) { printf("Reached maximum metadata sections (%d)\n", MAX_METADATA_SECTIONS); break; } // Store section name if (sscanf(s->e.name, METADATA_CONF_SEC_NAME, &chn) == 1) { // Successfully parsed the channel number if (chn >= 0 && chn < MAX_METADATA_SECTIONS) { snprintf(g_metadata_configs[chn - 1].section_name, sizeof(g_metadata_configs[0].section_name), METADATA_CONF_SEC_NAME, chn); } else { continue; } } else { // Handle format mismatch printf("set mis-format metadata configurations section name %s \n", s->e.name); continue; } // Parse options struct uci_option *opt; uci_foreach_element(&s->options, e1) { opt = uci_to_option(e1); if (strcmp(opt->e.name, "events") == 0) { g_metadata_configs[g_metadata_config_count].events = (strcasecmp(opt->v.string, "on") == 0) ? 1 : 0; } else if (strcmp(opt->e.name, "analytics") == 0) { g_metadata_configs[g_metadata_config_count].analytics = (strcasecmp(opt->v.string, "on") == 0) ? 1 : 0; } else if (strcmp(opt->e.name, "ptzstatus") == 0) { g_metadata_configs[g_metadata_config_count].ptzstatus = (strcasecmp(opt->v.string, "on") == 0) ? 1 : 0; } else if (strcmp(opt->e.name, "ptzposition") == 0) { g_metadata_configs[g_metadata_config_count].ptzposition = (strcasecmp(opt->v.string, "on") == 0) ? 1 : 0; } } g_metadata_config_count++; } ret = 0; printf("Successfully loaded %d metadata configurations\n", g_metadata_config_count); cleanup: if (pkg) { uci_unload(ctx, pkg); } if (ctx) { uci_free_context(ctx); } return ret; } void init_metadata_configs() { for (int i = 0; i < MAX_METADATA_SECTIONS; i++) { snprintf(g_metadata_configs[i].section_name, sizeof(g_metadata_configs[0].section_name), METADATA_CONF_SEC_NAME, i + 1); // Set default values: 0,1,0,0 g_metadata_configs[i].events = 0; g_metadata_configs[i].analytics = 1; // Default to 1 as specified g_metadata_configs[i].ptzstatus = 0; g_metadata_configs[i].ptzposition = 0; } } 这些设置需要给g_metadata_config加锁
最新发布
11-06
#E:\AI_System\core\config.py import os # 必须添加此导入 import json import logging import configparser from pathlib import Path from typing import Dict, Any, Optional, Union from dotenv import load_dotenv class CoreConfig: """ 核心配置管理类 - 提供统一的配置管理接口 支持多来源配置加载:环境变量 > 配置文件 > 默认值 """ def __init__(self, config_path: Optional[Union[str, Path]] = None, env_prefix: str = "APP_", default_config: Optional[Dict[str, Any]] = None): """ 初始化配置管理器 :param config_path: 配置文件路径(支持.json, .ini, .env) :param env_prefix: 环境变量前缀 :param default_config: 默认配置字典 """ # 初始化日志 self.logger = logging.getLogger('CoreConfig') self._setup_logger() # 设置实例变量 self.env_prefix = env_prefix self.config_path = Path(config_path) if config_path else None self.config_data = default_config or {} self.config_modified = False self.log(f"📋 初始化配置管理器 | 环境前缀: {env_prefix}") # 加载配置 self.load_configuration() def _setup_logger(self): """配置日志记录器""" if not self.logger.handlers: handler = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) self.logger.addHandler(handler) self.logger.setLevel(logging.INFO) self.logger.propagate = False def log(self, message: str, level: str = "info"): """记录日志""" log_levels = { "debug": self.logger.debug, "info": self.logger.info, "warning": self.logger.warning, "error": self.logger.error } log_func = log_levels.get(level.lower(), self.logger.info) log_func(message) def load_configuration(self): """加载所有配置源""" # 1. 加载环境变量 self._load_environment_vars() # 2. 加载配置文件(如果存在) if self.config_path and self.config_path.exists(): self._load_config_file() elif self.config_path: self.log(f"⚠️ 配置文件不存在: {self.config_path}", "warning") self.log(f"✅ 配置加载完成 | 条目数: {len(self.config_data)}") def _load_environment_vars(self): """加载环境变量""" self.log("🔍 加载环境变量...") load_dotenv() # 加载.env文件(如果存在) # 获取所有以指定前缀开头的环境变量 for key, value in os.environ.items(): if key.startswith(self.env_prefix): config_key = key[len(self.env_prefix):].lower() self.config_data[config_key] = self._parse_value(value) self.log(f" - 加载环境变量: {config_key} = {self._mask_secret(config_key, value)}") def _load_config_file(self): """根据文件扩展名加载配置文件""" suffix = self.config_path.suffix.lower() self.log(f"📄 加载配置文件: {self.config_path} (类型: {suffix[1:]})") try: if suffix == '.json': self._load_json_config() elif suffix in ('.ini', '.cfg'): self._load_ini_config() elif suffix == '.env': self._load_dotenv_config() else: self.log(f"❌ 不支持的配置文件类型: {suffix}", "error") except Exception as e: self.log(f"❌ 配置文件加载失败: {str(e)}", "error") def _load_json_config(self): """加载JSON配置文件""" with open(self.config_path, 'r', encoding='utf-8') as f: json_data = json.load(f) self._merge_config(json_data) def _load_ini_config(self): """加载INI配置文件""" parser = configparser.ConfigParser() parser.read(self.config_path) config_dict = {} for section in parser.sections(): section_dict = {} for key, value in parser.items(section): section_dict[key] = self._parse_value(value) config_dict[section] = section_dict self._merge_config(config_dict) def _load_dotenv_config(self): """加载.env配置文件""" # 已由load_dotenv()处理,这里只需记录 self.log(" - .env文件已加载") def _merge_config(self, new_config: Dict[str, Any]): """合并新配置到现有配置""" for key, value in new_config.items(): # 处理嵌套配置 if isinstance(value, dict) and key in self.config_data and isinstance(self.config_data[key], dict): self.config_data[key].update(value) else: self.config_data[key] = value self.log(f" - 加载配置项: {key} = {self._mask_secret(key, value)}") def _parse_value(self, value: str) -> Any: """智能解析字符串值为合适的Python类型""" # 尝试解析为布尔值 if value.lower() in ('true', 'yes', 'on'): return True if value.lower() in ('false', 'no', 'off'): return False # 尝试解析为数字 try: return int(value) except ValueError: try: return float(value) except ValueError: pass # 尝试解析为列表(仅当明确使用逗号分隔时) if isinstance(value, str) and ',' in value and ' ' not in value.strip(): return [self._parse_value(item.strip()) for item in value.split(',')] # 返回原始字符串 return value def _mask_secret(self, key: str, value: Any) -> str: """对敏感信息进行掩码处理""" if 'secret' in key or 'password' in key or 'key' in key or 'token' in key: return '******' if value else '空' if isinstance(value, list): return f"[列表, 长度: {len(value)}]" if isinstance(value, dict): return f"{{字典, 键数: {len(value)}}}" return str(value) def get(self, key: str, default: Any = None) -> Any: """ 获取配置值,支持点分路径 (如: 'database.host') :param key: 配置键名 :param default: 默认值(如果键不存在) :return: 配置值 """ keys = key.split('.') current = self.config_data for k in keys: if isinstance(current, dict) and k in current: current = current[k] else: return default return current def set(self, key: str, value: Any, persist: bool = False): """ 设置配置值 :param key: 配置键名 :param value: 配置值 :param persist: 是否持久化到配置文件 """ keys = key.split('.') current = self.config_data # 遍历创建嵌套字典 for i, k in enumerate(keys[:-1]): if k not in current or not isinstance(current[k], dict): current[k] = {} current = current[k] # 设置最终值 last_key = keys[-1] current[last_key] = value self.config_modified = True self.log(f"⚙️ 设置配置: {key} = {self._mask_secret(last_key, value)}") # 持久化到文件 if persist and self.config_path: self.save_config() def save_config(self, path: Optional[Union[str, Path]] = None): """ 保存配置到文件 :param path: 可选的自定义保存路径 """ save_path = Path(path) if path else self.config_path if not save_path: self.log("❌ 保存失败: 未指定配置文件路径", "error") return False suffix = save_path.suffix.lower() try: if suffix == '.json': with open(save_path, 'w', encoding='utf-8') as f: json.dump(self.config_data, f, indent=2, ensure_ascii=False) elif suffix in ('.ini', '.cfg'): self._save_ini_config(save_path) else: self.log(f"❌ 不支持的文件格式: {suffix}", "error") return False self.log(f"💾 配置已保存到: {save_path}") self.config_modified = False return True except Exception as e: self.log(f"❌ 配置保存失败: {str(e)}", "error") return False def _save_ini_config(self, path: Path): """保存为INI格式配置文件""" parser = configparser.ConfigParser() # 递归处理嵌套字典 def add_section(data, section_name=None): if section_name: parser.add_section(section_name) for key, value in data.items(): if isinstance(value, dict): add_section(value, f"{section_name}.{key}" if section_name else key) else: if not section_name: parser.set('DEFAULT', key, str(value)) else: parser.set(section_name, key, str(value)) add_section(self.config_data) with open(path, 'w', encoding='utf-8') as f: parser.write(f) def reload(self): """重新加载所有配置源""" self.log("🔄 重新加载配置...") self.config_data = {} self.load_configuration() def to_dict(self) -> Dict[str, Any]: """返回当前配置的完整字典""" return self.config_data.copy() def __getitem__(self, key: str) -> Any: """支持字典式访问""" return self.get(key) def __setitem__(self, key: str, value: Any): """支持字典式设置""" self.set(key, value) def __contains__(self, key: str) -> bool: """检查配置项是否存在""" return self.get(key) is not None # 创建全局系统配置实例 system_config = CoreConfig( config_path=Path(__file__).parent.parent / "config" / "system_config.json", env_prefix="AI_SYSTEM_" ) # 仅在直接运行时执行测试 if __name__ == "__main__": run_config_tests() def run_config_tests(): """运行配置管理器测试""" # 设置测试日志 logging.basicConfig( level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) print("=" * 50) print("核心配置管理器测试") print("=" * 50) # 创建临时配置文件 config_json = """ { "database": { "host": "localhost", "port": 5432, "username": "admin", "password": "db_secret" }, "logging": { "level": "INFO", "path": "/var/log/app.log" }, "features": ["auth", "caching", "analytics"] } """ test_config_path = "test_config.json" with open(test_config_path, "w") as f: f.write(config_json) try: # 设置环境变量 os.environ["APP_API_KEY"] = "env_secret_key" os.environ["APP_DATABASE_PORT"] = "6432" # 覆盖配置文件中的端口 # 创建配置管理器实例 config = CoreConfig( config_path=test_config_path, env_prefix="APP_", default_config={ "app_name": "MyApp", "version": "1.0.0" } ) # 测试配置获取 print("\n测试配置获取:") print(f"数据库主机: {config.get('database.host')}") print(f"数据库端口: {config.get('database.port')} (应被环境变量覆盖)") print(f"API密钥: {config.get('api_key')} (来自环境变量)") print(f"应用名称: {config.get('app_name')} (来自默认配置)") print(f"日志级别: {config.get('logging.level')}") print(f"功能列表: {config.get('features')}") # 测试配置设置 print("\n测试配置设置:") config.set("new_feature.enabled", True) config.set("database.password", "new_secret", persist=True) print(f"新功能状态: {config.get('new_feature.enabled')}") # 测试配置保存 print("\n测试配置保存:") config.save_config("test_config_saved.json") # 测试配置包含检查 print("\n测试配置包含检查:") print(f"数据库用户名存在: {'database.username' in config}") print(f"不存在的键: {'nonexistent.key' in config}") # 测试配置转字典 print("\n完整配置字典:") print(json.dumps(config.to_dict(), indent=2, ensure_ascii=False)) finally: # 清理临时文件 if os.path.exists(test_config_path): os.remove(test_config_path) if os.path.exists("test_config_saved.json"): os.remove("test_config_saved.json") 改成#E:\AI_System\core\config.py import os # 必须添加此导入 import json import logging import configparser from pathlib import Path from typing import Dict, Any, Optional, Union from dotenv import load_dotenv class CoreConfig: """ 核心配置管理类 - 提供统一的配置管理接口 支持多来源配置加载:环境变量 > 配置文件 > 默认值 """ def __init__(self, config_path: Optional[Union[str, Path]] = None, env_prefix: str = "APP_", default_config: Optional[Dict[str, Any]] = None): """ 初始化配置管理器 :param config_path: 配置文件路径(支持.json, .ini, .env) :param env_prefix: 环境变量前缀 :param default_config: 默认配置字典 """ # 初始化日志 self.logger = logging.getLogger('CoreConfig') self._setup_logger() # 设置实例变量 self.env_prefix = env_prefix self.config_path = Path(config_path) if config_path else None self.config_data = default_config or {} self.config_modified = False self.log(f"📋 初始化配置管理器 | 环境前缀: {env_prefix}") # 加载配置 self.load_configuration() def _setup_logger(self): """配置日志记录器""" if not self.logger.handlers: handler = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) self.logger.addHandler(handler) self.logger.setLevel(logging.INFO) self.logger.propagate = False def log(self, message: str, level: str = "info"): """记录日志""" log_levels = { "debug": self.logger.debug, "info": self.logger.info, "warning": self.logger.warning, "error": self.logger.error } log_func = log_levels.get(level.lower(), self.logger.info) log_func(message) def load_configuration(self): """加载所有配置源""" # 1. 加载环境变量 self._load_environment_vars() # 2. 加载配置文件(如果存在) if self.config_path and self.config_path.exists(): self._load_config_file() elif self.config_path: self.log(f"⚠️ 配置文件不存在: {self.config_path}", "warning") self.log(f"✅ 配置加载完成 | 条目数: {len(self.config_data)}") def _load_environment_vars(self): """加载环境变量""" self.log("🔍 加载环境变量...") load_dotenv() # 加载.env文件(如果存在) # 获取所有以指定前缀开头的环境变量 for key, value in os.environ.items(): if key.startswith(self.env_prefix): config_key = key[len(self.env_prefix):].lower() self.config_data[config_key] = self._parse_value(value) self.log(f" - 加载环境变量: {config_key} = {self._mask_secret(config_key, value)}") def _load_config_file(self): """根据文件扩展名加载配置文件""" suffix = self.config_path.suffix.lower() self.log(f"📄 加载配置文件: {self.config_path} (类型: {suffix[1:]})") try: if suffix == '.json': self._load_json_config() elif suffix in ('.ini', '.cfg'): self._load_ini_config() elif suffix == '.env': self._load_dotenv_config() else: self.log(f"❌ 不支持的配置文件类型: {suffix}", "error") except Exception as e: self.log(f"❌ 配置文件加载失败: {str(e)}", "error") def _load_json_config(self): """加载JSON配置文件""" with open(self.config_path, 'r', encoding='utf-8') as f: json_data = json.load(f) self._merge_config(json_data) def _load_ini_config(self): """加载INI配置文件""" parser = configparser.ConfigParser() parser.read(self.config_path) config_dict = {} for section in parser.sections(): section_dict = {} for key, value in parser.items(section): section_dict[key] = self._parse_value(value) config_dict[section] = section_dict self._merge_config(config_dict) def _load_dotenv_config(self): """加载.env配置文件""" # 已由load_dotenv()处理,这里只需记录 self.log(" - .env文件已加载") def _merge_config(self, new_config: Dict[str, Any]): """合并新配置到现有配置""" for key, value in new_config.items(): # 处理嵌套配置 if isinstance(value, dict) and key in self.config_data and isinstance(self.config_data[key], dict): self.config_data[key].update(value) else: self.config_data[key] = value self.log(f" - 加载配置项: {key} = {self._mask_secret(key, value)}") def _parse_value(self, value: str) -> Any: """智能解析字符串值为合适的Python类型""" # 尝试解析为布尔值 if value.lower() in ('true', 'yes', 'on'): return True if value.lower() in ('false', 'no', 'off'): return False # 尝试解析为数字 try: return int(value) except ValueError: try: return float(value) except ValueError: pass # 尝试解析为列表(仅当明确使用逗号分隔时) if isinstance(value, str) and ',' in value and ' ' not in value.strip(): return [self._parse_value(item.strip()) for item in value.split(',')] # 返回原始字符串 return value def _mask_secret(self, key: str, value: Any) -> str: """对敏感信息进行掩码处理""" if 'secret' in key or 'password' in key or 'key' in key or 'token' in key: return '******' if value else '空' if isinstance(value, list): return f"[列表, 长度: {len(value)}]" if isinstance(value, dict): return f"{{字典, 键数: {len(value)}}}" return str(value) def get(self, key: str, default: Any = None) -> Any: """ 获取配置值,支持点分路径 (如: 'database.host') :param key: 配置键名 :param default: 默认值(如果键不存在) :return: 配置值 """ keys = key.split('.') current = self.config_data for k in keys: if isinstance(current, dict) and k in current: current = current[k] else: return default return current def set(self, key: str, value: Any, persist: bool = False): """ 设置配置值 :param key: 配置键名 :param value: 配置值 :param persist: 是否持久化到配置文件 """ keys = key.split('.') current = self.config_data # 遍历创建嵌套字典 for i, k in enumerate(keys[:-1]): if k not in current or not isinstance(current[k], dict): current[k] = {} current = current[k] # 设置最终值 last_key = keys[-1] current[last_key] = value self.config_modified = True self.log(f"⚙️ 设置配置: {key} = {self._mask_secret(last_key, value)}") # 持久化到文件 if persist and self.config_path: self.save_config() def save_config(self, path: Optional[Union[str, Path]] = None): """ 保存配置到文件 :param path: 可选的自定义保存路径 """ save_path = Path(path) if path else self.config_path if not save_path: self.log("❌ 保存失败: 未指定配置文件路径", "error") return False suffix = save_path.suffix.lower() try: if suffix == '.json': with open(save_path, 'w', encoding='utf-8') as f: json.dump(self.config_data, f, indent=2, ensure_ascii=False) elif suffix in ('.ini', '.cfg'): self._save_ini_config(save_path) else: self.log(f"❌ 不支持的文件格式: {suffix}", "error") return False self.log(f"💾 配置已保存到: {save_path}") self.config_modified = False return True except Exception as e: self.log(f"❌ 配置保存失败: {str(e)}", "error") return False def _save_ini_config(self, path: Path): """保存为INI格式配置文件""" parser = configparser.ConfigParser() # 递归处理嵌套字典 def add_section(data, section_name=None): if section_name: parser.add_section(section_name) for key, value in data.items(): if isinstance(value, dict): add_section(value, f"{section_name}.{key}" if section_name else key) else: if not section_name: parser.set('DEFAULT', key, str(value)) else: parser.set(section_name, key, str(value)) add_section(self.config_data) with open(path, 'w', encoding='utf-8') as f: parser.write(f) def reload(self): """重新加载所有配置源""" self.log("🔄 重新加载配置...") self.config_data = {} self.load_configuration() def to_dict(self) -> Dict[str, Any]: """返回当前配置的完整字典""" return self.config_data.copy() def __getitem__(self, key: str) -> Any: """支持字典式访问""" return self.get(key) def __setitem__(self, key: str, value: Any): """支持字典式设置""" self.set(key, value) def __contains__(self, key: str) -> bool: """检查配置项是否存在""" return self.get(key) is not None # 创建全局系统配置实例 system_config = CoreConfig( config_path=Path(__file__).parent.parent / "config" / "system_config.json", env_prefix="AI_SYSTEM_" ) # 仅在直接运行时执行测试 if __name__ == "__main__": run_config_tests() def run_config_tests(): """运行配置管理器测试""" # 设置测试日志 logging.basicConfig( level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) print("=" * 50) print("核心配置管理器测试") print("=" * 50) # 创建临时配置文件 config_json = """ { "database": { "host": "localhost", "port": 5432, "username": "admin", "password": "db_secret" }, "logging": { "level": "INFO", "path": "/var/log/app.log" }, "features": ["auth", "caching", "analytics"] } """ test_config_path = "test_config.json" with open(test_config_path, "w") as f: f.write(config_json) try: # 设置环境变量 os.environ["APP_API_KEY"] = "env_secret_key" os.environ["APP_DATABASE_PORT"] = "6432" # 覆盖配置文件中的端口 # 创建配置管理器实例 config = CoreConfig( config_path=test_config_path, env_prefix="APP_", default_config={ "app_name": "MyApp", "version": "1.0.0" } ) # 测试配置获取 print("\n测试配置获取:") print(f"数据库主机: {config.get('database.host')}") print(f"数据库端口: {config.get('database.port')} (应被环境变量覆盖)") print(f"API密钥: {config.get('api_key')} (来自环境变量)") print(f"应用名称: {config.get('app_name')} (来自默认配置)") print(f"日志级别: {config.get('logging.level')}") print(f"功能列表: {config.get('features')}") # 测试配置设置 print("\n测试配置设置:") config.set("new_feature.enabled", True) config.set("database.password", "new_secret", persist=True) print(f"新功能状态: {config.get('new_feature.enabled')}") # 测试配置保存 print("\n测试配置保存:") config.save_config("test_config_saved.json") # 测试配置包含检查 print("\n测试配置包含检查:") print(f"数据库用户名存在: {'database.username' in config}") print(f"不存在的键: {'nonexistent.key' in config}") # 测试配置转字典 print("\n完整配置字典:") print(json.dumps(config.to_dict(), indent=2, ensure_ascii=False)) finally: # 清理临时文件 if os.path.exists(test_config_path): os.remove(test_config_path) if os.path.exists("test_config_saved.json"): os.remove("test_config_saved.json") 吗
08-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值