sylar learning (p1-p2)

1. Introduction

[C++ Advanced Tutorial] Develop server framework (sylar) from scratch
https://www.bilibili.com/video/BV184411s7qF/?spm_id_from=333.337.search-card.all.click&vd_source=de2dcd0f37ff916ec3f8fb83c6366123
p1-p2

2. Code and knowledge points used

2.1 header file log.h

#include <string>
// string是C++标准库中的一个头文件,它定义了用于处理字符串的类模板std::string。
// 这个类提供了许多有用的成员函数和操作符,使得字符串的操作更加方便和高效。
// 1. 创建字符串变量
// 2. 字符串操作
// 3. 字符串比较
// 4. 字符串查找和替换
#include <stdint.h>
// stdint.h是C语言标准库中的一个头文件,而在C++中对应的头文件是<cstdint>。这个头文件定义了一组固定大小的整数类型,以确保在不同平台上的整数类型的大小是一致的。
// 这些类型通常用于编写跨平台的代码,以确保整数类型的大小和范围是可预测和一致的。这些整数类型的使用可以提高代码的可移植性和可靠性,尤其是在需要精确控制整数大小和范围的情况下。
// 下面是<cstdint>头文件中定义的一些常见的整数类型:
// 1. 基本整数类型:
// int8_t:有符号8位整数
// uint8_t:无符号8位整数
// int16_t:有符号16位整数
// uint16_t:无符号16位整数
// int32_t:有符号32位整数
// uint32_t:无符号32位整数
// int64_t:有符号64位整数
// uint64_t:无符号64位整数
// 2. 小/最大值常量:
// INT8_MIN、INT16_MIN、INT32_MIN、INT64_MIN:最小有符号整数值
// INT8_MAX、INT16_MAX、INT32_MAX、INT64_MAX:最大有符号整数值
// UINT8_MAX、UINT16_MAX、UINT32_MAX、UINT64_MAX:最大无符号整数值 
// 3. 指定宽度的整数类型:
// int_least8_t、uint_least8_t:至少8位宽的有符号和无符号整数类型
// int_fast8_t、uint_fast8_t:快速的至少8位宽的有符号和无符号整数类型
#include <memory>
// memory是C++标准库中的一个头文件,它提供了用于动态内存管理和智能指针的工具和类。这个头文件定义了几个重要的类和函数,用于管理和操作内存资源,以提高内存管理的安全性和效率。
// 这些类和函数提供了方便、安全和高效的内存管理机制,减少了手动管理动态内存的风险。使用智能指针可以避免内存泄漏和野指针等常见的内存管理错误。
// 1. std::shared_ptr:共享指针
// std::shared_ptr是一个智能指针类,用于共享资源的所有权。多个shared_ptr可以指向相同的对象,它们共享对象的所有权并自动管理内存的释放。当最后一个指向对象的shared_ptr被销毁时,对象会自动被销毁。
// 2. std::unique_ptr:独占指针
// std::unique_ptr是一个智能指针类,用于管理独占的资源。它提供了对动态分配对象的独占所有权,保证只有一个unique_ptr可以指向该对象。当unique_ptr被销毁时,它所管理的对象会自动被销毁。
// 3. std::weak_ptr:弱引用指针
// std::weak_ptr是一种弱引用指针,它可以共享资源的观测权而不会增加资源的引用计数。它通常用于解决循环引用的问题,允许引用的对象被销毁。
// 4. std::make_shared:创建shared_ptr的工厂函数
// std::make_shared是一个模板函数,用于创建shared_ptr指针并初始化对象。它可以避免直接使用new操作符来创建动态分配的对象,并确保正确管理内存。
// 5. std::make_unique:创建unique_ptr的工厂函数
// std::make_unique是一个模板函数,用于创建unique_ptr指针并初始化对象。它提供了一种安全的方式来创建独占所有权的动态分配对象。
#include <list>
// list是C++标准库中的一个头文件,它定义了模板类std::list,该类实现了双向链表的数据结构。双向链表是一种动态数据结构,其中每个节点都包含一个指向前一个节点和后一个节点的指针,可以在常量时间内进行插入、删除和访问操作。
// 1. 创建和访问链表
// 2. 插入和删除元素
// 3. 获取链表大小和判断是否为空
// 4. 排序和反转链表
// 日志事件
class LogEvent {
    
    
public:
    typedef std::shared_ptr<LogEvent> ptr;
    // typedef关键字为std::shared_ptr<LogEvent>定义了一个新的类型别名ptr
    // std::shared_ptr是一个智能指针类,用于共享资源的所有权。多个shared_ptr可以指向相同的对象,它们共享对象的所有权并自动管理内存的释放。当最后一个指向对象的shared_ptr被销毁时,对象会自动被销毁。
    // 共享指针尽量不要和裸指针混用
    // https://www.bilibili.com/video/BV1Ye4y127rZ/?spm_id_from=333.337.search-card.all.click&vd_source=de2dcd0f37ff916ec3f8fb83c6366123(C++的共享指针 shared_ptr 如何帮你自动管理内存)
    // 其他几种指针以后在整理
    LogEvent();
private:
    const char* m_file = nullptr;   // 文件名

    // 一个字节是八位,使用库stdint.h给统一了
    int32_t m_line = 0;             // 行号
    // 32位(4字节)
    uint32_t m_elapse;              // 程序启动开始到现在的毫秒数
    // 32位(4字节)
    uint32_t m_threadId = 0;        // 线程id
    // 32位(4字节)
    uint32_t m_fiberId = 0;         // 协程id
    // 32位(4字节)
    uint64_t m_time;                // 时间戳
    // 64位(8字节)
    std::string m_content;
    // 使用<string>
};
// 日志级别
class LogLevel {
    
    
public:
    enum Level {
    
    
        DEBUG = 1,
        INFO = 2,
        WARN = 3,
        ERROR = 4,
        FATAL = 5
    };
};
// 日志格式器
class LogFormatter {
    
    
public:
    typedef std::shared_ptr<LogFormatter> ptr;
    std::string format(LogEvent::ptr event);
private:
};

// 日志输出地 
class LogAppender {
    
    
public:
    typedef std::shared_ptr<LogAppender> ptr;
    virtual ~LogAppender() {
    
    };

    void log(LogLevel::Level level,LogEvent::ptr event);
private:
    LogLevel::Level m_level;
};
// 日志器
class Logger{
    
    
public:
    typedef std::shared_ptr<Logger> ptr;

    Logger(const std::string& name = "root");
    void log(LogLevel::Level level,LogEvent::ptr event);

    void debug(LogEvent::ptr event);
    void info(LogEvent::ptr event);
    void warn(LogEvent::ptr event);
    void error(LogEvent::ptr event);
    void fatal(LogEvent::ptr event);

    void addAppender(LogAppender::ptr appender);
    void delAppender(LogAppender::ptr appender);

    LogLevel::Level getLevel() const {
    
    return m_level;};
    // 在只读操作中使用,不修改类的状态
    void setLevel(LogLevel::Level val) {
    
    m_level = val;};

private:
    std::string m_name;                               // 日志名称
    LogLevel::Level m_level;                          // 日志级别
    std::list<LogAppender::ptr> m_appenders;          // Appender集合
    // list 可以被认为是一个链表。它是由一系列节点组成的双向链表结构,每个节点都包含一个元素和指向前一个节点和后一个节点的指针。
};
// 输出到控制台的Appender
class StdoutLogAppender : public LogAppender {
    
    

};

2.2 header file log.cc

Logger class implementation

// 日志器
class Logger{
    
    
public:
    typedef std::shared_ptr<Logger> ptr;

    Logger(const std::string& name = "root");
    void log(LogLevel::Level level,LogEvent::ptr event);

    void debug(LogEvent::ptr event);
    void info(LogEvent::ptr event);
    void warn(LogEvent::ptr event);
    void error(LogEvent::ptr event);
    void fatal(LogEvent::ptr event);

    void addAppender(LogAppender::ptr appender);
    void delAppender(LogAppender::ptr appender);

    LogLevel::Level getLevel() const {
    
    return m_level;};
    void setLevel(LogLevel::Level val) {
    
    m_level = val;};

private:
    std::string m_name;                               // 日志名称
    LogLevel::Level m_level;                          // 日志级别
    std::list<LogAppender::ptr> m_appenders;          // Appender集合

};
Logger::Logger(const std::string& name) :m_name(name) {
    
    

};

void Logger::addAppender(LogAppender::ptr appender) {
    
    
    m_appenders.push_back(appender);
};

void Logger::delAppender(LogAppender::ptr appender) {
    
    
    for(auto it = m_appenders.begin();it != m_appenders.end();++it){
    
    
    // auto 是 C++11 引入的关键字,用于让编译器根据变量的初始值自动推导出变量的类型。
	// 使用 auto 关键字声明变量时,编译器会根据变量的初始值进行类型推导,从而确定变量的类型。
	// 这样可以简化代码,避免手动指定变量类型,特别是对于复杂的类型或使用模板时,可以减少代码的冗余和复杂性。
        if(*it == appender) {
    
    
            m_appenders.erase(it);
            break;
        }
    }
};

void Logger::log(LogLevel::Level level,LogEvent::ptr event) {
    
    
    if(level >= m_level) {
    
    
        for(auto& i : m_appenders) {
    
    
            i->log(level, event);
        }
    }
};

void Logger::debug(LogEvent::ptr event) {
    
    
    debug(LogLevel::DEBUG, event);
};

void Logger::info(LogEvent::ptr event) {
    
    
    debug(LogLevel::INFO, event);
};

void Logger::warn(LogEvent::ptr event) {
    
    
    debug(LogLevel::WARN, event);
};

void Logger::error(LogEvent::ptr event) {
    
    
    debug(LogLevel::ERROR, event);
};      

void Logger::fatal(LogEvent::ptr event) {
    
    
    debug(LogLevel::FATAL, event);
};

2.2 All codes

log.h

#ifndef __SYLAR_LOG_H__
#define __SYLAR_LOG_H__

#include <string>
#include <stdint.h>
#include <memory>
#include <list>
// 防止变量名字冲突
namespace sylar {
    
    

// 日志事件    
class LogEvent {
    
    
public:
    typedef std::shared_ptr<LogEvent> ptr;
    LogEvent();
private:
    const char* m_file = nullptr;   // 文件名
    int32_t m_line = 0;             // 行号
    uint32_t m_elapse;              // 程序启动开始到现在的毫秒数
    uint32_t m_threadId = 0;        // 线程id
    uint32_t m_fiberId = 0;         // 协程id
    uint64_t m_time;                // 时间戳
    std::string m_content;
};

// 日志级别
class LogLevel {
    
    
public:
    enum Level {
    
    
        DEBUG = 1,
        INFO = 2,
        WARN = 3,
        ERROR = 4,
        FATAL = 5
    };
};

// 日志格式器
class LogFormatter {
    
    
public:
    typedef std::shared_ptr<LogFormatter> ptr;
    std::string format(LogEvent::ptr event);
private:
};

// 日志输出地 
class LogAppender {
    
    
public:
    typedef std::shared_ptr<LogAppender> ptr;
    virtual ~LogAppender() {
    
    };

    void log(LogLevel::Level level,LogEvent::ptr event);
private:
    LogLevel::Level m_level;
};

// 日志器
class Logger{
    
    
public:
    typedef std::shared_ptr<Logger> ptr;

    Logger(const std::string& name = "root");
    void log(LogLevel::Level level,LogEvent::ptr event);

    void debug(LogEvent::ptr event);
    void info(LogEvent::ptr event);
    void warn(LogEvent::ptr event);
    void error(LogEvent::ptr event);
    void fatal(LogEvent::ptr event);

    void addAppender(LogAppender::ptr appender);
    void delAppender(LogAppender::ptr appender);

    LogLevel::Level getLevel() const {
    
    return m_level;};
    void setLevel(LogLevel::Level val) {
    
    m_level = val;};

private:
    std::string m_name;                               // 日志名称
    LogLevel::Level m_level;                          // 日志级别
    std::list<LogAppender::ptr> m_appenders;          // Appender集合

};

// 输出到控制台的Appender
class StdoutLogAppender : public LogAppender {
    
    

};

};
#endif

log.cc

#include "log.h"



namespace sylar {
    
    

Logger::Logger(const std::string& name) :m_name(name) {
    
    

};

void Logger::addAppender(LogAppender::ptr appender) {
    
    
    m_appenders.push_back(appender);
};

void Logger::delAppender(LogAppender::ptr appender) {
    
    
    for(auto it = m_appenders.begin();it != m_appenders.end();++it){
    
    
        if(*it == appender) {
    
    
            m_appenders.erase(it);
            break;
        }
    }
};

void Logger::log(LogLevel::Level level,LogEvent::ptr event) {
    
    
    if(level >= m_level) {
    
    
        for(auto& i : m_appenders) {
    
    
            i->log(level, event);
        }
    }
};

void Logger::debug(LogEvent::ptr event) {
    
    
    debug(LogLevel::DEBUG, event);
};

void Logger::info(LogEvent::ptr event) {
    
    
    debug(LogLevel::INFO, event);
};

void Logger::warn(LogEvent::ptr event) {
    
    
    debug(LogLevel::WARN, event);
};

void Logger::error(LogEvent::ptr event) {
    
    
    debug(LogLevel::ERROR, event);
};      

void Logger::fatal(LogEvent::ptr event) {
    
    
    debug(LogLevel::FATAL, event);
};
    
};



Guess you like

Origin blog.csdn.net/qq_45179361/article/details/131315509