Skip to content

Commit 6ac608b

Browse files
committed
[lldb] Add RotatingLogHandler
Add a log handler that maintains a circular buffer with a fixed size. Differential revision: https://reviews.llvm.org/D127937
1 parent 9d7b01d commit 6ac608b

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

lldb/include/lldb/Utility/Log.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,26 @@ class CallbackLogHandler : public LogHandler {
8282
void *m_baton;
8383
};
8484

85+
class RotatingLogHandler : public LogHandler {
86+
public:
87+
RotatingLogHandler(size_t size);
88+
89+
void Emit(llvm::StringRef message) override;
90+
void Dump(llvm::raw_ostream &stream) const;
91+
92+
static std::shared_ptr<RotatingLogHandler> Create(size_t size);
93+
94+
private:
95+
size_t NormalizeIndex(size_t i) const;
96+
size_t GetNumMessages() const;
97+
size_t GetFirstMessageIndex() const;
98+
99+
std::unique_ptr<std::string[]> m_messages;
100+
const size_t m_size = 0;
101+
size_t m_next_index = 0;
102+
size_t m_total_count = 0;
103+
};
104+
85105
class Log final {
86106
public:
87107
/// The underlying type of all log channel enums. Declare them as:

lldb/source/Utility/Log.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,3 +365,37 @@ std::shared_ptr<CallbackLogHandler>
365365
CallbackLogHandler::Create(lldb::LogOutputCallback callback, void *baton) {
366366
return std::make_shared<CallbackLogHandler>(callback, baton);
367367
}
368+
369+
RotatingLogHandler::RotatingLogHandler(size_t size)
370+
: m_messages(std::make_unique<std::string[]>(size)), m_size(size) {}
371+
372+
void RotatingLogHandler::Emit(llvm::StringRef message) {
373+
++m_total_count;
374+
const size_t index = m_next_index;
375+
m_next_index = NormalizeIndex(index + 1);
376+
m_messages[index] = message.str();
377+
}
378+
379+
size_t RotatingLogHandler::NormalizeIndex(size_t i) const { return i % m_size; }
380+
381+
size_t RotatingLogHandler::GetNumMessages() const {
382+
return m_total_count < m_size ? m_total_count : m_size;
383+
}
384+
385+
size_t RotatingLogHandler::GetFirstMessageIndex() const {
386+
return m_total_count < m_size ? 0 : m_next_index;
387+
}
388+
389+
void RotatingLogHandler::Dump(llvm::raw_ostream &stream) const {
390+
const size_t start_idx = GetFirstMessageIndex();
391+
const size_t stop_idx = start_idx + GetNumMessages();
392+
for (size_t i = start_idx; i < stop_idx; ++i) {
393+
const size_t idx = NormalizeIndex(i);
394+
stream << m_messages[idx];
395+
}
396+
stream.flush();
397+
}
398+
399+
std::shared_ptr<RotatingLogHandler> RotatingLogHandler::Create(size_t size) {
400+
return std::make_shared<RotatingLogHandler>(size);
401+
}

lldb/unittests/Utility/LogTest.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ class LogChannelEnabledTest : public LogChannelTest {
104104
public:
105105
void SetUp() override;
106106
};
107+
108+
static std::string GetDumpAsString(const RotatingLogHandler &handler) {
109+
std::string buffer;
110+
llvm::raw_string_ostream stream(buffer);
111+
handler.Dump(stream);
112+
return buffer;
113+
}
107114
} // end anonymous namespace
108115

109116
void LogChannelEnabledTest::SetUp() {
@@ -171,6 +178,21 @@ TEST(LogTest, CallbackLogHandler) {
171178
EXPECT_EQ(1u, callback_count);
172179
}
173180

181+
TEST(LogHandlerTest, RotatingLogHandler) {
182+
RotatingLogHandler handler(3);
183+
184+
handler.Emit("foo");
185+
handler.Emit("bar");
186+
EXPECT_EQ(GetDumpAsString(handler), "foobar");
187+
188+
handler.Emit("baz");
189+
handler.Emit("qux");
190+
EXPECT_EQ(GetDumpAsString(handler), "barbazqux");
191+
192+
handler.Emit("quux");
193+
EXPECT_EQ(GetDumpAsString(handler), "bazquxquux");
194+
}
195+
174196
TEST_F(LogChannelTest, Enable) {
175197
EXPECT_EQ(nullptr, GetLog(TestChannel::FOO));
176198
std::string message;

0 commit comments

Comments
 (0)