栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【C++模块实现】| 【05】日志模块增加配置模块的功能

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【C++模块实现】| 【05】日志模块增加配置模块的功能

文章目录
    • 1、代码实现
        • 1.1 自定义结构转换
        • 1.2 添加监听函数
    • 2、测试

1、代码实现
结合配置的功能让日志系统更加便捷;
- 提供IsChange用于检测日志的配置文件是否被修改,若修改了,则在LoggerMrg的析构中会将其同步到配置文件中;
- 提供g_filename,在检测到加载日志的时候即将配置文件名进行记录,便于后期使用;
- 设置LogAppenderDefine结构体,加载配置文件中的LogAppender配置项;
	- type:1为文件,2为控制台;
	- level:日志级别;
	- formatter:输出格式;
	- file:日志输出文件;
	- file_num:日志写满时,转移到下一个输出文件名的序号;
	- backups_files:日志文件备份;
	- file_buf:限制文件大小;
- 设置LogDefine结构体,加载配置文件中的logs配置项;
	- name:日志器的名称;
	- level:日志级别;
	- formatter:日志格式;
	- appenders:日志输出地;
static bool IsChange = false;

static std::string g_filename = "";


struct LogAppenderDefine {
    int type = 0;           //1 File, 2 Stdout
    LogLevel::Level level = LogLevel::UNKNOW;
    std::string formatter;
    std::string file;
    uint16_t file_num = 0;
    uint16_t backups_files = 0;
    uint16_t backups_days = 0;
    uint64_t file_buf = 0;


    bool operator==(const LogAppenderDefine& oth) const {
        return type == oth.type
               && level == oth.level
               && formatter == oth.formatter
               && file == oth.file
               && backups_days == oth.backups_days
               && backups_files == oth.backups_files
               && file_buf == oth.file_buf
               && file_num == oth.file_num;
    }
};

struct LogDefine {
    std::string name;
    LogLevel::Level level = LogLevel::UNKNOW;
    std::string formatter;
    std::vector appenders;

    bool operator==(const LogDefine& oth) const {
        return name == oth.name
               && level == oth.level
               && formatter == oth.formatter
               && appenders == appenders;
    }

    bool operator<(const LogDefine& oth) const {
        return name < oth.name;
    }

    bool isValid() const {
        return !name.empty();
    }
};
1.1 自定义结构转换
确保在加载yaml文件时能够进行转换,对该类型进行特化;
template<>
class LexicalCast {
public:
    LogDefine operator()(const std::string& v) {
        YAML::Node n = YAML::Load(v);
        LogDefine ld;
        if(!n["name"].IsDefined()) {
            std::cout << "log config error: name is null, " << n
                      << std::endl;
            throw std::logic_error("log config name is null");
        }
        ld.name = n["name"].as();
        ld.level = LogLevel::FromString(n["level"].IsDefined() ? n["level"].as() : "");
        if(n["formatter"].IsDefined()) {
            ld.formatter = n["formatter"].as();
        }

        if(n["appenders"].IsDefined()) {
            for(size_t x = 0; x < n["appenders"].size(); ++x) {
                auto a = n["appenders"][x];
                if(!a["type"].IsDefined()) {
                    std::cout << "log config error: appender type is null, " << a
                              << std::endl;
                    continue;
                }
                std::string type = a["type"].as();
                LogAppenderDefine lad;
                if(type == "FileLogAppender") {
                    lad.type = 1;
                    if(!a["file"].IsDefined()) {
                        std::cout << "log config error: fileappender file is null, " << a
                                  << std::endl;
                        continue;
                    }
                    lad.file = a["file"].as();
                    if(a["formatter"].IsDefined()) {
                        lad.formatter = a["formatter"].as();
                    }
                    if(a["backups_files"].IsDefined()) {
                        lad.backups_files = a["backups_files"].as();
                    }
                    if(a["backups_days"].IsDefined()) {
                        lad.backups_days = a["backups_days"].as();
                    }
                    if(a["file_buf"].IsDefined()) {
                        lad.file_buf = a["file_buf"].as();
                    }
                    if(a["file_num"].IsDefined()) {
                        lad.file_num = a["file_num"].as();
                    }
                } else if(type == "StdoutLogAppender") {
                    lad.type = 2;
                    if(a["formatter"].IsDefined()) {
                        lad.formatter = a["formatter"].as();
                    }
                } else {
                    std::cout << "log config error: appender type is invalid, " << a
                              << std::endl;
                    continue;
                }

                ld.appenders.push_back(lad);
            }
        }
        return ld;
    }
};

template<>
class LexicalCast {
public:
    std::string operator()(const LogDefine& i) {
        YAML::Node n;
        n["name"] = i.name;
        if(i.level != LogLevel::UNKNOW) {
            n["level"] = LogLevel::ToString(i.level);
        }
        if(!i.formatter.empty()) {
            n["formatter"] = i.formatter;
        }

        for(auto& a : i.appenders) {
            YAML::Node na;
            if(a.type == 1) {
                na["type"] = "FileLogAppender";
                na["file"] = a.file;
                na["backups_days"] = a.backups_days;
                na["backups_files"] = a.backups_files;
                na["file_buf"] = a.file_buf;
                na["file_num"] = a.file_num;
            } else if(a.type == 2) {
                na["type"] = "StdoutLogAppender";
            }
            if(a.level != LogLevel::UNKNOW) {
                na["level"] = LogLevel::ToString(a.level);
            }
            if(!a.formatter.empty()) {
                na["formatter"] = a.formatter;
            }
            n["appenders"].push_back(na);
        }
        std::stringstream ss;
        ss << n;
        return ss.str();
    }
};
1.2 添加监听函数
使用Config中的Lookup获取logs配置,并且在结构体的构造函数中调用addListener函数,添加配置变更函数;
并在全局中调用,让其执行期早于main函数前加载配置;
sylar::ConfigVar>::ptr g_log_defines =
        sylar::Config::Lookup("logs", std::set(), "logs config");

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";
            g_filename = sylar::Config::GetFileName();
            
            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);
                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, a.file_num, a.backups_files, a.backups_days, a.file_buf));
                    } 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();
                }
            }
        });
    }
};

// 全局 在main函数之前会调用LogIniter()
static LogIniter __log_init;
2、测试

int main(int argc, char** argv) {
    std::cout << sylar::LoggerMgr::GetInstance()->toYamlString() << std::endl;
    sylar::Config::LoadFromYaml("/root/code/log_server/bin/conf/log.yml");
    std::cout << "load: " << std::endl;
    std::cout << sylar::LoggerMgr::GetInstance()->toYamlString() << std::endl;

    return 0;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1029568.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号