[源码阅读]——Sylar服务器框架:配置模块

[源码阅读]——Sylar服务器框架:配置模块,第1张

[源码阅读]——Sylar服务器框架:配置模块

配置模块
  • 配置模块概述
  • 配置模块相关类
  • YAML配置文件
  • 类型转换的偏特化
  • 配置模块与日志模块的整合
  • 还需进一步理解问题

配置模块概述

  在sylar的配置模块设计中,采用约定优于配置的思想,其常规使用方法如下:

sylar::ConfigVar::ptr g_int_value_config =
    sylar::Config::Lookup("system.port", (int)8080, "system port");
// 定义了system.port未int类型的8090,可通过g_int_value_config->getValue()获得当前参数值

  其中“约定优于配置”,也称作按约定编程,是一种软件设计范式,旨在减少软件开发人员需做决定的数量,获得简单的好处,而又不失灵活性。
  本质是说,开发人员仅需规定应用中不符约定的部分。例如,如果模型中有个名为Sale的类,那么数据库中对应的表就会默认命名为sales。只有在偏离这一约定时,例如将该表命名为"products_sold",才需写有关这个名字的配置。


配置模块相关类
 * @brief 配置变量的基类

class ConfigVarbase {};


template
class LexicalCast {};


template
                ,class ToStr = LexicalCast >
class ConfigVar : public ConfigVarbase {};


class Config {};
  • ConfigVarbase:配置变量的基类,其主要是虚方法,定义了配置项中共有的成员和方法,其具体实验由基类的具体子类负责实现。其中重点是toString()方法和fromString()方法,其分别负责将配置信息转化字符串和从字符串中解析出配置。
  • ConfigVar:配置参数模板子类,并且是模板类,其具有三个模板参数,分别是配置项类型模板T、仿函数FromStr和仿函数Tostr。ConfigVar类在ConfigVarbase的基础上,增加了AddListener方法和delListener等方法,用于增删配置变更回调函数。
  • Config:ConfigVar的管理类,其提供便捷的方法创建、访问ConfigVar,其主要方法未Lookup方法,可根据配置的名称查询配置项,如果查询时未找到对应的配置则新建一个配置项。其还有从配置文件中读取配置、遍历所有配置项等方法。其中,Config中的方法都是static方法,确保全局只有一个实例。

YAML配置文件

  YAML是一种简洁的非标记语言。YAML以数据为中心,使用空白,缩进,分行组织数据,从而使得表示更加简洁易读。其实例如下:

# yaml测试样例
# null 或 NULL 为关键字,不能写

# 名称
# 字符串
name: conf file

# 版本
# 如按浮点,2.0会转换成2
# 如按字符串,保留原样
version: 2.0

# 布尔类,转换为1或0
need: true

# 时间
time: 2020-10-03T09:21:13

empty: nul

# 对象
# 加双引号会转义n,即会换行
my:
  name: late n lee
  name1: "late n lee"
  age: 99
  
# 块
text: |
  hello
  world!

# 数组
fruit:
  - apple
  - apple1
  - apple2
  - apple3
  - apple4
  - apple5

# 多级数组
multi:
  sta:
    - 110 210 ddd 99
    - 133 135 1 2 1588 1509
    - 310-410
    - 333-444

  在C++中,可使用YAML-CPP开源库进行YAML文件的读写,其配置可自行百度。其中,在windows平台使用VScode配置Yaml-cpp可参考本人之前做的一个记录:Windows平台使用VSCode配置Yaml-cpp,相关测试可在上文中也有。


类型转换的偏特化

  在sylar的配置模块中,后续需要基于自己需求添加的便是对类型转换函数的偏特化实现,其实现了基本类型和Yaml字符串的相互转换。C++中的偏特化介于主版本模板和模板全特化之间,其只明确定义了部分类型,而非将模板唯一化,注意函数模板不能被偏特化。


配置模块与日志模块的整合
sylar::ConfigVar >::ptr g_log_defines =
    sylar::Config::Lookup("logs", std::set(), "logs config");

//定义LogDefine LogAppenderDefine, 偏特化 LexicalCast,
//实现日志配置解析
struct LogIniter {
    LogIniter() {
        g_log_defines->addListener([](const std::set& old_value,
                    const std::set& new_value){
            SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "on_logger_conf_changed";
            for(auto& i : new_value) {
                auto it = old_value.find(i);
                sylar::Logger::ptr logger;
                if(it == old_value.end()) {
                    //新增logger
                    logger = SYLAR_LOG_NAME(i.name);
                } else {
                    if(!(i == *it)) {
                        //修改的logger
                        logger = SYLAR_LOG_NAME(i.name);
                    } else {
                        continue;
                    }
                }
                logger->setLevel(i.level);
                //std::cout << "** " << i.name << " level=" << i.level
                //<< "  " << logger << std::endl;
                if(!i.formatter.empty()) {
                    logger->setFormatter(i.formatter);
                }

                logger->clearAppenders();
                for(auto& a : i.appenders) {
                    sylar::LogAppender::ptr ap;
                    if(a.type == 1) {
                        ap.reset(new FileLogAppender(a.file));
                    } 
                    else if(a.type == 2) {
                        ap.reset(new StdoutLogAppender);
                    }
                    ap->setLevel(a.level);
                    if(!a.formatter.empty()) {
                        LogFormatter::ptr fmt(new LogFormatter(a.formatter));
                        if(!fmt->isError()) {
                            ap->setFormatter(fmt);
                        } else {
                            std::cout << "log.name=" << i.name << " appender type=" << a.type
                                      << " formatter=" << a.formatter << " is invalid" << std::endl;
                        }
                    }
                    logger->addAppender(ap);
                }
            }

            for(auto& i : old_value) {
                auto it = new_value.find(i);
                if(it == new_value.end()) {
                    //删除logger
                    auto logger = SYLAR_LOG_NAME(i.name);
                    logger->setLevel((LogLevel::Level)0);
                    logger->clearAppenders();
                }
            }
        });
    }
};

// 定义一个LogIniter类,实例化未全局对象。
static LogIniter __log_init;
logs:
    - name: root
      level: (debug,info,warn,error,fatal)
      formatter: '%d%T%p%T%t%m%n'
      appender:
        - type: (StdoutLogAppender, FileLogAppender)
          level:(debug,...)
          file: /logs/xxx.log
    sylar::Logger g_logger = sylar::LoggerMgr::GetInstance()->getLogger(name);
    SYLAR_LOG_INFO(g_logger) << "xxxx log";
void test_log() {
    static sylar::Logger::ptr system_log = SYLAR_LOG_NAME("system");
    SYLAR_LOG_INFO(system_log) << "hello system" << std::endl;
    std::cout << sylar::LoggerMgr::GetInstance()->toYamlString() << std::endl;
    YAML::Node root = YAML::LoadFile("/home/sylar/workspace/sylar/bin/conf/log.yml");
    sylar::Config::LoadFromYaml(root);
    std::cout << "=============" << std::endl;
    std::cout << sylar::LoggerMgr::GetInstance()->toYamlString() << std::endl;
    std::cout << "=============" << std::endl;
    std::cout << root << std::endl;
    SYLAR_LOG_INFO(system_log) << "hello system" << std::endl;

    system_log->setFormatter("%d - %m%n");
    SYLAR_LOG_INFO(system_log) << "hello system" << std::endl;
}

还需进一步理解问题
  • 对于配置模块其实我本人感觉代码量并不是很多,也不是很难理解,但主要是不太清楚其具体用途,虽然在后续的模块中有用到,但如何在系统初始化时加载默认配置、配置文件修改完后如何统一初始化系列参数等问题还是让我有些懵,可能是没怎么接触过这种系统性的东西吧有大佬理解的话也可以讲解一下谢谢啦~
  • 关于日志模块与配置模块的整合,其实在这两个模块整合中,我感觉还是有点没理清楚思路,看了一下测试,其应该是通过LoadFromYaml读取配置文件内容,随后将其为日志系统配置name、level、appenders等,这里后续还会通过调试一步一步看一下是什么样的流程。
  • 关于配置模块我主要是以阅读为主,并没有试图修改内容,这里主要是读取yaml配置文件,后续也努力尝试改为其他文件进行读取等,但是本人能力可能还不太够,还需要多学习~

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5580572.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存