【Muduo】Noncopyable、Logger、Timestam代码逻辑梳理

在开始之前,先将用到的一些工具类实现。

Noncopyable类 

此类在Muduo源码中,作为不可拷贝构造和赋值的类的基类,通过禁止其拷贝构造和赋值运算符来实现,并被其他的类所默认继承(私有继承)。

/*
noncopyable 被继承以后,派生类对象可以正常构造和析构
                        但是不可用进行拷贝构造和赋值
*/
class noncopyable{
public:
    noncopyable(const noncopyable&) = delete;
    noncopyable& operator=(const noncopyable) = delete;
protected: // 可以被派生类访问
    noncopyable() = default;
    ~noncopyable() = default;
};

Timestamp类

Timestamp类封装了多个接口,提供了Muduo库中的时间获取。

头文件:

#pragma once
#include <iostream>
#include <string>

class Timestamp
{
private:
    int64_t microSecondsSinceEpoch_;

public:
    Timestamp();
    explicit Timestamp(int64_t microSecondsSinceEpoch); // explicit 不允许隐式类型转换
    static Timestamp now();
    std::string toString() const;

    ~Timestamp();
};

cpp文件

#include "Timestamp.h"
#include <time.h>
#include <sstream>
#include <iomanip>  

Timestamp::Timestamp() : microSecondsSinceEpoch_(0)
{
}
Timestamp::Timestamp(int64_t microSecondsSinceEpochArg) : microSecondsSinceEpoch_(microSecondsSinceEpochArg)
{
}
Timestamp Timestamp::now()
{
    return Timestamp(ti);
}
// return yyyy/MM/dd hh:mm:ss
std::string Timestamp::toString() const
{
    // C++写法,格式化输出太麻烦
    std::string time;
    tm *tm_time = localtime(&microSecondsSinceEpoch_);
    std::ostringstream oss;
    oss << std::setw(4) << (tm_time->tm_year + 1900) << "-"  
        << std::setw(2) << std::setfill('0') << (tm_time->tm_mon + 1) << "-"  
        << std::setw(2) << std::setfill('0') << tm_time->tm_mday << " "  
        << std::setw(2) << std::setfill('0') << tm_time->tm_hour << ":"  
        << std::setw(2) << std::setfill('0') << tm_time->tm_min << ":"  
        << std::setw(2) << std::setfill('0') << tm_time->tm_sec;
    time = oss.str();
    return time;

    // C语言写法
    char buf[128] = {0};
    sprintf(buf, "%4d-%02d-%02d %02d:%2d:%02d",
                tm_time->tm_year + 1900,
                tm_time->tm_mon + 1,
                tm_time->tm_mday,
                tm_time->tm_hour,
                tm_time->tm_min,
                tm_time->tm_sec);
    return buf;
}

Timestamp::~Timestamp()
{
}

Logger类

源代码中日志逻辑比较复杂,而课程中老师实现了一个C语言输出风格的日志类,在此,我实现了一个C++风格的日志类LogStream,易于使用,可以通过宏定义实现日志分级,确保了线程间安全。(只是不知道这种频繁的对象创建会不会对性能有所影响,请大佬们指点~)

头文件:

#include "Timestamp.h"
#include <sstream>
#include <string>
#include <mutex>
#include <fstream>

// 定义日志级别 INFO  ERROR  FATAL  DEBUG
enum LogLevel
{
    INFO,  // 普通信息
    ERROR, // 错误信息
    FATAL, // core信息
    DEBUG, // 调试信息
};

// 直接使用左移运算法<<进行输出,末尾不需要加换行
#define LOG_INFO LogStream(INFO, __FILE__, __LINE__, __FUNCTION__)
// 直接使用左移运算法<<进行输出,末尾不需要加换行
#define LOG_ERROR LogStream(ERROR, __FILE__, __LINE__, __FUNCTION__)
// 直接使用左移运算法<<进行输出,末尾不需要加换行
#define LOG_FATAL LogStream(FATAL, __FILE__, __LINE__, __FUNCTION__)

#ifdef DEBUG_LOGGING_ENABLED
// 直接使用左移运算法<<进行输出,末尾不需要加换行
#define LOG_DEBUG LogStream(DEBUG, __FILE__, __LINE__, __FUNCTION__)
#else
#define LOG_DEBUG if(false) LogStream(DEBUG, __FILE__, __LINE__, __FUNCTION__)
#endif


// 每个LogStream对象都是一行Log日志
// 在对象析构的时候存入文件
class LogStream
{
public:
    LogStream(const int logLevel,
                const char* file = __FILE__,   
                const int line = __LINE__,
                const char* func = __FUNCTION__);

    // 在此处将ss_中所有内容写入文件
    ~LogStream();

    // 代理到std::stringstream的函数
    template <typename T>
    LogStream &operator<<(const T &value);

private:
    std::stringstream ss_; // 通过重载<<接收用户的多种数据的log信息
    std::stringstream ssEnd_; // 保存log发生的位置信息
    // 静态变量,全局只有一个,在多线程的多个实例化对象中也可保持线程安全
    static std::mutex fileMutex;
    int logLevel_;
};

// 代理到std::stringstream的函数
template <typename T>
LogStream& LogStream::operator<<(const T &value)
{
    ss_ << value;
    return *this;
}

CPP文件

#include "LogStream.h"

std::mutex LogStream::fileMutex;

LogStream::LogStream(const int logLevel, const char *file, const int line, const char* func)
    : logLevel_(logLevel)
{
    ssEnd_ << " --FILE:" << file << " LINE:" << line << " FUNC:" << func;
}

// 在此处将ss_中所有内容写入文件
LogStream::~LogStream()
{
    if (ss_.str().empty())
        return;
    std::string output;
    switch (logLevel_)
    {
    case INFO:
        output += "[INFO] ";
        break;
    case ERROR:
        output += "[ERROR]";
        break;
    case FATAL:
        output += "[FATAL]";
        break;
    case DEBUG:
        output += "[DEBUG]";
        break;
    default:
        break;
    }
    std::string time = Timestamp::now().toString();
    std::string filePath = time.substr(0, 10) + "-log.txt";

    {
        std::unique_lock<std::mutex> ulock(fileMutex);
        // C++ 文件流
        std::ofstream file(filePath, std::ios::app);
        if (file.is_open())
        {
            file << output << time << " " << ss_.str() << ssEnd_.str() << std::endl;
            file.close();
        }
        else
        {
            // std::cout << "error : log file not open!" << std::endl;
            return;
        }
    }

    if (logLevel_ == FATAL)
    {
        exit(-1);
    }
}

Callbacks.h文件

使用C++的语法来定义一些类型别名,方便其他类使用

#include <functional>
#include <memory>

class Buffer;
class TcpConnection;
class Timestamp;

using TcpConnectionPtr = std::shared_ptr<TcpConnection>;
using TimerCallback = std::function<void()>;
using ConnectionCallback = std::function<void (const TcpConnectionPtr&)>;
using CloseCallback = std::function<void (const TcpConnectionPtr&)>;
using WriteCompleteCallback = std::function<void (const TcpConnectionPtr&)>;
using HighWaterMarkCallback = std::function<void (const TcpConnectionPtr&, size_t)>;
using MessageCallback = std::function<void (const TcpConnectionPtr&,
                                            Buffer*,
                                            Timestamp)>;

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值