summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonas Devlieghere <jonas@devlieghere.com>2024-05-03 11:08:50 -0700
committerGitHub <noreply@github.com>2024-05-03 11:08:50 -0700
commita8fbe500fe2ecdbd3c09ed06788092937819411f (patch)
tree9da5d7cc527dc71e902a7c7ce4cb004058c66736
parente2b3e4ea9f2d0cb34d197439cfbc5090cdacb124 (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.h17
-rw-r--r--lldb/source/Utility/Log.cpp14
-rw-r--r--lldb/unittests/Utility/LogTest.cpp12
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;