testlogger分析

功能:

一、将loggger和ctx作为pair放到步书写器AsyncLogWrite的list中:List<std::pair<LogContextPtr, Logger *> > _pending;

1.InfoL << "测试std::cout风格打印:";

#define InfoL WriteL(::toolkit::LInfo)
--->#define WriteL(level) ::toolkit::LogContextCapture(::toolkit::getLogger(), level, __FILE__, __FUNCTION__, __LINE__)
实例化LogContextCapture:
参数:::toolkit::getLogger():全局获取Logger对象
level:传递进来的值:LInfo
__FILE__, __FUNCTION__, __LINE__:系统自带的默认值
-->LogContextCapture(Logger &logger, LogLevel level, const char *file, const char *function, int line, const char *flag = "");
调用构造函数:同时构造LogContextCapture和LogContextPtr(ctx,是LogContextCapture的内部私有成员-全局)两个对象:
LogContextCapture::
LogContextCapture(Logger &logger, LogLevel level, const char *file, const char *function, int line, const char *flag) :
_ctx(new LogContext(level, file, function, line, s_module_name.c_str(), flag)), _logger(logger) {
}
--> 需要构造LogContext:new LogContext(level, file, function, line, s_module_name.c_str(), flag)

将data输出到_ctx(LogContext)

【2.将ostream(现在_ctx 输出<<)】
LogContextCapture &LogContextCapture::operator<<(ostream &(*f)(ostream &))
if (!_ctx) {
return *this;
}
###3.关键代码:调用了_logger.write
_logger.write(_ctx);-->3.关键代码:调用了_logger.write
_ctx.reset();
return *this;
}
--> ###3.1 关键代码:调用异步书写器的write函数
void Logger::write(const LogContextPtr &ctx) {
if (_writer) {
_writer->write(ctx, *this); 3.1 关键代码:调用异步书写器的write函数
} else {
writeChannels(ctx);
}
}

-->###3.1.1 将loggger和ctx作为pair放到异步书写器AsyncLogWrite的list中,此时还在list中
_writer->write(ctx, *this);
--->void AsyncLogWriter::write(const LogContextPtr &ctx, Logger &logger) {
{
lock_guard<mutex> lock(_mutex);
/*list从尾部插入元素*/
_pending.emplace_back(std::make_pair(ctx, &logger));3.1.1 将loggger和ctx作为pair放到异步书写器的list中:List<std::pair<LogContextPtr, Logger *> > _pending;

}
_sem.post();
}

至此已经 将loggger和ctx作为pair放到异步书写器AsyncLogWriter的_pending(list)中,等待AsyncLogWriter::flushAll()
其中ctx(LogContext的智能指针):包含了日志要输出的data
// liu 实际的日志的内容
std::string _content;

------

二、等待flush异步书写器开辟了线程:

两种情况下会flushAll()


构造函数:
AsyncLogWriter::AsyncLogWriter() : _exit_flag(false) {
_thread = std::make_shared<thread>([this]() { this->run(); });
}


情况1.没有遇到_exit_flag 为true情况下,会一直flushAll,默认构造AsyncLogWriter时_exit_flag是false
void AsyncLogWriter::run() {
setThreadName("async log");
while (!_exit_flag) {
_sem.wait();
flushAll();
}
}

情况2.析构调用时:

遇到_exit_flag 为true情况下,
会在AsyncLogWriter的析构函数中设置_exit_flag为true,并且后面调用flushAll,输出最后缓存中的内容;
AsyncLogWriter::~AsyncLogWriter() {
_exit_flag = true;
_sem.post();
_thread->join();
flushAll();
}

===============================

void AsyncLogWriter::flushAll() {
// liu 获取对象或表达式的类型
decltype(_pending) tmp;
{
lock_guard<mutex> lock(_mutex);
/**
*liu 注意交换后迭代器与引用保持与原来的元素关联,
*/
tmp.swap(_pending);
}

// 挨个遍历List的中的pair,依次调用logger.writeChannels函数,LogContextPrt(_ctx) 是参数,其中包含了log的日志数据data,放到了osstringstream的stringbuff中;
tmp.for_each([&](std::pair<LogContextPtr, Logger *> &pr) {
pr.second->writeChannels(pr.first);
});
}

作者重新封装了List
template<typename FUNC>
void for_each(FUNC &&func) {
for (auto &t : *this) {
func(t);
}
}

============================

void Logger::writeChannels(const LogContextPtr &ctx) {
if (ctx->_line == _last_log->_line && ctx->_file == _last_log->_file && ctx->str() == _last_log->str()) {
//重复的日志每隔500ms打印一次,过滤频繁的重复日志
++_last_log->_repeat;
if (timevalDiff(_last_log->_tv, ctx->_tv) > 500) {
ctx->_repeat = _last_log->_repeat;
writeChannels_l(ctx);
}
return;
}
if (_last_log->_repeat) {
writeChannels_l(_last_log);
}
writeChannels_l(ctx);
}


继续调用writeChannels_l:
void Logger::writeChannels_l(const LogContextPtr &ctx) {
for (auto &chn : _channels) {
//关键:调用channels的write函数
chn.second->write(*this, ctx);
}
_last_log = ctx;
_last_log->_repeat = 0;
}

实际是:【a.1】logger->writeChannels
---【a.1.1】调用_channels->write
实际是:LogChannel->write
实际是logger的成员变量_channels(std::map<std::string, std::shared_ptr<LogChannel> > _channels;)
父类LogChannel调用write,多态转换为ConsoleChannel
实际是:
--【a.1.1.1】void ConsoleChannel::write(const Logger &logger, const LogContextPtr &ctx) {

=============================
继续解析:
void ConsoleChannel::write(const Logger &logger, const LogContextPtr &ctx) {
if (_level > ctx->_level) {
return;
}
......
//linux/windows日志启用颜色并显示日志详情
format(logger, std::cout, ctx);
#endif
}

接着调用:
format(logger, std::cout, ctx);


/**
*
* 函数调用:
* InfoL << "测试std::cout风格打印:";
* 打印的信息:
* 2023-12-16 15:18:30.658 I [test_logger.exe] [1188-14240] test_logger.cpp:40 main | 测试std::cout风格打印:
*
* @param logger
* @param ost
* @param ctx
* @param enable_color
* @param enable_detail
*/
void LogChannel::format(const Logger &logger, ostream &ost, const LogContextPtr &ctx, bool enable_color, bool enable_detail) {
if (!enable_detail && ctx->str().empty()) {
// 没有任何信息打印
return;
}

if (enable_color) {
// color console start
#ifdef _WIN32
SetConsoleColor(LOG_CONST_TABLE[ctx->_level][1]);
#else
ost << LOG_CONST_TABLE[ctx->_level][1];
#endif
}

// print log time and level
#ifdef _WIN32
ost << printTime(ctx->_tv) << " " << (char)LOG_CONST_TABLE[ctx->_level][2] << " ";
#else
ost << printTime(ctx->_tv) << " " << LOG_CONST_TABLE[ctx->_level][2] << " ";
#endif

if (enable_detail) {
// tag or process name
ost << "[" << (!ctx->_flag.empty() ? ctx->_flag : logger.getName()) << "] ";
// pid and thread_name
ost << "[" << printf_pid() << "-" << ctx->_thread_name << "] ";
// source file location
ost << ctx->_file << ":" << ctx->_line << " " << ctx->_function << " | ";
}

// log content
// liu 输出实际的log的内容“测试std::cout风格打印:” 到ost的缓存
ost << ctx->str();

if (enable_color) {
// color console end
#ifdef _WIN32
SetConsoleColor(CLEAR_COLOR);
#else
ost << CLEAR_COLOR;
#endif
}

if (ctx->_repeat > 1) {
// log repeated
ost << "\r\n Last message repeated " << ctx->_repeat << " times";
}

// flush log and new line
ost << endl;
}

类图

vs2022中使用该库(静态库)

新建工程:

 

复制include和lib

在项目根目录新建include和lib文件夹:

include:放头文件,头文件是将src目录下的所有文件直接复制进来,然后按照“类型排序”,删除其他文件,只保留".h"文件

lib:放lib库文件,lib库文件原始路径:ZLToolKit\lib\Debug

目录树如下:

 testLogger.sln
│
├─include
│  ├─Network
│  │      Buffer.h
│  │      BufferSock.h
│  │      Server.h
│  │      Session.h
│  │      Socket.h
│  │      Socket_ios.mm
│  │      sockutil.h
│  │      TcpClient.h
│  │      TcpServer.h
│  │      UdpServer.h
│  │
│  ├─Poller
│  │      EventPoller.h
│  │      Pipe.h
│  │      PipeWrap.h
│  │      SelectWrap.h
│  │      Timer.h
│  │
│  ├─Thread
│  │      semaphore.h
│  │      TaskExecutor.h
│  │      TaskQueue.h
│  │      threadgroup.h
│  │      ThreadPool.h
│  │      WorkThreadPool.h
│  │
│  ├─Util
│  │      base64.h
│  │      CMD.h
│  │      File.h
│  │      function_traits.h
│  │      List.h
│  │      local_time.h
│  │      logger.h
│  │      MD5.h
│  │      mini.h
│  │      NoticeCenter.h
│  │      onceToken.h
│  │      ResourcePool.h
│  │      RingBuffer.h
│  │      SHA1.h
│  │      SpeedStatistic.h
│  │      SqlConnection.h
│  │      SqlPool.h
│  │      SSLBox.h
│  │      SSLUtil.h
│  │      strptime_win.h
│  │      TimeTicker.h
│  │      util.h
│  │      uv_errno.h
│  │
│  └─win32
│          getopt.h
│          tailor.h
│
├─lib
│  └─Debug
│          ZLToolKit.lib
│          ZLToolKit.pdb
│
├─testLogger
│  │  testLogger.cpp
│  │  testLogger.vcxproj
│  │  testLogger.vcxproj.filters
│  │  testLogger.vcxproj.user
│  │
│  └─x64
│      └─Debug
│          │  testLogger.exe.recipe
│          │  testLogger.ilk
│          │  testLogger.log
│          │  testLogger.obj
│          │  vc143.idb
│          │  vc143.pdb
│          │
│          └─testLogger.tlog
│                  CL.command.1.tlog
│                  Cl.items.tlog
│                  CL.read.1.tlog
│                  CL.write.1.tlog
│                  link.command.1.tlog
│                  link.read.1.tlog
│                  link.write.1.tlog
│                  testLogger.lastbuildstate
│
└─x64
    └─Debug
            testLogger.exe
            testLogger.pdb

PS E:\26_zlmediakit\11_ZLToolKit\__code\_testLogger-vs22\testLogger>

 

设置项目属性

 

 

 代码调用

 1 // testLogger.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
 2 //
 3 
 4 #include <iostream>
 5 #include "Util/logger.h"
 6 
 7 
 8 using namespace std;
 9 using namespace toolkit;
10 
11 int main()
12 {
13     Logger::Instance().add(std::make_shared<ConsoleChannel>());
14     Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
15 
16 
17     InfoL << "测试std::cout 风格的日志输出打印:";
18     
19     DebugL << "DebugL...";
20 
21     std::cout << "Hello World!\n";
22 }

运行结果

centos 使用 (动态库)

新建clion项目,选择可执行文件、支持c++11

cmake源码

 1 cmake_minimum_required(VERSION 3.21)
 2 project(_testLogger)
 3 
 4 set(CMAKE_CXX_STANDARD 11)
 5 
 6 #指定库的目录变量
 7 set(LIBZLM_LIB /_workdir/_08_selfCode/_testLogger/lib/libZLToolKit.so)
 8 
 9 #指定头文件搜索路径
10 include_directories("${PROJECT_SOURCE_DIR}/include")
11 
12 add_executable(_testLogger main.cpp)
13 
14 target_link_libraries(_testLogger ${LIBZLM_LIB})

 

main源码

#include <iostream>
#include "Util/logger.h"

using namespace std;
using namespace toolkit;

// cmake https://blog.csdn.net/Vincent20111024/article/details/129327542

int main() {

    Logger::Instance().add(std::make_shared<ConsoleChannel>());
    Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());


    InfoL << "测试std::cout 风格的日志输出打印:";

    DebugL << "DebugL...";

    std::cout << "Hello, World!" << std::endl;
    return 0;
}

 

运行结果:

 文件树目录:

  1 .
  2 ├── cmake-build-debug
  3 │   ├── build.ninja
  4 │   ├── .cmake
  5 │   │   └── api
  6 │   │       └── v1
  7 │   │           ├── query
  8 │   │           │   ├── cache-v2
  9 │   │           │   ├── cmakeFiles-v1
 10 │   │           │   ├── codemodel-v2
 11 │   │           │   └── toolchains-v1
 12 │   │           └── reply
 13 │   │               ├── cache-v2-8e8881062be1748bf551.json
 14 │   │               ├── cmakeFiles-v1-a684896424473d278502.json
 15 │   │               ├── codemodel-v2-e48b31e71f5adb5d5705.json
 16 │   │               ├── directory-.-Debug-f5ebdc15457944623624.json
 17 │   │               ├── index-2023-12-18T11-43-16-0332.json
 18 │   │               ├── target-_testLogger-Debug-7820f096840015a86989.json
 19 │   │               └── toolchains-v1-c006aca650fa415857a6.json
 20 │   ├── CMakeCache.txt
 21 │   ├── CMakeFiles
 22 │   │   ├── 3.21.1
 23 │   │   │   ├── CMakeCCompiler.cmake
 24 │   │   │   ├── CMakeCXXCompiler.cmake
 25 │   │   │   ├── CMakeDetermineCompilerABI_C.bin
 26 │   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
 27 │   │   │   ├── CMakeSystem.cmake
 28 │   │   │   ├── CompilerIdC
 29 │   │   │   │   ├── a.out
 30 │   │   │   │   ├── CMakeCCompilerId.c
 31 │   │   │   │   └── tmp
 32 │   │   │   └── CompilerIdCXX
 33 │   │   │       ├── a.out
 34 │   │   │       ├── CMakeCXXCompilerId.cpp
 35 │   │   │       └── tmp
 36 │   │   ├── clion-environment.txt
 37 │   │   ├── clion-log.txt
 38 │   │   ├── cmake.check_cache
 39 │   │   ├── CMakeOutput.log
 40 │   │   ├── CMakeTmp
 41 │   │   ├── feature_tests.bin
 42 │   │   ├── feature_tests.cxx
 43 │   │   ├── rules.ninja
 44 │   │   ├── TargetDirectories.txt
 45 │   │   └── _testLogger.dir
 46 │   ├── cmake_install.cmake
 47 │   ├── .ninja_deps
 48 │   ├── .ninja_log
 49 │   └── Testing
 50 │       └── Temporary
 51 │           └── LastTest.log
 52 ├── CMakeLists.txt
 53 ├── .idea
 54 │   ├── .gitignore
 55 │   ├── misc.xml
 56 │   ├── modules.xml
 57 │   ├── _testLogger.iml
 58 │   └── workspace.xml
 59 ├── include
 60 │   ├── Network
 61 │   │   ├── Buffer.h
 62 │   │   ├── BufferSock.h
 63 │   │   ├── Server.h
 64 │   │   ├── Session.h
 65 │   │   ├── Socket.h
 66 │   │   ├── Socket_ios.mm
 67 │   │   ├── sockutil.h
 68 │   │   ├── TcpClient.h
 69 │   │   ├── TcpServer.h
 70 │   │   └── UdpServer.h
 71 │   ├── Poller
 72 │   │   ├── EventPoller.h
 73 │   │   ├── Pipe.h
 74 │   │   ├── PipeWrap.h
 75 │   │   ├── SelectWrap.h
 76 │   │   └── Timer.h
 77 │   ├── Thread
 78 │   │   ├── semaphore.h
 79 │   │   ├── TaskExecutor.h
 80 │   │   ├── TaskQueue.h
 81 │   │   ├── threadgroup.h
 82 │   │   ├── ThreadPool.h
 83 │   │   └── WorkThreadPool.h
 84 │   ├── Util
 85 │   │   ├── base64.h
 86 │   │   ├── CMD.h
 87 │   │   ├── File.h
 88 │   │   ├── function_traits.h
 89 │   │   ├── List.h
 90 │   │   ├── local_time.h
 91 │   │   ├── logger.h
 92 │   │   ├── MD5.h
 93 │   │   ├── mini.h
 94 │   │   ├── NoticeCenter.h
 95 │   │   ├── onceToken.h
 96 │   │   ├── ResourcePool.h
 97 │   │   ├── RingBuffer.h
 98 │   │   ├── SHA1.h
 99 │   │   ├── SpeedStatistic.h
100 │   │   ├── SqlConnection.h
101 │   │   ├── SqlPool.h
102 │   │   ├── SSLBox.h
103 │   │   ├── SSLUtil.h
104 │   │   ├── strptime_win.h
105 │   │   ├── TimeTicker.h
106 │   │   ├── util.h
107 │   │   └── uv_errno.h
108 │   └── win32
109 │       ├── getopt.h
110 │       └── tailor.h
111 ├── lib
112 │   ├── libZLToolKit.a
113 │   └── libZLToolKit.so
114 └── main.cpp
115 
116 24 directories, 90 files

 

posted @ 2023-12-16 16:14  OzTaking  阅读(14)  评论(0编辑  收藏  举报