跳转至

Lessweb 配置系统

Lessweb 框架提供了一个强大而灵活的配置系统,支持 TOML 格式的配置文件、多环境配置、环境变量覆盖以及模块化配置管理。

配置系统概述

Lessweb 的配置系统具有以下特性:

  • TOML 格式:使用易读易写的 TOML 格式
  • 多环境支持:支持基于环境的配置文件自动加载
  • 环境变量覆盖:支持通过环境变量覆盖配置文件中的值
  • 模块化配置:支持为不同模块定义独立的配置结构
  • Pydantic 验证:使用 Pydantic 进行配置验证和类型检查

配置文件组织

基本用法

在创建 Bridge 实例时,可以指定配置文件或配置目录:

from lessweb import Bridge

# 使用配置目录
bridge = Bridge('config')

# 使用单个配置文件
bridge = Bridge('config.toml')

配置目录结构

当使用配置目录时,Lessweb 会自动加载目录中的所有 .toml 文件:

config/
├── lessweb.toml      # 框架核心配置
├── mysql.toml        # MySQL 配置
├── redis.toml        # Redis 基础配置
├── redis.production.toml  # Redis 生产环境配置
└── other.toml        # 其他模块配置

多环境配置

Lessweb 支持基于 ENV 环境变量的多环境配置:

  1. 设置环境变量:export ENV=production
  2. 创建对应环境的配置文件:redis.production.toml
  3. 框架会优先加载环境特定的配置文件
# 开发环境
export ENV=staging

# 生产环境
export ENV=production

# 测试环境
export ENV=test

环境变量覆盖

配置系统支持通过环境变量覆盖配置文件中的任何值。环境变量名规则:

  • 使用配置路径的大写形式
  • 用下划线连接层级

示例:

# config.toml
[lessweb]
port = 8080

[lessweb.logger]
level = 'INFO'

[mysql]
host = 'localhost'
port = 3306

对应的环境变量:

export LESSWEB_PORT=9000
export LESSWEB_LOGGER_LEVEL=DEBUG
export MYSQL_HOST=production-db.example.com
export MYSQL_PORT=3307

Lessweb 框架配置

核心配置项

在配置文件中,使用 [lessweb] 节定义框架核心配置:

[lessweb]
port = 80                           # 服务器端口(默认为8080)
enable_global_error_handling = false  # 是否启用全局错误处理(默认为true)
orjson_option = 'SORT_KEYS,STRICT_INTEGER,UTC_Z,...'                   # orjson 序列化选项

配置项说明

配置项 类型 默认值 说明
port int 8080 HTTP 服务器监听端口
enable_global_error_handling bool true 是否启用全局错误处理中间件
orjson_option str '' orjson 库的序列化选项配置

日志配置

[lessweb.logger] 节中配置日志系统:

[lessweb.logger]
format = '%(asctime)s %(name)s %(filename)s:%(lineno)d %(levelname)s - %(message)s'
level = 'INFO'                    # 日志级别:DEBUG, INFO, WARNING, ERROR
stream = 'stdout'                 # 输出目标:stdout, stderr, file
name = 'my-app'                   # 指定日志器名称
file = 'logs/myapp.log'            # 日志文件路径(stream=file时使用)

# 日志轮转配置(可选)
[lessweb.logger.rotating]
when = 'd'                        # 轮转时机:d(天), h(小时), m(分钟)
interval = 1                      # 轮转间隔
backup_count = 30                 # 保留备份数量
suffix = "%Y%m%d"                # 备份文件名后缀格式

日志配置项说明

配置项 类型 默认值 说明
format str '%(asctime)s %(name)s %(filename)s:%(lineno)d %(levelname)s - %(message)s' 日志格式字符串
level str 'INFO' 日志级别,可选:DEBUG, INFO, WARNING, ERROR
stream str 'stdout' 输出目标,可选:stdout, stderr, file
name str None 指定的日志器名称(可选)
file str None 日志文件路径,当 stream='file' 时必需

日志轮转配置:

配置项 类型 默认值 说明
when str 'd' 轮转时机:'d'(天), 'h'(小时), 'm'(分钟)
interval int 1 轮转间隔数
backup_count int 30 保留的备份文件数量
suffix str "%Y%m%d" 备份文件名的时间戳后缀格式

示例配置

# lessweb.toml
[lessweb]
port = 8080
enable_global_error_handling = true

[lessweb.logger]
format = '%(asctime)s %(name)s %(filename)s:%(lineno)d %(levelname)s - %(message)s'
level = 'INFO'
stream = 'file'
name = 'my-web-app'
file = 'logs/myapp.log'

[lessweb.logger.rotating]
when = 'd'
interval = 1
backup_count = 30
suffix = "%Y%m%d"

模块配置系统

定义配置模型

使用 Pydantic 定义配置模型:

from pydantic import BaseModel

class RedisConfig(BaseModel):
    host: str
    port: int
    password: str | None = None
    db: int = 0

class MysqlConfig(BaseModel):
    host: str
    port: int = 3306
    user: str
    password: str
    db: str
    maxsize: int = 20
    autocommit: bool = True

在模块中使用配置

在 Module 子类中实现 load_config 方法:

from typing import Annotated
from lessweb import Module, load_module_config

class RedisModule(Module):
    def load_config(self, app: Application) -> Annotated[RedisConfig, 'redis']:
        return load_module_config(app, 'redis', RedisConfig)

    async def on_startup(self, app: Application) -> None:
        config = self.load_config(app)
        # 使用配置初始化 Redis 连接
        self.redis_client = redis.Redis(
            host=config.host,
            port=config.port,
            password=config.password,
            db=config.db,
            decode_responses=True,
        )

load_module_config 函数

def load_module_config(app: Application, module_config_key: str, module_config_cls: Type[T]) -> T:
    """
    加载指定模块的配置

    参数:
        app: aiohttp Application 实例
        module_config_key: 配置键名,对应 TOML 文件中的节名
        module_config_cls: Pydantic 配置模型类

    返回:
        配置模型实例
    """

完整使用示例

1. 配置文件

# config/lessweb.toml
[lessweb]
port = 8080

[lessweb.logger]
level = 'INFO'
stream = 'file'
file = 'logs/myapp.log'
# config/redis.toml
[redis]
host = '127.0.0.1'
port = 6379
db = 0
# config/redis.production.toml
[redis]
host = '127.0.0.1'
port = 6379
db = 0
password = 'password'
# config/mysql.toml
[mysql]
host = '127.0.0.1'
port = 3306
user = 'username'
password = 'password'
db = 'database'
maxsize = 20

2. 配置模型定义

# models/config.py
from pydantic import BaseModel

class RedisConfig(BaseModel):
    host: str
    port: int
    password: str | None = None
    db: int

class MysqlConfig(BaseModel):
    host: str
    port: int = 3306
    user: str
    password: str
    db: str
    maxsize: int = 20

3. 模块实现

# modules/redis_module.py
from typing import Annotated
import redis.asyncio as redis
from aiohttp.web import Application
from lessweb import Module, load_module_config
from models.config import RedisConfig

class RedisModule(Module):
    def load_config(self, app: Application) -> Annotated[RedisConfig, 'redis']:
        return load_module_config(app, 'redis', RedisConfig)

    async def on_startup(self, app: Application) -> None:
        config = self.load_config(app)
        self.redis_client = redis.Redis(
            host=config.host,
            port=config.port,
            password=config.password,
            db=config.db,
            decode_responses=True,
        )

    async def on_cleanup(self, app: Application) -> None:
        await self.redis_client.aclose()

def redis_bean(redis_module: RedisModule) -> redis.Redis:
    return redis_module.redis_client

4. 应用启动

# main.py
from lessweb import Bridge
from modules.redis_module import redis_bean

def main():
    # 使用配置目录初始化
    bridge = Bridge('config')

    # 注册 bean
    bridge.beans(redis_bean)

    # 扫描并注册路由
    bridge.scan('src')

    # 启动应用
    bridge.run_app()

if __name__ == '__main__':
    main()

5. 使用环境变量覆盖

# 设置环境和覆盖配置
export ENV=production
export REDIS_HOST=redis.production.example.com
export MYSQL_HOST=db.production.example.com
export LESSWEB_PORT=9000

python main.py

最佳实践

1. 配置文件组织

  • 将不同模块的配置分离到独立的 TOML 文件
  • 使用环境特定的配置文件管理多环境差异
  • 敏感信息(密码、密钥)通过环境变量覆盖

2. 配置模型设计

  • 使用 Pydantic 模型定义配置结构
  • 为配置项提供合理的默认值
  • 使用类型注解增强代码可读性

3. 模块配置

  • 在 Module 的 load_config 方法中加载配置
  • on_startup 中使用配置初始化资源
  • on_cleanup 中正确清理资源

4. 安全考虑

  • 不要将敏感信息提交到版本控制
  • 使用环境变量或外部密钥管理系统
  • 在生产环境中限制配置文件访问权限

通过这套配置系统,你可以轻松管理复杂应用的配置需求,同时保持代码的清晰和可维护性。