diff options
author | Jonas Devlieghere <jonas@devlieghere.com> | 2024-05-03 11:08:50 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-03 11:08:50 -0700 |
commit | a8fbe500fe2ecdbd3c09ed06788092937819411f (patch) | |
tree | 9da5d7cc527dc71e902a7c7ce4cb004058c66736 | |
parent | e2b3e4ea9f2d0cb34d197439cfbc5090cdacb124 (diff) |
[lldb] Add TeeLogHandler to log to 2 handlers (#90984)
Add a T-style log handler that multiplexes messages to two log handlers.
The goal is to use this in combination with the SystemLogHandler to log
messages both to the user requested file as well as the system log. The
latter is part of a sysdiagnose on Darwin which is commonly attached to
bug reports.
-rw-r--r-- | lldb/include/lldb/Utility/Log.h | 17 | ||||
-rw-r--r-- | lldb/source/Utility/Log.cpp | 14 | ||||
-rw-r--r-- | lldb/unittests/Utility/LogTest.cpp | 12 |
3 files changed, 43 insertions, 0 deletions
diff --git a/lldb/include/lldb/Utility/Log.h b/lldb/include/lldb/Utility/Log.h index 01876ad732d4..27707c17f9b8 100644 --- a/lldb/include/lldb/Utility/Log.h +++ b/lldb/include/lldb/Utility/Log.h @@ -112,6 +112,23 @@ private: static char ID; }; +/// A T-style log handler that multiplexes messages to two log handlers. +class TeeLogHandler : public LogHandler { +public: + TeeLogHandler(std::shared_ptr<LogHandler> first_log_handler, + std::shared_ptr<LogHandler> second_log_handler); + + void Emit(llvm::StringRef message) override; + + bool isA(const void *ClassID) const override { return ClassID == &ID; } + static bool classof(const LogHandler *obj) { return obj->isA(&ID); } + +private: + std::shared_ptr<LogHandler> m_first_log_handler; + std::shared_ptr<LogHandler> m_second_log_handler; + static char ID; +}; + class Log final { public: /// The underlying type of all log channel enums. Declare them as: diff --git a/lldb/source/Utility/Log.cpp b/lldb/source/Utility/Log.cpp index 3a45a0285d3e..6713a5bd7582 100644 --- a/lldb/source/Utility/Log.cpp +++ b/lldb/source/Utility/Log.cpp @@ -39,6 +39,7 @@ char LogHandler::ID; char StreamLogHandler::ID; char CallbackLogHandler::ID; char RotatingLogHandler::ID; +char TeeLogHandler::ID; llvm::ManagedStatic<Log::ChannelMap> Log::g_channel_map; @@ -438,3 +439,16 @@ void RotatingLogHandler::Dump(llvm::raw_ostream &stream) const { } stream.flush(); } + +TeeLogHandler::TeeLogHandler(std::shared_ptr<LogHandler> first_log_handler, + std::shared_ptr<LogHandler> second_log_handler) + : m_first_log_handler(first_log_handler), + m_second_log_handler(second_log_handler) { + assert(m_first_log_handler && "first log handler must be valid"); + assert(m_second_log_handler && "second log handler must be valid"); +} + +void TeeLogHandler::Emit(llvm::StringRef message) { + m_first_log_handler->Emit(message); + m_second_log_handler->Emit(message); +} diff --git a/lldb/unittests/Utility/LogTest.cpp b/lldb/unittests/Utility/LogTest.cpp index 1dac19486a8f..b9b0af4133da 100644 --- a/lldb/unittests/Utility/LogTest.cpp +++ b/lldb/unittests/Utility/LogTest.cpp @@ -200,6 +200,18 @@ TEST(LogHandlerTest, RotatingLogHandler) { EXPECT_EQ(GetDumpAsString(handler), "bazquxquux"); } +TEST(LogHandlerTest, TeeLogHandler) { + auto handler1 = std::make_shared<RotatingLogHandler>(2); + auto handler2 = std::make_shared<RotatingLogHandler>(2); + TeeLogHandler handler(handler1, handler2); + + handler.Emit("foo"); + handler.Emit("bar"); + + EXPECT_EQ(GetDumpAsString(*handler1), "foobar"); + EXPECT_EQ(GetDumpAsString(*handler2), "foobar"); +} + TEST_F(LogChannelTest, Enable) { EXPECT_EQ(nullptr, GetLog(TestChannel::FOO)); std::string message; |