diff --git a/modules/base/CMakeLists.txt b/modules/base/CMakeLists.txt index b1b39cc75bc498e6bf47440708b22f21cdfa7378..4494fa508a863348dd98f1fa9931defe7cd41494 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 ec799aa8a620a29145457c59c923f4736141d1dd..59a99b11df20a1cbf60eb372c4b895ae50b7030c 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 73% rename from modules/base/log_imp.cpp rename to modules/base/log_impl.cpp index c563461ea9e292adc0dff51f15021b46b4bb0234..422491ddb14cbd7bcabd9397c7c268c9159b06cc 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 @@ -29,7 +29,8 @@ #include namespace { -constexpr uint32_t LOG_MAX_LEN = (100 << 10); + +size_t _LogTextMaxLength = (100 << 10); //! 限定单条日志最大长度,默认为100KB std::mutex _lock; uint32_t _id_alloc = 0; @@ -76,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 文字黑,背景亮绿 @@ -86,6 +87,22 @@ 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; +} + +size_t LogGetMaxLength() +{ + std::lock_guard lg(_lock); + return _LogTextMaxLength; +} + /** * \brief 日志格式化打印接口的实现 * @@ -120,19 +137,29 @@ 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; //! 初始大小,可应对绝大数情况 + uint32_t buff_size = std::min(2048lu, _LogTextMaxLength) + 1; + 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; + + len = ::vsnprintf(buffer, buff_size, fmt, args); + + if (content.text_trunc) + len = _LogTextMaxLength; + va_end(args); + //! 如果buffer的空间够用,则正常派发日志 + //! 否则要对buffer空间进行扩张,或是对内容进行截断 if (len < buff_size) { content.text_len = len; content.text_ptr = buffer; @@ -140,22 +167,36 @@ void LogPrintfFunc(const char *module_id, const char *func_name, const char *fil 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 <= _LogTextMaxLength) { + buff_size = len + 1; //! 要多留一个结束符 \0,否则 vsnprintf() 会少一个字符 + + } else { //! 否则进行截断处理 + 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 86% rename from modules/base/log_imp.h rename to modules/base/log_impl.h index 65e81420091a0090da45a37621db4b1789ab5924..8955222c4ad82dee2541fdc6151d17e3c92cc979 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,11 @@ 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); +//! 获取最大长度 +size_t LogGetMaxLength(); + //! 添加与删除日志输出函数 uint32_t LogAddPrintfFunc(LogPrintfFuncType func, void *ptr); bool LogRemovePrintfFunc(uint32_t id); @@ -66,4 +73,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 8d783af3e2bc4dd823c0532183b1361b1f10f25d..b557a644c7d0af8a2f19cbcb03ba29ca00370f8c 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 dc38d87dc866267eb43c65edbf54496e81d46843..73b98f11ad15e8fc1fef677d894cbdc7ac93a077 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 05af5540da3a57cb861bf455ceb2937a192405f0..74caf5d1c545c3b7f0d82fe6a8007496fc502901 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 b377a5e51760f4a1308448c06819175f4f4544f5..2ae1b17dc24caa42dda46b4cd64d8a339a433bbb 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 fc78f924c3a22f8e5e64b37d11bb87c07548115d..3f0984aa7d24b4fd760e959f8e646fbd840ec306 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 5f58a521e83b1215de78e9faa2e9a241bd039813..0d3ccde37f3dd3242024d781c97195a29b66836d 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 35877c60d5861566083477463b4c092021d4ef59..70bcad22ad45b08b29fb75199dbd809edddbc71d 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 707f4bf15a7bb1b606216ac8ea06affe474662a0..792fd47b42dcf17cf791fe0ca9441a3aa2aa84e1 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 38c05937b2588fb0976d59f1416b03135f50bd4c..88e4af3145698aeb92d00b645e7f7e9e9905d102 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 bfd7ba701b759e5c488956d8faea797a41161924..299f7452068665574401c1a286ac41b8bf221d58 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 1abba1c8a76c803e301d50dddaf68de26e423ebd..7094f9418ba26971d2f5e9f9584cbbf458874339 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 e58a175c1611e27013dc6e94c6ad55d0b6892dc8..6a55db4744f6f43b836db029490dbc788f677f09 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 e4299a15f190307a0341b69a2dcbfd471b06c46a..9533d70472d9d896ae4c4d888d7aa0e452e2528e 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 3fdb6457aee0cc850a40b82ec3514a218fd3b879..9e57a3da1bce6c89351a7387bd85e26783f5007f 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 a3c039eb90bcd5f5a9e07403bee8918b376aa866..6aca2f7c690f8fc33656f654bec1fa59ac049ec0 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 f4e53cbd30821427fdf646033ba68dbaef7a9bf2..ee60619098b17a3d88fb28828f68a91497667827 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 cb84794eef0f8f7cb7987a617cf5b8cc753cd992..667a7285944c6351f4c83fece5304cc0e08de18f 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/modules/main/log.cpp b/modules/main/log.cpp index 8d52469e544d314e187f34e60ea24ec474582762..63706212f4291e6bc3b8ad2559b80d0b19c96981 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 664877b83e489c129452826794bc0d6a797540f0..8a84836fe1d4d82fc201f7c18a378bfd8e54bd84 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 := 14