From cced71ca5b739e9e63c6c9b03c92f0600c495a9d Mon Sep 17 00:00:00 2001 From: Hevake Lee Date: Fri, 7 Feb 2025 22:27:29 +0800 Subject: [PATCH 1/4] =?UTF-8?q?fix(base):=20=E5=AE=9E=E7=8E=B0=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=BF=87=E9=95=BF=EF=BC=8C=E8=BF=9B=E8=A1=8C=E6=88=AA?= =?UTF-8?q?=E6=96=AD=E6=89=93=E5=8D=B0=E7=9A=84=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=97=A5=E5=BF=97=E5=86=85=E5=AE=B9=E8=BF=87?= =?UTF-8?q?=E9=95=BF=E4=B8=A2=E5=BC=83=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/base/log_imp.cpp | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/modules/base/log_imp.cpp b/modules/base/log_imp.cpp index c563461..a92a786 100644 --- a/modules/base/log_imp.cpp +++ b/modules/base/log_imp.cpp @@ -29,7 +29,10 @@ #include namespace { -constexpr uint32_t LOG_MAX_LEN = (100 << 10); +constexpr size_t kMaxLength = (100 << 10); //! 限定单条日志最大长度 +constexpr const char *kTruncTipText = " (TOO LONG, TRUNCATED)"; +constexpr size_t kTruncTipLen = ::strlen(kTruncTipText); +constexpr size_t kTruncatedLength = kMaxLength - kTruncTipLen; std::mutex _lock; uint32_t _id_alloc = 0; @@ -125,25 +128,42 @@ void LogPrintfFunc(const char *module_id, const char *func_name, const char *fil if (fmt != nullptr) { if (with_args) { uint32_t buff_size = 1024; //! 初始大小,可应对绝大数情况 + bool is_need_trunc = false; //! 是否过长需要截断 + for (;;) { va_list args; char buffer[buff_size]; va_start(args, fmt); - size_t len = vsnprintf(buffer, buff_size, fmt, args); + size_t len = 0; + + if (!is_need_trunc) { //! 如果不需要截断 + len = ::vsnprintf(buffer, buff_size, fmt, args); + + } else { //! 如果需要截断处理 + ::vsnprintf(buffer, kTruncatedLength + 1, fmt, args); + ::strcpy(buffer + kTruncatedLength, kTruncTipText); + len = kTruncatedLength + kTruncTipLen; + } + va_end(args); + //! 如果buffer的空间够用,则正常派发日志 + //! 否则要对buffer空间进行扩张,或是对内容进行截断 if (len < buff_size) { content.text_len = len; content.text_ptr = buffer; Dispatch(content); break; } - - buff_size = len + 1; //! 要多留一个结束符 \0,否则 vsnprintf() 会少一个字符 - if (buff_size > LOG_MAX_LEN) { - std::cerr << "WARN: log text length " << buff_size << ", too long!" << std::endl; - break; + + //! 没有超过MaxLength,则进行扩张 + if (len <= kMaxLength) { + buff_size = len + 1; //! 要多留一个结束符 \0,否则 vsnprintf() 会少一个字符 + + } else { //! 否则进行截断处理 + is_need_trunc = true; + buff_size = kTruncatedLength + kTruncTipLen + 1; } } } else { -- Gitee From cf34c7d3a9c01e35cfc0b48196214bd64624b9d2 Mon Sep 17 00:00:00 2001 From: Hevake Lee Date: Sat, 8 Feb 2025 09:45:37 +0800 Subject: [PATCH 2/4] =?UTF-8?q?tidy(base):=20=E4=BC=98=E5=8C=96log=5Fimpl.?= =?UTF-8?q?cpp=E6=A0=BC=E5=BC=8F=EF=BC=8C=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/base/log_imp.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/base/log_imp.cpp b/modules/base/log_imp.cpp index a92a786..7206df1 100644 --- a/modules/base/log_imp.cpp +++ b/modules/base/log_imp.cpp @@ -29,10 +29,11 @@ #include namespace { -constexpr size_t kMaxLength = (100 << 10); //! 限定单条日志最大长度 + +constexpr size_t kLogTextMaxLength = (100 << 10); //! 限定单条日志最大长度为100KB constexpr const char *kTruncTipText = " (TOO LONG, TRUNCATED)"; constexpr size_t kTruncTipLen = ::strlen(kTruncTipText); -constexpr size_t kTruncatedLength = kMaxLength - kTruncTipLen; +constexpr size_t kTruncatedLength = kLogTextMaxLength - kTruncTipLen; std::mutex _lock; uint32_t _id_alloc = 0; @@ -156,11 +157,11 @@ void LogPrintfFunc(const char *module_id, const char *func_name, const char *fil Dispatch(content); break; } - + //! 没有超过MaxLength,则进行扩张 - if (len <= kMaxLength) { + if (len <= kLogTextMaxLength) { buff_size = len + 1; //! 要多留一个结束符 \0,否则 vsnprintf() 会少一个字符 - + } else { //! 否则进行截断处理 is_need_trunc = true; buff_size = kTruncatedLength + kTruncTipLen + 1; -- Gitee From 24377e81c75bcb23fc7dd41696443cbac424248a Mon Sep 17 00:00:00 2001 From: Hevake Lee Date: Wed, 12 Feb 2025 01:07:04 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix(base,log):1.11.13,=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=86=85=E5=AE=B9=E8=BF=87=E9=95=BF=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E8=BE=93=E5=87=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/base/CMakeLists.txt | 4 +- modules/base/Makefile | 4 +- modules/base/{log_imp.cpp => log_impl.cpp} | 52 ++++++---- modules/base/{log_imp.h => log_impl.h} | 11 +- modules/base/log_output.cpp | 7 +- modules/base/log_output_test.cpp | 19 ++++ modules/log/async_file_sink.cpp | 18 ++-- modules/log/async_file_sink.h | 4 +- modules/log/async_file_sink_test.cpp | 47 ++++----- modules/log/async_sink.cpp | 112 ++++++++------------- modules/log/async_sink.h | 13 ++- modules/log/async_sink_test.cpp | 38 ++++--- modules/log/async_stdout_sink.cpp | 15 +-- modules/log/async_stdout_sink.h | 4 +- modules/log/async_stdout_sink_test.cpp | 13 ++- modules/log/async_syslog_sink.cpp | 8 +- modules/log/async_syslog_sink.h | 3 +- modules/log/async_syslog_sink_test.cpp | 12 ++- modules/log/sink.h | 4 +- modules/log/sync_stdout_sink.cpp | 7 +- modules/log/sync_stdout_sink_test.cpp | 38 ++++++- version.mk | 2 +- 22 files changed, 250 insertions(+), 185 deletions(-) rename modules/base/{log_imp.cpp => log_impl.cpp} (81%) rename modules/base/{log_imp.h => log_impl.h} (88%) diff --git a/modules/base/CMakeLists.txt b/modules/base/CMakeLists.txt index b1b39cc..4494fa5 100644 --- a/modules/base/CMakeLists.txt +++ b/modules/base/CMakeLists.txt @@ -30,7 +30,7 @@ set(TBOX_LIBRARY_NAME tbox_base) set(TBOX_BASE_HEADERS version.h log.h - log_imp.h + log_impl.h log_output.h defines.h scope_exit.hpp @@ -50,7 +50,7 @@ set(TBOX_BASE_HEADERS set(TBOX_BASE_SOURCES version.cpp - log_imp.cpp + log_impl.cpp log_output.cpp backtrace.cpp catch_throw.cpp diff --git a/modules/base/Makefile b/modules/base/Makefile index ec799aa..59a99b1 100644 --- a/modules/base/Makefile +++ b/modules/base/Makefile @@ -31,7 +31,7 @@ HAVE_EXECINFO_H ?= yes HEAD_FILES = \ version.h \ log.h \ - log_imp.h \ + log_impl.h \ log_output.h \ defines.h \ scope_exit.hpp \ @@ -51,7 +51,7 @@ HEAD_FILES = \ CPP_SRC_FILES = \ version.cpp \ - log_imp.cpp \ + log_impl.cpp \ log_output.cpp \ backtrace.cpp \ catch_throw.cpp \ diff --git a/modules/base/log_imp.cpp b/modules/base/log_impl.cpp similarity index 81% rename from modules/base/log_imp.cpp rename to modules/base/log_impl.cpp index 7206df1..4797674 100644 --- a/modules/base/log_imp.cpp +++ b/modules/base/log_impl.cpp @@ -17,7 +17,7 @@ * project authors may be found in the CONTRIBUTORS.md file in the root * of the source tree. */ -#include "log_imp.h" +#include "log_impl.h" #include #include @@ -30,10 +30,7 @@ namespace { -constexpr size_t kLogTextMaxLength = (100 << 10); //! 限定单条日志最大长度为100KB -constexpr const char *kTruncTipText = " (TOO LONG, TRUNCATED)"; -constexpr size_t kTruncTipLen = ::strlen(kTruncTipText); -constexpr size_t kTruncatedLength = kLogTextMaxLength - kTruncTipLen; +size_t _LogTextMaxLength = (100 << 10); //! 限定单条日志最大长度,默认为100KB std::mutex _lock; uint32_t _id_alloc = 0; @@ -80,8 +77,8 @@ const char LOG_LEVEL_LEVEL_CODE[LOG_LEVEL_MAX] = { }; const char* LOG_LEVEL_COLOR_CODE[LOG_LEVEL_MAX] = { - "31", //! FATAL 红 - "7;91", //! ERROR 文字黑,背景亮红 + "7;91", //! FATAL 文字黑,背景亮红 + "31", //! ERROR 红 "7;93", //! WARN 文字黑,背景亮黄 "93", //! NOTICE 亮黄 "7;92", //! IMPORTANT 文字黑,背景亮绿 @@ -90,6 +87,16 @@ const char* LOG_LEVEL_COLOR_CODE[LOG_LEVEL_MAX] = { "35", //! TRACE 洋葱红 }; +extern "C" { + +size_t LogSetMaxLength(size_t max_len) +{ + std::lock_guard lg(_lock); + auto origin_len = _LogTextMaxLength; + _LogTextMaxLength = max_len; + return origin_len; +} + /** * \brief 日志格式化打印接口的实现 * @@ -124,12 +131,12 @@ void LogPrintfFunc(const char *module_id, const char *func_name, const char *fil .level = level, .text_len = 0, .text_ptr = nullptr, + .text_trunc = false, }; if (fmt != nullptr) { if (with_args) { - uint32_t buff_size = 1024; //! 初始大小,可应对绝大数情况 - bool is_need_trunc = false; //! 是否过长需要截断 + uint32_t buff_size = std::min(2048lu, _LogTextMaxLength) + 1; for (;;) { va_list args; @@ -138,14 +145,10 @@ void LogPrintfFunc(const char *module_id, const char *func_name, const char *fil va_start(args, fmt); size_t len = 0; - if (!is_need_trunc) { //! 如果不需要截断 - len = ::vsnprintf(buffer, buff_size, fmt, args); + len = ::vsnprintf(buffer, buff_size, fmt, args); - } else { //! 如果需要截断处理 - ::vsnprintf(buffer, kTruncatedLength + 1, fmt, args); - ::strcpy(buffer + kTruncatedLength, kTruncTipText); - len = kTruncatedLength + kTruncTipLen; - } + if (content.text_trunc) + len = _LogTextMaxLength; va_end(args); @@ -159,24 +162,35 @@ void LogPrintfFunc(const char *module_id, const char *func_name, const char *fil } //! 没有超过MaxLength,则进行扩张 - if (len <= kLogTextMaxLength) { + if (len <= _LogTextMaxLength) { buff_size = len + 1; //! 要多留一个结束符 \0,否则 vsnprintf() 会少一个字符 } else { //! 否则进行截断处理 - is_need_trunc = true; - buff_size = kTruncatedLength + kTruncTipLen + 1; + buff_size = _LogTextMaxLength + 1; //! 同上 + content.text_trunc = true; } } + } else { content.text_len = ::strlen(fmt); + + //! 如果超出最大长度,要限制 + if (content.text_len > _LogTextMaxLength) { + content.text_len = _LogTextMaxLength; + content.text_trunc = true; + } + content.text_ptr = fmt; Dispatch(content); } + } else { Dispatch(content); } } +} + uint32_t LogAddPrintfFunc(LogPrintfFuncType func, void *ptr) { std::lock_guard lg(_lock); diff --git a/modules/base/log_imp.h b/modules/base/log_impl.h similarity index 88% rename from modules/base/log_imp.h rename to modules/base/log_impl.h index 65e8142..e0298a5 100644 --- a/modules/base/log_imp.h +++ b/modules/base/log_impl.h @@ -17,8 +17,8 @@ * project authors may be found in the CONTRIBUTORS.md file in the root * of the source tree. */ -#ifndef TBOX_BASE_LOG_IMP_20180201 -#define TBOX_BASE_LOG_IMP_20180201 +#ifndef TBOX_BASE_LOG_IMPL_20180201 +#define TBOX_BASE_LOG_IMPL_20180201 /** * 本文件只声明了函数 LogSetPrintfFunc() 该函数用于指定日志输出函数 @@ -27,6 +27,7 @@ #include #include +#include #include "log.h" @@ -49,6 +50,7 @@ struct LogContent { int level; //!< 日志等级 uint32_t text_len; //!< 内容大小 const char *text_ptr; //!< 内容地址 + bool text_trunc; //!< 是否截断 }; //! 日志等级颜色表 @@ -58,6 +60,9 @@ extern const char* LOG_LEVEL_COLOR_CODE[LOG_LEVEL_MAX]; //! 定义日志输出函数 typedef void (*LogPrintfFuncType)(const LogContent *content, void *ptr); +//! 设置最大长度 +size_t LogSetMaxLength(size_t max_len); + //! 添加与删除日志输出函数 uint32_t LogAddPrintfFunc(LogPrintfFuncType func, void *ptr); bool LogRemovePrintfFunc(uint32_t id); @@ -66,4 +71,4 @@ bool LogRemovePrintfFunc(uint32_t id); } #endif -#endif //TBOX_BASE_LOG_IMP_20180201 +#endif //TBOX_BASE_LOG_IMPL_20180201 diff --git a/modules/base/log_output.cpp b/modules/base/log_output.cpp index 8d783af..b557a64 100644 --- a/modules/base/log_output.cpp +++ b/modules/base/log_output.cpp @@ -30,7 +30,7 @@ #include #include -#include "log_imp.h" +#include "log_impl.h" #define TIMESTAMP_STRING_SIZE 27 @@ -64,7 +64,10 @@ namespace { printf("%s() ", content->func_name); if (content->text_len > 0) - printf("%s ", content->text_ptr); + printf("%.*s ", content->text_len, content->text_ptr); + + if (content->text_trunc == 1) + printf("(TRUNCATED) "); if (content->file_name != nullptr) printf("-- %s:%d", content->file_name, content->line); diff --git a/modules/base/log_output_test.cpp b/modules/base/log_output_test.cpp index dc38d87..73b98f1 100644 --- a/modules/base/log_output_test.cpp +++ b/modules/base/log_output_test.cpp @@ -19,6 +19,7 @@ */ #include #include "log.h" +#include "log_impl.h" #include "log_output.h" TEST(Log, AllLevel) @@ -60,3 +61,21 @@ TEST(Log, error) LogErrno(1, "has value:%d", 123); LogOutput_Disable(); } + +TEST(Log, Truncate) +{ + LogOutput_Enable(); + + std::string long_str(1025, 'l'); + std::string normal_str(1024, 'n'); + + auto origin_len = LogSetMaxLength(1024); + + LogInfo(normal_str.c_str()); + LogNotice(long_str.c_str()); + LogInfo("%s", normal_str.c_str()); + LogNotice("%s", long_str.c_str()); + + LogSetMaxLength(origin_len); + LogOutput_Disable(); +} diff --git a/modules/log/async_file_sink.cpp b/modules/log/async_file_sink.cpp index 05af554..74caf5d 100644 --- a/modules/log/async_file_sink.cpp +++ b/modules/log/async_file_sink.cpp @@ -91,30 +91,28 @@ void AsyncFileSink::updateInnerValues() CHECK_CLOSE_RESET_FD(fd_); } -void AsyncFileSink::appendLog(const char *str, size_t len) +void AsyncFileSink::endline() { - buffer_.reserve(buffer_.size() + len - 1); - std::back_insert_iterator> back_insert_iter(buffer_); - std::copy(str, str + len - 1, back_insert_iter); + cache_.push_back('\n'); } -void AsyncFileSink::flushLog() +void AsyncFileSink::flush() { if (pid_ == 0 || !checkAndCreateLogFile()) return; - auto wsize = ::write(fd_, buffer_.data(), buffer_.size()); - if (wsize != static_cast(buffer_.size())) { + auto wsize = ::write(fd_, cache_.data(), cache_.size()); + if (wsize != static_cast(cache_.size())) { cerr << "Err: write file error." << endl; return; } - total_write_size_ += buffer_.size(); - - buffer_.clear(); + total_write_size_ += cache_.size(); if (total_write_size_ >= file_max_size_) CHECK_CLOSE_RESET_FD(fd_); + + cache_.clear(); } bool AsyncFileSink::checkAndCreateLogFile() diff --git a/modules/log/async_file_sink.h b/modules/log/async_file_sink.h index b377a5e..2ae1b17 100644 --- a/modules/log/async_file_sink.h +++ b/modules/log/async_file_sink.h @@ -44,8 +44,8 @@ class AsyncFileSink : public AsyncSink { protected: void updateInnerValues(); - virtual void appendLog(const char *str, size_t len) override; - virtual void flushLog() override; + virtual void endline() override; + virtual void flush() override; bool checkAndCreateLogFile(); diff --git a/modules/log/async_file_sink_test.cpp b/modules/log/async_file_sink_test.cpp index fc78f92..3f0984a 100644 --- a/modules/log/async_file_sink_test.cpp +++ b/modules/log/async_file_sink_test.cpp @@ -66,25 +66,6 @@ TEST(AsyncFileSink, AllLevel) ch.cleanup(); } -TEST(AsyncFileSink, LongString) -{ - AsyncFileSink ch; - - ch.setFilePath("/tmp/tbox"); - ch.setFilePrefix("test"); - ch.enable(); - - for (size_t s = 900; s < 1200; ++s) { - std::string tmp(s, 'z'); - LogInfo("%s", tmp.c_str()); - } - - std::string tmp(4096, 'x'); - LogInfo("%s", tmp.c_str()); - - ch.cleanup(); -} - TEST(AsyncFileSink, FileDivide) { AsyncFileSink ch; @@ -116,28 +97,34 @@ TEST(AsyncFileSink, ParamNormalize) ch.cleanup(); } -TEST(AsyncFileSink, CreateFileInInit) +TEST(AsyncFileSink, RemoveLogFileDuringWriting) { AsyncFileSink ch; ch.setFilePath("/tmp/tbox"); - ch.setFilePrefix("create_file_init"); + ch.setFilePrefix("remove_log_file_during_writing"); ch.enable(); - std::string name = ch.currentFilename(); - EXPECT_TRUE(util::fs::IsFileExist(name)); + util::fs::RemoveFile(ch.currentFilename()); + LogInfo("Hello"); + std::this_thread::sleep_for(std::chrono::seconds(1)); + EXPECT_TRUE(util::fs::IsFileExist(ch.currentFilename())); ch.cleanup(); } -TEST(AsyncFileSink, RemoveLogFileDuringWriting) +TEST(AsyncFileSink, Truncate) { + auto origin_len = LogSetMaxLength(100); + AsyncFileSink ch; ch.setFilePath("/tmp/tbox"); - ch.setFilePrefix("remove_log_file_during_writing"); + ch.setFilePrefix("truncate"); ch.enable(); util::fs::RemoveFile(ch.currentFilename()); - LogInfo("Hello"); - std::this_thread::sleep_for(std::chrono::seconds(1)); - EXPECT_TRUE(util::fs::IsFileExist(ch.currentFilename())); + + std::string tmp(200, 'x'); + LogInfo("%s", tmp.c_str()); + ch.cleanup(); + LogSetMaxLength(origin_len); } #include @@ -157,10 +144,10 @@ TEST(AsyncFileSink, Benchmark) function func = [&] { for (int i = 0; i < 100; ++i) LogInfo("%d %s", i, tmp.c_str()); - sp_loop->run(func); + sp_loop->runNext(func); counter += 100; }; - sp_loop->run(func); + sp_loop->runNext(func); sp_loop->exitLoop(chrono::seconds(10)); sp_loop->runLoop(); diff --git a/modules/log/async_sink.cpp b/modules/log/async_sink.cpp index 5f58a52..0d3ccde 100644 --- a/modules/log/async_sink.cpp +++ b/modules/log/async_sink.cpp @@ -24,8 +24,6 @@ #include #include -constexpr uint32_t LOG_MAX_LEN = (100 << 10); //! 限定单条日志最大长度 - namespace tbox { namespace log { @@ -83,7 +81,7 @@ void AsyncSink::onLogBackEndReadPipe(const void *data_ptr, size_t data_size) } if (is_need_flush) - flushLog(); + flush(); auto time_cost = std::chrono::steady_clock::now() - start_ts; if (time_cost > std::chrono::milliseconds(500)) @@ -92,85 +90,61 @@ void AsyncSink::onLogBackEndReadPipe(const void *data_ptr, size_t data_size) void AsyncSink::onLogBackEnd(const LogContent &content) { - size_t buff_size = 1024; //! 初始大小,可应对绝大数情况 + char buff[1024]; + size_t len = 0; udpateTimestampStr(content.timestamp.sec); - //! 加循环为了应对缓冲不够的情况 - for (;;) { - char buff[buff_size]; - size_t pos = 0; - -#define REMAIN_SIZE ((buff_size > pos) ? (buff_size - pos) : 0) -#define WRITE_PTR (buff + pos) - - size_t len = 0; - - //! 开启色彩,显示日志等级 - if (enable_color_) { - len = snprintf(WRITE_PTR, REMAIN_SIZE, "\033[%sm", LOG_LEVEL_COLOR_CODE[content.level]); - pos += len; - } - - //! 打印等级、时间戳、线程号、模块名 - len = snprintf(WRITE_PTR, REMAIN_SIZE, "%c %s.%06u %ld %s ", - LOG_LEVEL_LEVEL_CODE[content.level], - timestamp_str_, content.timestamp.usec, - content.thread_id, content.module_id); - pos += len; - - if (content.func_name != nullptr) { - len = snprintf(WRITE_PTR, REMAIN_SIZE, "%s() ", content.func_name); - pos += len; - } + //! 开启色彩,显示日志等级 + if (enable_color_) { + len = snprintf(buff, sizeof(buff), "\033[%sm", LOG_LEVEL_COLOR_CODE[content.level]); + append(buff, len); + } - if (content.text_len > 0) { - if (REMAIN_SIZE >= content.text_len) - memcpy(WRITE_PTR, content.text_ptr, content.text_len); - pos += content.text_len; + //! 打印等级、时间戳、线程号、模块名 + len = snprintf(buff, sizeof(buff), "%c %s.%06u %ld %s ", + LOG_LEVEL_LEVEL_CODE[content.level], + timestamp_str_, content.timestamp.usec, + content.thread_id, content.module_id); + append(buff, len); - if (REMAIN_SIZE >= 1) //! 追加一个空格 - *WRITE_PTR = ' '; - ++pos; - } + if (content.func_name != nullptr) { + len = snprintf(buff, sizeof(buff), "%s() ", content.func_name); + append(buff, len); + } - if (content.file_name != nullptr) { - len = snprintf(WRITE_PTR, REMAIN_SIZE, "-- %s:%d", content.file_name, content.line); - pos += len; - } + if (content.text_len > 0) { + append(content.text_ptr, content.text_len); + append(' '); //! 追加空格 - if (enable_color_) { - if (REMAIN_SIZE >= 4) - memcpy(WRITE_PTR, "\033[0m", 4); - pos += 4; + if (content.text_trunc) { + const char *tip = "(TRUNCATED) "; + append(tip, ::strlen(tip)); } + } - if (REMAIN_SIZE >= 2) { - *WRITE_PTR = '\n'; //! 追加结束符 - ++pos; - *WRITE_PTR = '\0'; //! 追加结束符 - ++pos; - } else { - pos += 2; - } + if (content.file_name != nullptr) { + len = snprintf(buff, sizeof(buff), "-- %s:%d", content.file_name, content.line); + append(buff, len); + } -#undef REMAIN_SIZE -#undef WRITE_PTR + if (enable_color_) { + append("\033[0m", 4); + } - //! 如果缓冲区是够用的,就完成 - if (pos <= buff_size) { - appendLog(buff, pos); - break; - } + endline(); +} - //! 否则扩展缓冲区,重来 - buff_size = pos; +void AsyncSink::append(const char *str, size_t len) +{ + cache_.reserve(cache_.size() + len); + std::back_insert_iterator> back_insert_iter(cache_); + std::copy(str, str + len, back_insert_iter); +} - if (buff_size > LOG_MAX_LEN) { - std::cerr << "WARN: log length " << buff_size << ", too long!" << std::endl; - break; - } - } +void AsyncSink::append(char ch) +{ + cache_.push_back(ch); } } diff --git a/modules/log/async_sink.h b/modules/log/async_sink.h index 35877c6..70bcad2 100644 --- a/modules/log/async_sink.h +++ b/modules/log/async_sink.h @@ -22,6 +22,8 @@ #include "sink.h" +#include + #include #include @@ -42,8 +44,15 @@ class AsyncSink : public Sink { virtual void onLogFrontEnd(const LogContent *content) override; void onLogBackEndReadPipe(const void *data_ptr, size_t data_size); void onLogBackEnd(const LogContent &content); - virtual void appendLog(const char *str, size_t len) = 0; - virtual void flushLog() { } + + void append(const char *str, size_t len); + void append(char ch); + + virtual void endline() = 0; + virtual void flush() = 0; + + protected: + std::vector cache_; private: Config cfg_; diff --git a/modules/log/async_sink_test.cpp b/modules/log/async_sink_test.cpp index 707f4bf..792fd47 100644 --- a/modules/log/async_sink_test.cpp +++ b/modules/log/async_sink_test.cpp @@ -19,6 +19,8 @@ */ #include +#include + #include #include #include @@ -30,15 +32,21 @@ using namespace tbox::log; class TestAsyncSink : public AsyncSink { protected: - virtual void appendLog(const char *str, size_t len) { - cout << str << endl; - (void)len; + virtual void endline() { + cache_.push_back('\n'); + } + + virtual void flush() override { + auto wsize = ::write(STDOUT_FILENO, cache_.data(), cache_.size()); //! 写到终端 + (void)wsize; //! 消除警告用 + cache_.clear(); } }; class EmptyTestAsyncSink : public AsyncSink { protected: - virtual void appendLog(const char *str, size_t len) { (void)str; (void)len; } + virtual void endline() { } + virtual void flush() override { cache_.clear(); } }; @@ -76,15 +84,17 @@ TEST(AsyncSink, AllLevel) ch.cleanup(); } - -TEST(AsyncSink, LongString) +TEST(AsyncSink, Truncate) { - TestAsyncSink ch; + auto origin_len = LogSetMaxLength(100); + TestAsyncSink ch; ch.enable(); - std::string tmp(4096, 'x'); + + std::string tmp(200, 'x'); LogInfo("%s", tmp.c_str()); + LogSetMaxLength(origin_len); ch.cleanup(); } @@ -103,17 +113,17 @@ TEST(AsyncSink, Benchmark) function func = [&] { for (int i = 0; i < 100; ++i) LogInfo("%d %s", i, tmp.c_str()); - sp_loop->runInLoop(func); + sp_loop->runNext(func); counter += 100; }; - sp_loop->runInLoop(func); + sp_loop->runNext(func); sp_loop->exitLoop(chrono::seconds(10)); sp_loop->runLoop(); delete sp_loop; - cout << "count in sec: " << counter/10 << endl; ch.cleanup(); + cout << "count in sec: " << counter/10 << endl; } TEST(AsyncSink, Benchmark_Empty) @@ -128,16 +138,16 @@ TEST(AsyncSink, Benchmark_Empty) function func = [&] { for (int i = 0; i < 100; ++i) LogInfo("%d %s", i, tmp.c_str()); - sp_loop->run(func); + sp_loop->runNext(func); counter += 100; }; - sp_loop->run(func); + sp_loop->runNext(func); sp_loop->exitLoop(chrono::seconds(10)); sp_loop->runLoop(); delete sp_loop; - cout << "count in sec: " << counter/10 << endl; ch.cleanup(); + cout << "count in sec: " << counter/10 << endl; } diff --git a/modules/log/async_stdout_sink.cpp b/modules/log/async_stdout_sink.cpp index 38c0593..88e4af3 100644 --- a/modules/log/async_stdout_sink.cpp +++ b/modules/log/async_stdout_sink.cpp @@ -20,7 +20,6 @@ #include "async_stdout_sink.h" #include -#include namespace tbox { namespace log { @@ -36,21 +35,17 @@ AsyncStdoutSink::AsyncStdoutSink() setConfig(cfg); } -void AsyncStdoutSink::appendLog(const char *str, size_t len) +void AsyncStdoutSink::endline() { - buffer_.reserve(buffer_.size() + len - 1); - std::back_insert_iterator> back_insert_iter(buffer_); - std::copy(str, str + len - 1, back_insert_iter); + cache_.push_back('\n'); } -void AsyncStdoutSink::flushLog() +void AsyncStdoutSink::flush() { - auto wsize = ::write(STDOUT_FILENO, buffer_.data(), buffer_.size()); //! 写到终端 + auto wsize = ::write(STDOUT_FILENO, cache_.data(), cache_.size()); //! 写到终端 (void)wsize; //! 消除警告用 - buffer_.clear(); - if (buffer_.capacity() > 1024) - buffer_.shrink_to_fit(); + cache_.clear(); } } diff --git a/modules/log/async_stdout_sink.h b/modules/log/async_stdout_sink.h index bfd7ba7..299f745 100644 --- a/modules/log/async_stdout_sink.h +++ b/modules/log/async_stdout_sink.h @@ -32,8 +32,8 @@ class AsyncStdoutSink : public AsyncSink { AsyncStdoutSink(); protected: - virtual void appendLog(const char *str, size_t len) override; - virtual void flushLog() override; + virtual void endline() override; + virtual void flush() override; private: std::vector buffer_; diff --git a/modules/log/async_stdout_sink_test.cpp b/modules/log/async_stdout_sink_test.cpp index 1abba1c..7094f94 100644 --- a/modules/log/async_stdout_sink_test.cpp +++ b/modules/log/async_stdout_sink_test.cpp @@ -149,13 +149,17 @@ TEST(AsyncStdoutSink, Format) ch.cleanup(); } -TEST(AsyncStdoutSink, LongString) +TEST(AsyncStdoutSink, Truncate) { + auto origin_len = LogSetMaxLength(100); + AsyncStdoutSink ch; ch.enable(); - std::string tmp(4096, 'x'); + std::string tmp(200, 'x'); LogInfo("%s", tmp.c_str()); + ch.cleanup(); + LogSetMaxLength(origin_len); } #include @@ -173,10 +177,10 @@ TEST(AsyncStdoutSink, Benchmark) function func = [&] { for (int i = 0; i < 100; ++i) LogInfo("%d %s", i, tmp.c_str()); - sp_loop->run(func); + sp_loop->runNext(func); counter += 100; }; - sp_loop->run(func); + sp_loop->runNext(func); sp_loop->exitLoop(chrono::seconds(10)); sp_loop->runLoop(); @@ -186,3 +190,4 @@ TEST(AsyncStdoutSink, Benchmark) cout << "count in sec: " << counter/10 << endl; } + diff --git a/modules/log/async_syslog_sink.cpp b/modules/log/async_syslog_sink.cpp index e58a175..6a55db4 100644 --- a/modules/log/async_syslog_sink.cpp +++ b/modules/log/async_syslog_sink.cpp @@ -34,10 +34,12 @@ AsyncSyslogSink::AsyncSyslogSink() setConfig(cfg); } -void AsyncSyslogSink::appendLog(const char *str, size_t len) +void AsyncSyslogSink::endline() { - syslog(LOG_INFO, "%s", str); - (void)len; + cache_.push_back('\0'); + ::syslog(LOG_INFO, "%s", cache_.data()); + + cache_.clear(); } } diff --git a/modules/log/async_syslog_sink.h b/modules/log/async_syslog_sink.h index e4299a1..9533d70 100644 --- a/modules/log/async_syslog_sink.h +++ b/modules/log/async_syslog_sink.h @@ -30,7 +30,8 @@ class AsyncSyslogSink : public AsyncSink { AsyncSyslogSink(); protected: - virtual void appendLog(const char *str, size_t len) override; + virtual void endline() override; + virtual void flush() override { } }; } diff --git a/modules/log/async_syslog_sink_test.cpp b/modules/log/async_syslog_sink_test.cpp index 3fdb645..9e57a3d 100644 --- a/modules/log/async_syslog_sink_test.cpp +++ b/modules/log/async_syslog_sink_test.cpp @@ -94,14 +94,18 @@ TEST(AsyncSyslogSink, Format) ch.cleanup(); } -TEST(AsyncSyslogSink, LongString) +TEST(AsyncSyslogSink, Truncate) { + auto origin_len = LogSetMaxLength(100); + AsyncSyslogSink ch; ch.enable(); - std::string tmp(4096, 'x'); + + std::string tmp(200, 'x'); LogInfo("%s", tmp.c_str()); ch.cleanup(); + LogSetMaxLength(origin_len); } #include @@ -119,10 +123,10 @@ TEST(AsyncSyslogSink, Benchmark) function func = [&] { for (int i = 0; i < 100; ++i) LogInfo("%d %s", i, tmp.c_str()); - sp_loop->run(func); + sp_loop->runNext(func); counter += 100; }; - sp_loop->run(func); + sp_loop->runNext(func); sp_loop->exitLoop(chrono::seconds(10)); sp_loop->runLoop(); diff --git a/modules/log/sink.h b/modules/log/sink.h index a3c039e..6aca2f7 100644 --- a/modules/log/sink.h +++ b/modules/log/sink.h @@ -24,9 +24,9 @@ #include #include #include -#include +#include -#define TIMESTAMP_STRING_SIZE 20 +#define TIMESTAMP_STRING_SIZE 20 namespace tbox { namespace log { diff --git a/modules/log/sync_stdout_sink.cpp b/modules/log/sync_stdout_sink.cpp index f4e53cb..ee60619 100644 --- a/modules/log/sync_stdout_sink.cpp +++ b/modules/log/sync_stdout_sink.cpp @@ -42,13 +42,18 @@ void SyncStdoutSink::onLogFrontEnd(const LogContent *content) printf("%s() ", content->func_name); if (content->text_len > 0) - printf("%s ", content->text_ptr); + printf("%.*s ", content->text_len, content->text_ptr); + + if (content->text_trunc) + printf("(TRUNCATED) "); if (content->file_name != nullptr) printf("-- %s:%d", content->file_name, content->line); if (enable_color_) puts("\033[0m"); //! 恢复色彩 + else + putchar('\n'); } } diff --git a/modules/log/sync_stdout_sink_test.cpp b/modules/log/sync_stdout_sink_test.cpp index cb84794..667a728 100644 --- a/modules/log/sync_stdout_sink_test.cpp +++ b/modules/log/sync_stdout_sink_test.cpp @@ -134,10 +134,44 @@ TEST(SyncStdoutSink, Format) LogInfo("%d, %f, %s", 123456, 12.345, "world"); } -TEST(SyncStdoutSink, LongString) +TEST(SyncStdoutSink, Truncate) { + auto origin_len = LogSetMaxLength(100); + SyncStdoutSink ch; ch.enable(); - std::string tmp(4096, 'x'); + std::string tmp(200, 'x'); LogInfo("%s", tmp.c_str()); + + LogSetMaxLength(origin_len); } + +#include +using namespace tbox::event; + +TEST(SyncStdoutSink, Benchmark) +{ + SyncStdoutSink ch; + ch.enable(); + + std::string tmp(30, 'x'); + + auto sp_loop = Loop::New(); + + int counter = 0; + function func = [&] { + for (int i = 0; i < 100; ++i) + LogInfo("%d %s", i, tmp.c_str()); + sp_loop->runNext(func); + counter += 100; + }; + sp_loop->runNext(func); + + sp_loop->exitLoop(chrono::seconds(10)); + sp_loop->runLoop(); + + delete sp_loop; + + cout << "count in sec: " << counter/10 << endl; +} + diff --git a/version.mk b/version.mk index 664877b..8b7a552 100644 --- a/version.mk +++ b/version.mk @@ -21,4 +21,4 @@ # TBOX版本号 TBOX_VERSION_MAJOR := 1 TBOX_VERSION_MINOR := 11 -TBOX_VERSION_REVISION := 12 +TBOX_VERSION_REVISION := 13 -- Gitee From 95c58ad4d064c7e2afb10e090669f6dd73907d0d Mon Sep 17 00:00:00 2001 From: Hevake Lee Date: Wed, 12 Feb 2025 01:30:27 +0800 Subject: [PATCH 4/4] =?UTF-8?q?feat(main):1.11.14,=20=E4=B8=BAmain?= =?UTF-8?q?=E6=A1=86=E6=9E=B6=E6=B7=BB=E5=8A=A0log.max=5Flen=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=9B=E5=90=8C=E6=97=B6=E6=B7=BB=E5=8A=A0/log/max?= =?UTF-8?q?=5Flen=E7=BB=88=E7=AB=AF=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/base/log_impl.cpp | 6 ++++++ modules/base/log_impl.h | 2 ++ modules/main/log.cpp | 23 +++++++++++++++++++++++ version.mk | 2 +- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/modules/base/log_impl.cpp b/modules/base/log_impl.cpp index 4797674..422491d 100644 --- a/modules/base/log_impl.cpp +++ b/modules/base/log_impl.cpp @@ -97,6 +97,12 @@ size_t LogSetMaxLength(size_t max_len) return origin_len; } +size_t LogGetMaxLength() +{ + std::lock_guard lg(_lock); + return _LogTextMaxLength; +} + /** * \brief 日志格式化打印接口的实现 * diff --git a/modules/base/log_impl.h b/modules/base/log_impl.h index e0298a5..8955222 100644 --- a/modules/base/log_impl.h +++ b/modules/base/log_impl.h @@ -62,6 +62,8 @@ typedef void (*LogPrintfFuncType)(const LogContent *content, void *ptr); //! 设置最大长度 size_t LogSetMaxLength(size_t max_len); +//! 获取最大长度 +size_t LogGetMaxLength(); //! 添加与删除日志输出函数 uint32_t LogAddPrintfFunc(LogPrintfFuncType func, void *ptr); diff --git a/modules/main/log.cpp b/modules/main/log.cpp index 8d52469..6370621 100644 --- a/modules/main/log.cpp +++ b/modules/main/log.cpp @@ -62,6 +62,12 @@ bool Log::initialize(const char *proc_name, Context &ctx, const Json &cfg) if (util::json::HasObjectField(cfg, "log")) { auto &js_log = cfg.at("log"); + + int max_len = 0; + if (util::json::GetField(js_log, "max_len", max_len) && max_len > 0) { + LogSetMaxLength(static_cast(max_len)); + } + //! STDOUT if (util::json::HasObjectField(js_log, "stdout")) { auto &js_stdout = js_log.at("stdout"); @@ -152,6 +158,23 @@ void Log::initShell(TerminalNodes &term) initShellForSink(async_file_sink_, term, dir_node); initShellForAsyncFileSink(term, dir_node); } + + { + terminal::IntegerFuncNodeProfile profile; + profile.set_func = \ + [] (int max_len) { + if (max_len > 0) { + LogSetMaxLength(static_cast(max_len)); + return true; + } + return false; + }; + profile.get_func = [] { return LogGetMaxLength(); }; + profile.usage = "Usage: max_len # get max len, unit:byte\r\n" + " max_len # set max len, len>0\r\n"; + profile.help = "get or set log maxmum length"; + terminal::AddFuncNode(term, log_node, "max_len", profile); + } } void Log::initShellForSink(log::Sink &log_ch, terminal::TerminalNodes &term, terminal::NodeToken dir_node) diff --git a/version.mk b/version.mk index 8b7a552..8a84836 100644 --- a/version.mk +++ b/version.mk @@ -21,4 +21,4 @@ # TBOX版本号 TBOX_VERSION_MAJOR := 1 TBOX_VERSION_MINOR := 11 -TBOX_VERSION_REVISION := 13 +TBOX_VERSION_REVISION := 14 -- Gitee