当前位置: 代码迷 >> 综合 >> 从零开始自制实现WebServer(二十)---- C++ High-Performance WebServer源码实现(Logging核心代码部分)
  详细解决方案

从零开始自制实现WebServer(二十)---- C++ High-Performance WebServer源码实现(Logging核心代码部分)

热度:55   发布时间:2023-11-17 16:13:48.0

文章目录

    • 全流程实现博客链接
    • 前引
    • (二十)---- C++ High-Performance WebServer源码实现(Logging核心代码部分)
      • 1、asynclogging.h
      • 1、asynclogging.cc
      • 2、logfile.h
      • 2、logfile.cc
      • 3、logging.h
      • 3、logging.cc
      • 4、logstream.h
      • 4、logstream.cc


全流程实现博客链接


从零开始自制实现C++ High-Performance WebServer 全流程记录(基于muduo网络库)


前引


这部分写完了 待会把总结博客写了
就回寝室好好休息 吃顿饭 看部电影休息去啦~


(二十)---- C++ High-Performance WebServer源码实现(Logging核心代码部分)


1、asynclogging.h


#ifndef TINY_MUDUO_ASYNCLOGGING_H_
#define TINY_MUDUO_ASYNCLOGGING_H_#include <vector>
#include <memory>#include "mutex.h"
#include "condition.h"
#include "latch.h"
#include "thread.h"
#include "logging.h"
#include "logstream.h"
#include "noncopyable.h"
#include "logfile.h"namespace tiny_muduo {
    static const double kBufferWriteTimeout = 3.0;
static const int64_t kSingleFileMaximumSize = 1024 * 1024 * 1024;class AsyncLogging : public NonCopyAble {
    public:typedef FixedBuffer<kLargeSize> Buffer;typedef std::unique_ptr<Buffer> BufferPtr;typedef std::vector<BufferPtr> BufferVector;typedef std::unique_ptr<LogFile> LogFilePtr;AsyncLogging(const char* filepath = nullptr) : running_(false),filepath_(filepath),mutex_(),cond_(mutex_),latch_(1),thread_(std::bind(&AsyncLogging::ThreadFunc, this), "AsyncLogThread"),current_(new Buffer()),next_(new Buffer()) {
    }~AsyncLogging() {
    if (running_) {
    Stop();} }void Stop() {
    running_ = false;cond_.Notify();thread_.Join();}void StartAsyncLogging() {
    running_ = true;thread_.StartThread(); latch_.Wait();}void Append(const char* data, int len);void Flush();void ThreadFunc();private:bool running_;const char* filepath_;MutexLock mutex_;Condition cond_;Latch latch_;Thread thread_;BufferPtr current_;BufferPtr next_; BufferVector buffers_to_write_; 
};} // namespace tiny_muduo#endif

1、asynclogging.cc


#include "asynclogging.h"#include <functional>
#include <utility>
#include <memory>using namespace tiny_muduo;void AsyncLogging::Append(const char* data, int len) {
    MutexLockGuard guard(mutex_);if (current_->writablebytes() >= len) {
    current_->Append(data, len);} else {
    buffers_to_write_.emplace_back(std::move(current_)); if (next_) {
    current_ = std::move(next_);} else {
    current_.reset(new Buffer());}cond_.Notify();}
}void AsyncLogging::Flush() {
    fflush(stdout);
}void AsyncLogging::ThreadFunc() {
    latch_.CountDown();BufferPtr newbuffer_current(new Buffer());BufferPtr newbuffer_next(new Buffer());LogFilePtr log(new LogFile(filepath_));newbuffer_current->SetBufferZero();newbuffer_next->SetBufferZero();BufferVector buffers;while (running_) {
    {
    MutexLockGuard guard(mutex_);if (buffers_to_write_.empty()) {
    cond_.WaitForFewSeconds(kBufferWriteTimeout);}buffers_to_write_.emplace_back(std::move(current_));buffers.swap(buffers_to_write_);current_ = std::move(newbuffer_current);if (!next_) {
    next_ = std::move(newbuffer_next);}}for (const auto& buffer : buffers) {
    log->Write(buffer->data(), buffer->len());}if (log->writtenbytes() >= kSingleFileMaximumSize) {
    log.reset(new LogFile(filepath_));} if (buffers.size() > 2) {
    buffers.resize(2);}if (!newbuffer_current) {
    newbuffer_current = std::move(buffers.back());buffers.pop_back();newbuffer_current->SetBufferZero();}if (!newbuffer_next) {
    newbuffer_current = std::move(buffers.back());buffers.pop_back();newbuffer_current->SetBufferZero();}buffers.clear();}
}

2、logfile.h


#ifndef TINY_MUDUO_LOGFILE_H_
#define TINY_MUDUO_LOGFILE_H_#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>#include <string>#include "timestamp.h"namespace tiny_muduo {
    static const time_t kFlushInterval = 3;class LogFile {
    public:LogFile(const char* filepath);~LogFile();void Write(const char* data, int len);void Flush() {
     fflush(fp_); }int64_t writtenbytes() const {
     return written_bytes_; }private:FILE* fp_; int64_t written_bytes_;time_t lastwrite_;time_t lastflush_; 
};}#endif

2、logfile.cc


#include "logfile.h"using namespace tiny_muduo;LogFile::LogFile(const char* filepath = nullptr): fp_(::fopen(filepath, "ae")),written_bytes_(0),lastwrite_(0),lastflush_(0) {
    if (!fp_) {
    std::string DefaultPath = std::move("./LogFiles/LogFile_" +Timestamp::Now().Timestamp::ToFormattedDefaultLogString() +".log");fp_ = ::fopen(DefaultPath.data(), "ae");}
}LogFile::~LogFile() {
    Flush();fclose(fp_);
}void LogFile::Write(const char* data, int len) {
    int pos = 0;while (pos != len) {
    pos += static_cast<int>(fwrite_unlocked(data + pos, sizeof(char), len - pos, fp_));}time_t now = ::time(nullptr);if (len != 0) {
    lastwrite_ = now;written_bytes_ += len;}if (lastwrite_ - lastflush_ > kFlushInterval) {
    Flush();lastflush_ = now;}
}

3、logging.h


#ifndef TINY_MUDUO_LOGGING_H_
#define TINY_MUDUO_LOGGING_H_#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>#include <cstring>#include "timestamp.h"
#include "logstream.h"
#include "currentthread.h"
#include "noncopyable.h"namespace tiny_muduo {
    class SourceClass {
    public:SourceClass(const char* data) : data_(data), len_(static_cast<int>(strlen(data_))) {
    const char* forward_slash = strrchr(data, '/');if (forward_slash) {
    data_ = forward_slash + 1;len_ -= static_cast<int>((data_ - data)); } }  const char* data_;int len_; 
};class Logger : public NonCopyAble {
    public:enum Level {
    DEBUG,INFO,WARN,ERROR,FATAL};Logger(const char* file_, int line, Level level) : implement_(file_, line, level) {
    }LogStream& stream() {
     return implement_.stream(); }typedef void (*OutputFunc)(const char* data, int len);typedef void (*FlushFunc)();private:class Implement : public NonCopyAble {
    public:typedef Logger::Level Level;Implement(SourceClass&& source, int line, Level level); ~Implement();void FormattedTime();const char* GetLogLevel() const;void Finish() {
     stream_ << " - "<< GeneralTemplate(fileinfo_.data_, fileinfo_.len_) << ':' << line_ << '\n'; }LogStream& stream() {
     return stream_; }private:SourceClass fileinfo_;int line_; Level level_;LogStream stream_;};Implement implement_;
};} //namespace tiny_muduotiny_muduo::Logger::Level LogLevel();
void SetLogLevel(tiny_muduo::Logger::Level nowlevel);
const char* ErrorToString(int err);#define LOG_DEBUG if (LogLevel() <= tiny_muduo::Logger::DEBUG) \tiny_muduo::Logger(__FILE__, __LINE__, tiny_muduo::Logger::DEBUG).stream()
#define LOG_INFO if (LogLevel() <= tiny_muduo::Logger::INFO) \tiny_muduo::Logger(__FILE__, __LINE__, tiny_muduo::Logger::INFO).stream()
#define LOG_WARN tiny_muduo::Logger(__FILE__, __LINE__, tiny_muduo::Logger::WARN).stream()
#define LOG_ERROR tiny_muduo::Logger(__FILE__, __LINE__, tiny_muduo::Logger::ERROR).stream()
#define LOG_FATAL tiny_muduo::Logger(__FILE__, __LINE__, tiny_muduo::Logger::FATAL).stream()#endif

3、logging.cc


#include "logging.h"#include <utility>using namespace tiny_muduo;
using namespace CurrentThread;namespace CurrentThread {
    __thread time_t t_lastsecond;
__thread char t_time[64];
__thread const int t_formattedtimeLength = 18; 
__thread char t_errorbuf[512];} // namespace CurrentThreadconst char* ErrorToString(int err) {
    return strerror_r(err, t_errorbuf, sizeof(t_errorbuf));
}static const int kLogLevelStringLength = 6;static void DefaultOutput(const char* data, int len) {
    fwrite(data, len, sizeof(char), stdout); 
}static void DefaultFlush() {
    fflush(stdout);  
}Logger::OutputFunc g_Output = DefaultOutput;
Logger::FlushFunc g_Flush = DefaultFlush;
Logger::Level g_level = Logger::Level::INFO;void SetOutputFunc(Logger::OutputFunc func) {
    g_Output = func;
}void SetFlushFunc(Logger::FlushFunc func) {
    g_Flush = func;
}Logger::Level LogLevel() {
     return g_level; }
void SetLogLevel(tiny_muduo::Logger::Level nowlevel) {
     g_level = nowlevel; }Logger::Implement::Implement(SourceClass&& source, int line, Level level)  : fileinfo_(std::move(source)),line_(line),level_(level) {
    FormattedTime();CurrentThread::tid();
}  Logger::Implement::~Implement() {
    Finish();const LogStream::Buffer& buffer = stream_.buffer();g_Output(buffer.data(), buffer.len());
}const char* Logger::Implement::GetLogLevel() const {
    switch(level_) {
    case DEBUG:return "DEBUG ";case INFO:return "INFO ";case WARN:return "WARN ";case ERROR:return "ERROR ";case FATAL:return "FATAL ";}   return nullptr;
} void Logger::Implement::FormattedTime() {
    Timestamp now = Timestamp::Now();time_t seconds = static_cast<time_t>(now.microseconds() / kMicrosecond2Second);int microseconds = static_cast<int>(now.microseconds() % kMicrosecond2Second);if (t_lastsecond != seconds) {
    struct tm tm_time;localtime_r(&seconds, &tm_time);snprintf(t_time, sizeof(t_time), "%4d%02d%02d %02d:%02d:%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);t_lastsecond = seconds;}char buf[32] = {
    0};int microlen = snprintf(buf, sizeof(buf), "%06d ", microseconds);stream_ << GeneralTemplate(t_time, t_formattedtimeLength) << GeneralTemplate(buf, microlen);stream_ << GeneralTemplate(CurrentThread::t_formattedTid, CurrentThread::t_formattedTidLength);stream_ << GeneralTemplate(GetLogLevel(), kLogLevelStringLength);
}

4、logstream.h


#ifndef TINY_MUDUO_LOGSTREAM_H_
#define TINY_MUDUO_LOGSTREAM_H_#include <stdio.h>
#include <string.h>#include <string>
#include <algorithm>#include "noncopyable.h"namespace tiny_muduo {
    const int kSmallSize = 4096;
const int kLargeSize = 4096 * 1000;
static const int kNum2MaxStringLength = 48;
static const char digits[] = {
    '9', '8', '7', '6', '5', '4', '3', '2', '1', '0','1', '2', '3', '4', '5', '6', '7', '8', '9'}; class GeneralTemplate : public NonCopyAble {
    public:GeneralTemplate() : data_(nullptr), len_(0) {
    }explicit GeneralTemplate(const char* data, int len) : data_(data), len_(len) {
    }  const char* data_;int len_;
};template <int SIZE>
class FixedBuffer : public NonCopyAble {
    public:FixedBuffer();~FixedBuffer();static void CookieStart();static void CookieEnd();void Append(const char* input_data, int length) {
    if (writablebytes() < length) {
    length = writablebytes();}memcpy(cur_, input_data, length);cur_ += length;}void SetBufferZero() {
    memset(buf_, '\0', sizeof(buf_));cur_ = buf_;}void SetCookie(void (*cookie)()) {
     cookie_ = cookie; } void Add(int length) {
     cur_ += length; }const char* data() const {
     return buf_; }int len() const {
     return static_cast<int>(cur_ - buf_); }int writablebytes() const {
     return static_cast<int>(end() - cur_); }char* current() const {
     return cur_; }const char* end() const {
     return buf_ + sizeof(buf_); } private:void (*cookie_)();char buf_[SIZE]; char* cur_;
};class LogStream {
    public:typedef FixedBuffer<kSmallSize> Buffer;typedef LogStream Self;LogStream() {
    }~LogStream() {
    }Buffer& buffer() {
     return buffer_; }template <typename T>void FormatInteger(T num) {
    if (buffer_.writablebytes() >= kNum2MaxStringLength) {
    char* buf = buffer_.current();char* now = buf;const char* zero = digits + 9;bool negative = num < 0;do {
    int remainder = static_cast<int>(num % 10); *(now++) = zero[remainder];num /= 10; } while (num != 0); if (negative) *(now++) = '-';*now = '\0';std::reverse(buf, now); buffer_.Add(static_cast<int>(now - buf));}   }Self& operator<<(short num) {
    return (*this) << static_cast<int>(num); }Self& operator<<(unsigned short num) {
     return (*this) << static_cast<unsigned int>(num); } Self& operator<<(int num) {
    FormatInteger(num); return *this;} Self& operator<<(unsigned int num) {
    FormatInteger(num); return *this;}Self& operator<<(long num) {
    FormatInteger(num);return *this;} Self& operator<<(unsigned long num) {
    FormatInteger(num);return *this;}Self& operator<<(long long num) {
    FormatInteger(num);return *this;}Self& operator<<(unsigned long long num) {
    FormatInteger(num);return *this;}Self& operator<<(const float& num) {
    return (*this) << static_cast<double>(num);}Self& operator<<(const double& num) {
    char buf[32];int len = snprintf(buf, sizeof(buf), "%g", num); buffer_.Append(buf, len);return *this;}Self& operator<<(bool boolean) {
    return (*this) << (boolean ? 1 : 0);}Self& operator<<(char chr) {
    buffer_.Append(&chr, 1);return *this;}Self& operator<<(const void* data) {
    return (*this) << static_cast<const char*>(data); }Self& operator<<(const char* data) {
    buffer_.Append(data, static_cast<int>(strlen(data)));return *this;}Self& operator<<(const GeneralTemplate& source) {
    buffer_.Append(source.data_, source.len_);return *this;}Self& operator<<(const std::string& str) {
    buffer_.Append(str.data(), static_cast<int>(str.size()));return *this;}private:Buffer buffer_;};}#endif

4、logstream.cc


#include "logstream.h"using namespace tiny_muduo;template <int SIZE>
void FixedBuffer<SIZE>::CookieStart() {
    }template <int SIZE>
void FixedBuffer<SIZE>::CookieEnd() {
    }template <int SIZE>
FixedBuffer<SIZE>::FixedBuffer() : cur_(buf_) {
    SetCookie(CookieStart); 
}template <int SIZE>
FixedBuffer<SIZE>::~FixedBuffer() {
    SetCookie(CookieEnd);
}template class FixedBuffer<kLargeSize>;
template class FixedBuffer<kSmallSize>;
  相关解决方案