[lldb] Introduce the concept of a log handler (NFC)

This patch introduces the concept of a log handlers. Log handlers allow
customizing the way log output is emitted. The StreamCallback class
tried to do something conceptually similar. The benefit of the log
handler interface is that you don't need to conform to llvm's
raw_ostream interface.

Differential revision: https://reviews.llvm.org/D127922
This commit is contained in:
Jonas Devlieghere 2022-06-15 17:32:14 -07:00
parent 4c77d0276b
commit 6ff49af33d
No known key found for this signature in database
GPG Key ID: 49CC0BD90FDEED4D
11 changed files with 194 additions and 176 deletions

View File

@ -54,7 +54,9 @@ class ThreadPool;
namespace lldb_private {
class Address;
class CallbackLogHandler;
class CommandInterpreter;
class LogHandler;
class Process;
class Stream;
class SymbolContext;
@ -553,8 +555,8 @@ protected:
llvm::Optional<uint64_t> m_current_event_id;
llvm::StringMap<std::weak_ptr<llvm::raw_ostream>> m_log_streams;
std::shared_ptr<llvm::raw_ostream> m_log_callback_stream_sp;
llvm::StringMap<std::weak_ptr<LogHandler>> m_stream_handlers;
std::shared_ptr<CallbackLogHandler> m_callback_handler_sp;
ConstString m_instance_name;
static LoadPluginCallbackType g_load_plugin_callback;
typedef std::vector<llvm::sys::DynamicLibrary> LoadedPluginsList;

View File

@ -25,6 +25,7 @@
#include <cstdarg>
#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
#include <type_traits>
@ -45,6 +46,42 @@ class raw_ostream;
// Logging Functions
namespace lldb_private {
class LogHandler {
public:
virtual ~LogHandler() = default;
virtual void Emit(llvm::StringRef message) = 0;
void EmitThreadSafe(llvm::StringRef message);
private:
std::mutex m_mutex;
};
class StreamLogHandler : public LogHandler {
public:
StreamLogHandler(int fd, bool should_close, bool unbuffered);
void Emit(llvm::StringRef message) override;
static std::shared_ptr<StreamLogHandler> Create(int fd, bool unbuffered);
private:
llvm::raw_fd_ostream m_stream;
};
class CallbackLogHandler : public LogHandler {
public:
CallbackLogHandler(lldb::LogOutputCallback callback, void *baton);
void Emit(llvm::StringRef message) override;
static std::shared_ptr<CallbackLogHandler>
Create(lldb::LogOutputCallback callback, void *baton);
private:
lldb::LogOutputCallback m_callback;
void *m_baton;
};
class Log final {
public:
/// The underlying type of all log channel enums. Declare them as:
@ -111,7 +148,7 @@ public:
static void Unregister(llvm::StringRef name);
static bool
EnableLogChannel(const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
EnableLogChannel(const std::shared_ptr<LogHandler> &log_handler_sp,
uint32_t log_options, llvm::StringRef channel,
llvm::ArrayRef<const char *> categories,
llvm::raw_ostream &error_stream);
@ -188,7 +225,7 @@ private:
// Their modification however, is still protected by this mutex.
llvm::sys::RWMutex m_mutex;
std::shared_ptr<llvm::raw_ostream> m_stream_sp;
std::shared_ptr<LogHandler> m_handler;
std::atomic<uint32_t> m_options{0};
std::atomic<MaskType> m_mask{0};
@ -199,13 +236,13 @@ private:
void Format(llvm::StringRef file, llvm::StringRef function,
const llvm::formatv_object_base &payload);
std::shared_ptr<llvm::raw_ostream> GetStream() {
std::shared_ptr<LogHandler> GetHandler() {
llvm::sys::ScopedReader lock(m_mutex);
return m_stream_sp;
return m_handler;
}
void Enable(const std::shared_ptr<llvm::raw_ostream> &stream_sp,
uint32_t options, uint32_t flags);
void Enable(const std::shared_ptr<LogHandler> &handler_sp, uint32_t options,
uint32_t flags);
void Disable(uint32_t flags);

View File

@ -1,35 +0,0 @@
//===-- StreamCallback.h -----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_UTILITY_STREAMCALLBACK_H
#define LLDB_UTILITY_STREAMCALLBACK_H
#include "lldb/lldb-types.h"
#include "llvm/Support/raw_ostream.h"
#include <cstddef>
#include <cstdint>
namespace lldb_private {
class StreamCallback : public llvm::raw_ostream {
public:
StreamCallback(lldb::LogOutputCallback callback, void *baton);
~StreamCallback() override = default;
private:
lldb::LogOutputCallback m_callback;
void *m_baton;
void write_impl(const char *Ptr, size_t Size) override;
uint64_t current_pos() const override;
};
} // namespace lldb_private
#endif // LLDB_UTILITY_STREAMCALLBACK_H

View File

@ -51,7 +51,6 @@
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamCallback.h"
#include "lldb/Utility/StreamString.h"
#if defined(_WIN32)
@ -758,8 +757,7 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
m_forward_listener_sp(), m_clear_once() {
m_instance_name.SetString(llvm::formatv("debugger_{0}", GetID()).str());
if (log_callback)
m_log_callback_stream_sp =
std::make_shared<StreamCallback>(log_callback, baton);
m_callback_handler_sp = CallbackLogHandler::Create(log_callback, baton);
m_command_interpreter_up->Initialize();
// Always add our default platform to the platform list
PlatformSP default_platform_sp(Platform::GetHostPlatform());
@ -1292,8 +1290,7 @@ void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback,
// For simplicity's sake, I am not going to deal with how to close down any
// open logging streams, I just redirect everything from here on out to the
// callback.
m_log_callback_stream_sp =
std::make_shared<StreamCallback>(log_callback, baton);
m_callback_handler_sp = CallbackLogHandler::Create(log_callback, baton);
}
static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id,
@ -1412,22 +1409,21 @@ bool Debugger::EnableLog(llvm::StringRef channel,
llvm::StringRef log_file, uint32_t log_options,
llvm::raw_ostream &error_stream) {
const bool should_close = true;
const bool unbuffered = true;
std::shared_ptr<llvm::raw_ostream> log_stream_sp;
if (m_log_callback_stream_sp) {
log_stream_sp = m_log_callback_stream_sp;
std::shared_ptr<LogHandler> log_handler_sp;
if (m_callback_handler_sp) {
log_handler_sp = m_callback_handler_sp;
// For now when using the callback mode you always get thread & timestamp.
log_options |=
LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
} else if (log_file.empty()) {
log_stream_sp = std::make_shared<llvm::raw_fd_ostream>(
GetOutputFile().GetDescriptor(), !should_close, unbuffered);
log_handler_sp = StreamLogHandler::Create(GetOutputFile().GetDescriptor(),
!should_close);
} else {
auto pos = m_log_streams.find(log_file);
if (pos != m_log_streams.end())
log_stream_sp = pos->second.lock();
if (!log_stream_sp) {
auto pos = m_stream_handlers.find(log_file);
if (pos != m_stream_handlers.end())
log_handler_sp = pos->second.lock();
if (!log_handler_sp) {
File::OpenOptions flags =
File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;
if (log_options & LLDB_LOG_OPTION_APPEND)
@ -1442,18 +1438,18 @@ bool Debugger::EnableLog(llvm::StringRef channel,
return false;
}
log_stream_sp = std::make_shared<llvm::raw_fd_ostream>(
(*file)->GetDescriptor(), should_close, unbuffered);
m_log_streams[log_file] = log_stream_sp;
log_handler_sp =
StreamLogHandler::Create((*file)->GetDescriptor(), should_close);
m_stream_handlers[log_file] = log_handler_sp;
}
}
assert(log_stream_sp);
assert(log_handler_sp);
if (log_options == 0)
log_options =
LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
return Log::EnableLogChannel(log_stream_sp, log_options, channel, categories,
return Log::EnableLogChannel(log_handler_sp, log_options, channel, categories,
error_stream);
}

View File

@ -56,7 +56,6 @@ add_lldb_library(lldbUtility
State.cpp
Status.cpp
Stream.cpp
StreamCallback.cpp
StreamString.cpp
StringExtractor.cpp
StringExtractorGDBRemote.cpp

View File

@ -84,14 +84,14 @@ uint32_t Log::GetFlags(llvm::raw_ostream &stream, const ChannelMap::value_type &
return flags;
}
void Log::Enable(const std::shared_ptr<llvm::raw_ostream> &stream_sp,
void Log::Enable(const std::shared_ptr<LogHandler> &handler_sp,
uint32_t options, uint32_t flags) {
llvm::sys::ScopedWriter lock(m_mutex);
MaskType mask = m_mask.fetch_or(flags, std::memory_order_relaxed);
if (mask | flags) {
m_options.store(options, std::memory_order_relaxed);
m_stream_sp = stream_sp;
m_handler = handler_sp;
m_channel.log_ptr.store(this, std::memory_order_relaxed);
}
}
@ -101,7 +101,7 @@ void Log::Disable(uint32_t flags) {
MaskType mask = m_mask.fetch_and(~flags, std::memory_order_relaxed);
if (!(mask & ~flags)) {
m_stream_sp.reset();
m_handler.reset();
m_channel.log_ptr.store(nullptr, std::memory_order_relaxed);
}
}
@ -191,10 +191,10 @@ void Log::Unregister(llvm::StringRef name) {
g_channel_map->erase(iter);
}
bool Log::EnableLogChannel(
const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
uint32_t log_options, llvm::StringRef channel,
llvm::ArrayRef<const char *> categories, llvm::raw_ostream &error_stream) {
bool Log::EnableLogChannel(const std::shared_ptr<LogHandler> &log_handler_sp,
uint32_t log_options, llvm::StringRef channel,
llvm::ArrayRef<const char *> categories,
llvm::raw_ostream &error_stream) {
auto iter = g_channel_map->find(channel);
if (iter == g_channel_map->end()) {
error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
@ -203,7 +203,7 @@ bool Log::EnableLogChannel(
uint32_t flags = categories.empty()
? iter->second.m_channel.default_flags
: GetFlags(error_stream, *iter, categories);
iter->second.Enable(log_stream_sp, log_options, flags);
iter->second.Enable(log_handler_sp, log_options, flags);
return true;
}
@ -314,20 +314,15 @@ void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
void Log::WriteMessage(const std::string &message) {
// Make a copy of our stream shared pointer in case someone disables our log
// while we are logging and releases the stream
auto stream_sp = GetStream();
if (!stream_sp)
auto handler_sp = GetHandler();
if (!handler_sp)
return;
Flags options = GetOptions();
if (options.Test(LLDB_LOG_OPTION_THREADSAFE)) {
static std::recursive_mutex g_LogThreadedMutex;
std::lock_guard<std::recursive_mutex> guard(g_LogThreadedMutex);
*stream_sp << message;
stream_sp->flush();
} else {
*stream_sp << message;
stream_sp->flush();
}
if (options.Test(LLDB_LOG_OPTION_THREADSAFE))
handler_sp->EmitThreadSafe(message);
else
handler_sp->Emit(message);
}
void Log::Format(llvm::StringRef file, llvm::StringRef function,
@ -338,3 +333,35 @@ void Log::Format(llvm::StringRef file, llvm::StringRef function,
message << payload << "\n";
WriteMessage(message.str());
}
void LogHandler::EmitThreadSafe(llvm::StringRef message) {
std::lock_guard<std::mutex> guard(m_mutex);
Emit(message);
}
StreamLogHandler::StreamLogHandler(int fd, bool should_close, bool unbuffered)
: m_stream(fd, should_close, unbuffered) {}
void StreamLogHandler::Emit(llvm::StringRef message) {
m_stream << message;
m_stream.flush();
}
std::shared_ptr<StreamLogHandler> StreamLogHandler::Create(int fd,
bool should_close) {
constexpr const bool unbuffered = true;
return std::make_shared<StreamLogHandler>(fd, should_close, unbuffered);
}
CallbackLogHandler::CallbackLogHandler(lldb::LogOutputCallback callback,
void *baton)
: m_callback(callback), m_baton(baton) {}
void CallbackLogHandler::Emit(llvm::StringRef message) {
m_callback(message.data(), m_baton);
}
std::shared_ptr<CallbackLogHandler>
CallbackLogHandler::Create(lldb::LogOutputCallback callback, void *baton) {
return std::make_shared<CallbackLogHandler>(callback, baton);
}

View File

@ -1,22 +0,0 @@
//===-- StreamCallback.cpp ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Utility/StreamCallback.h"
#include <string>
using namespace lldb_private;
StreamCallback::StreamCallback(lldb::LogOutputCallback callback, void *baton)
: llvm::raw_ostream(true), m_callback(callback), m_baton(baton) {}
void StreamCallback::write_impl(const char *Ptr, size_t Size) {
m_callback(std::string(Ptr, Size).c_str(), m_baton);
}
uint64_t StreamCallback::current_pos() const { return 0; }

View File

@ -18,21 +18,37 @@
using namespace lldb;
using namespace lldb_private::lldb_server;
using namespace lldb_private;
using namespace llvm;
static std::shared_ptr<raw_ostream> GetLogStream(StringRef log_file) {
class TestLogHandler : public LogHandler {
public:
TestLogHandler(std::shared_ptr<llvm::raw_ostream> stream_sp)
: m_stream_sp(stream_sp) {}
void Emit(llvm::StringRef message) override {
(*m_stream_sp) << message;
m_stream_sp->flush();
}
private:
std::shared_ptr<raw_ostream> m_stream_sp;
};
static std::shared_ptr<TestLogHandler> GetLogStream(StringRef log_file) {
if (!log_file.empty()) {
std::error_code EC;
std::shared_ptr<raw_ostream> stream_sp = std::make_shared<raw_fd_ostream>(
auto stream_sp = std::make_shared<raw_fd_ostream>(
log_file, EC, sys::fs::OF_TextWithCRLF | sys::fs::OF_Append);
if (!EC)
return stream_sp;
return std::make_shared<TestLogHandler>(stream_sp);
errs() << llvm::formatv(
"Failed to open log file `{0}`: {1}\nWill log to stderr instead.\n",
log_file, EC.message());
}
// No need to delete the stderr stream.
return std::shared_ptr<raw_ostream>(&errs(), [](raw_ostream *) {});
return std::make_shared<TestLogHandler>(
std::shared_ptr<raw_ostream>(&errs(), [](raw_ostream *) {}));
}
bool LLDBServerUtilities::SetupLogging(const std::string &log_file,

View File

@ -8,7 +8,6 @@ add_lldb_unittest(LLDBCoreTests
RichManglingContextTest.cpp
SourceLocationSpecTest.cpp
SourceManagerTest.cpp
StreamCallbackTest.cpp
UniqueCStringMapTest.cpp
LINK_LIBS

View File

@ -1,27 +0,0 @@
//===-- StreamCallbackTest.cpp --------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Utility/StreamCallback.h"
#include "gtest/gtest.h"
using namespace lldb;
using namespace lldb_private;
static char test_baton;
static size_t callback_count = 0;
static void TestCallback(const char *data, void *baton) {
EXPECT_STREQ("Foobar", data);
EXPECT_EQ(&test_baton, baton);
++callback_count;
}
TEST(StreamCallbackTest, Callback) {
StreamCallback stream(TestCallback, &test_baton);
stream << "Foobar";
EXPECT_EQ(1u, callback_count);
}

View File

@ -39,13 +39,13 @@ template <> Log::Channel &LogChannelFor<TestChannel>() { return test_channel; }
} // namespace lldb_private
// Wrap enable, disable and list functions to make them easier to test.
static bool EnableChannel(std::shared_ptr<llvm::raw_ostream> stream_sp,
static bool EnableChannel(std::shared_ptr<LogHandler> log_handler_sp,
uint32_t log_options, llvm::StringRef channel,
llvm::ArrayRef<const char *> categories,
std::string &error) {
error.clear();
llvm::raw_string_ostream error_stream(error);
return Log::EnableLogChannel(stream_sp, log_options, channel, categories,
return Log::EnableLogChannel(log_handler_sp, log_options, channel, categories,
error_stream);
}
@ -68,9 +68,7 @@ namespace {
struct LogChannelTest : public ::testing::Test {
void TearDown() override { Log::DisableAllLogChannels(); }
static void SetUpTestCase() {
Log::Register("chan", test_channel);
}
static void SetUpTestCase() { Log::Register("chan", test_channel); }
static void TearDownTestCase() {
Log::Unregister("chan");
@ -78,18 +76,27 @@ struct LogChannelTest : public ::testing::Test {
}
};
class TestLogHandler : public LogHandler {
public:
TestLogHandler() : m_messages(), m_stream(m_messages) {}
void Emit(llvm::StringRef message) override { m_stream << message; }
llvm::SmallString<0> m_messages;
llvm::raw_svector_ostream m_stream;
};
// A test fixture which provides tests with a pre-registered and pre-enabled
// channel. Additionally, the messages written to that channel are captured and
// made available via getMessage().
class LogChannelEnabledTest : public LogChannelTest {
llvm::SmallString<0> m_messages;
std::shared_ptr<llvm::raw_svector_ostream> m_stream_sp =
std::make_shared<llvm::raw_svector_ostream>(m_messages);
std::shared_ptr<TestLogHandler> m_log_handler_sp =
std::make_shared<TestLogHandler>();
Log *m_log;
size_t m_consumed_bytes = 0;
protected:
std::shared_ptr<llvm::raw_ostream> getStream() { return m_stream_sp; }
std::shared_ptr<LogHandler> getLogHandler() { return m_log_handler_sp; }
Log *getLog() { return m_log; }
llvm::StringRef takeOutput();
llvm::StringRef logAndTakeOutput(llvm::StringRef Message);
@ -103,19 +110,21 @@ void LogChannelEnabledTest::SetUp() {
LogChannelTest::SetUp();
std::string error;
ASSERT_TRUE(EnableChannel(m_stream_sp, 0, "chan", {}, error));
ASSERT_TRUE(EnableChannel(m_log_handler_sp, 0, "chan", {}, error));
m_log = GetLog(TestChannel::FOO);
ASSERT_NE(nullptr, m_log);
}
llvm::StringRef LogChannelEnabledTest::takeOutput() {
llvm::StringRef result = m_stream_sp->str().drop_front(m_consumed_bytes);
m_consumed_bytes+= result.size();
llvm::StringRef result =
m_log_handler_sp->m_stream.str().drop_front(m_consumed_bytes);
m_consumed_bytes += result.size();
return result;
}
llvm::StringRef LogChannelEnabledTest::logAndTakeOutput(llvm::StringRef Message) {
llvm::StringRef
LogChannelEnabledTest::logAndTakeOutput(llvm::StringRef Message) {
LLDB_LOG(m_log, "{0}", Message);
return takeOutput();
}
@ -138,33 +147,48 @@ TEST(LogTest, Unregister) {
Log::Register("chan", test_channel);
EXPECT_EQ(nullptr, GetLog(TestChannel::FOO));
std::string message;
std::shared_ptr<llvm::raw_string_ostream> stream_sp(
new llvm::raw_string_ostream(message));
EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", {"foo"}, llvm::nulls()));
auto log_handler_sp = std::make_shared<TestLogHandler>();
EXPECT_TRUE(
Log::EnableLogChannel(log_handler_sp, 0, "chan", {"foo"}, llvm::nulls()));
EXPECT_NE(nullptr, GetLog(TestChannel::FOO));
Log::Unregister("chan");
EXPECT_EQ(nullptr, GetLog(TestChannel::FOO));
}
namespace {
static char test_baton;
static size_t callback_count = 0;
static void TestCallback(const char *data, void *baton) {
EXPECT_STREQ("Foobar", data);
EXPECT_EQ(&test_baton, baton);
++callback_count;
}
} // namespace
TEST(LogTest, CallbackLogHandler) {
CallbackLogHandler handler(TestCallback, &test_baton);
handler.Emit("Foobar");
EXPECT_EQ(1u, callback_count);
}
TEST_F(LogChannelTest, Enable) {
EXPECT_EQ(nullptr, GetLog(TestChannel::FOO));
std::string message;
std::shared_ptr<llvm::raw_string_ostream> stream_sp(
new llvm::raw_string_ostream(message));
auto log_handler_sp = std::make_shared<TestLogHandler>();
std::string error;
ASSERT_FALSE(EnableChannel(stream_sp, 0, "chanchan", {}, error));
ASSERT_FALSE(EnableChannel(log_handler_sp, 0, "chanchan", {}, error));
EXPECT_EQ("Invalid log channel 'chanchan'.\n", error);
EXPECT_TRUE(EnableChannel(stream_sp, 0, "chan", {}, error));
EXPECT_TRUE(EnableChannel(log_handler_sp, 0, "chan", {}, error));
EXPECT_NE(nullptr, GetLog(TestChannel::FOO));
EXPECT_EQ(nullptr, GetLog(TestChannel::BAR));
EXPECT_NE(nullptr, GetLog(TestChannel::FOO | TestChannel::BAR));
EXPECT_TRUE(EnableChannel(stream_sp, 0, "chan", {"bar"}, error));
EXPECT_TRUE(EnableChannel(log_handler_sp, 0, "chan", {"bar"}, error));
EXPECT_NE(nullptr, GetLog(TestChannel::FOO));
EXPECT_NE(nullptr, GetLog(TestChannel::BAR));
EXPECT_TRUE(EnableChannel(stream_sp, 0, "chan", {"baz"}, error));
EXPECT_TRUE(EnableChannel(log_handler_sp, 0, "chan", {"baz"}, error));
EXPECT_NE(std::string::npos, error.find("unrecognized log category 'baz'"))
<< "error: " << error;
}
@ -172,11 +196,10 @@ TEST_F(LogChannelTest, Enable) {
TEST_F(LogChannelTest, EnableOptions) {
EXPECT_EQ(nullptr, GetLog(TestChannel::FOO));
std::string message;
std::shared_ptr<llvm::raw_string_ostream> stream_sp(
new llvm::raw_string_ostream(message));
auto log_handler_sp = std::make_shared<TestLogHandler>();
std::string error;
EXPECT_TRUE(
EnableChannel(stream_sp, LLDB_LOG_OPTION_VERBOSE, "chan", {}, error));
EXPECT_TRUE(EnableChannel(log_handler_sp, LLDB_LOG_OPTION_VERBOSE, "chan", {},
error));
Log *log = GetLog(TestChannel::FOO);
ASSERT_NE(nullptr, log);
@ -186,10 +209,9 @@ TEST_F(LogChannelTest, EnableOptions) {
TEST_F(LogChannelTest, Disable) {
EXPECT_EQ(nullptr, GetLog(TestChannel::FOO));
std::string message;
std::shared_ptr<llvm::raw_string_ostream> stream_sp(
new llvm::raw_string_ostream(message));
auto log_handler_sp = std::make_shared<TestLogHandler>();
std::string error;
EXPECT_TRUE(EnableChannel(stream_sp, 0, "chan", {"foo", "bar"}, error));
EXPECT_TRUE(EnableChannel(log_handler_sp, 0, "chan", {"foo", "bar"}, error));
EXPECT_NE(nullptr, GetLog(TestChannel::FOO));
EXPECT_NE(nullptr, GetLog(TestChannel::BAR));
@ -226,12 +248,12 @@ TEST_F(LogChannelTest, List) {
TEST_F(LogChannelEnabledTest, log_options) {
std::string Err;
EXPECT_EQ("Hello World\n", logAndTakeOutput("Hello World"));
EXPECT_TRUE(EnableChannel(getStream(), LLDB_LOG_OPTION_THREADSAFE, "chan", {},
Err));
EXPECT_TRUE(EnableChannel(getLogHandler(), LLDB_LOG_OPTION_THREADSAFE, "chan",
{}, Err));
EXPECT_EQ("Hello World\n", logAndTakeOutput("Hello World"));
{
EXPECT_TRUE(EnableChannel(getStream(), LLDB_LOG_OPTION_PREPEND_SEQUENCE,
EXPECT_TRUE(EnableChannel(getLogHandler(), LLDB_LOG_OPTION_PREPEND_SEQUENCE,
"chan", {}, Err));
llvm::StringRef Msg = logAndTakeOutput("Hello World");
int seq_no;
@ -239,19 +261,23 @@ TEST_F(LogChannelEnabledTest, log_options) {
}
{
EXPECT_TRUE(EnableChannel(getStream(), LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION,
"chan", {}, Err));
EXPECT_TRUE(EnableChannel(getLogHandler(),
LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION, "chan", {},
Err));
llvm::StringRef Msg = logAndTakeOutput("Hello World");
char File[12];
char Function[17];
sscanf(Msg.str().c_str(), "%[^:]:%s Hello World", File, Function);
sscanf(Msg.str().c_str(),
"%[^:]:%s Hello World", File,
Function);
EXPECT_STRCASEEQ("LogTest.cpp", File);
EXPECT_STREQ("logAndTakeOutput", Function);
}
EXPECT_TRUE(EnableChannel(
getStream(), LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD, "chan", {}, Err));
EXPECT_TRUE(EnableChannel(getLogHandler(),
LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD, "chan", {},
Err));
EXPECT_EQ(llvm::formatv("[{0,0+4}/{1,0+4}] Hello World\n", ::getpid(),
llvm::get_threadid())
.str(),
@ -300,7 +326,7 @@ TEST_F(LogChannelEnabledTest, LogVerboseThread) {
// (with different log options).
std::thread log_thread([this] { LLDB_LOGV(getLog(), "Hello World"); });
EXPECT_TRUE(
EnableChannel(getStream(), LLDB_LOG_OPTION_VERBOSE, "chan", {}, err));
EnableChannel(getLogHandler(), LLDB_LOG_OPTION_VERBOSE, "chan", {}, err));
log_thread.join();
// The log thread either managed to write to the log, or it didn't. In either