forked from OSchip/llvm-project
Revert "Refactor log channel registration mechanism"
The change breaks on Windows and NetBSD bots. Revert while I investigate. llvm-svn: 295201
This commit is contained in:
parent
94c8d4976c
commit
f0713996b2
|
@ -44,53 +44,6 @@ namespace lldb_private {
|
|||
|
||||
class Log final {
|
||||
public:
|
||||
// Description of a log channel category.
|
||||
struct Category {
|
||||
llvm::StringLiteral name;
|
||||
llvm::StringLiteral description;
|
||||
uint32_t flag;
|
||||
};
|
||||
|
||||
// This class describes a log channel. It also encapsulates the behavior
|
||||
// necessary to enable a log channel in an atomic manner.
|
||||
class Channel {
|
||||
std::atomic<Log *> log_ptr;
|
||||
|
||||
public:
|
||||
const llvm::ArrayRef<Category> categories;
|
||||
const uint32_t default_flags;
|
||||
|
||||
constexpr Channel(llvm::ArrayRef<Log::Category> categories,
|
||||
uint32_t default_flags)
|
||||
: log_ptr(nullptr), categories(categories),
|
||||
default_flags(default_flags) {}
|
||||
|
||||
// This function is safe to call at any time
|
||||
// FIXME: Not true yet, mask access is not atomic
|
||||
Log *GetLogIfAll(uint32_t mask) {
|
||||
Log *log = log_ptr.load(std::memory_order_acquire);
|
||||
if (log && log->GetMask().AllSet(mask))
|
||||
return log;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This function is safe to call at any time
|
||||
// FIXME: Not true yet, mask access is not atomic
|
||||
Log *GetLogIfAny(uint32_t mask) {
|
||||
Log *log = log_ptr.load(std::memory_order_acquire);
|
||||
if (log && log->GetMask().AnySet(mask))
|
||||
return log;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Calls to Enable and disable need to be serialized externally.
|
||||
void Enable(Log &log, const std::shared_ptr<llvm::raw_ostream> &stream_sp,
|
||||
uint32_t flags);
|
||||
|
||||
// Calls to Enable and disable need to be serialized externally.
|
||||
void Disable(uint32_t flags);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Callback definitions for abstracted plug-in log access.
|
||||
//------------------------------------------------------------------
|
||||
|
@ -110,9 +63,6 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
// Static accessors for logging channels
|
||||
//------------------------------------------------------------------
|
||||
static void Register(llvm::StringRef name, Channel &channel);
|
||||
static void Unregister(llvm::StringRef name);
|
||||
|
||||
static void RegisterLogChannel(const ConstString &channel,
|
||||
const Log::Callbacks &log_callbacks);
|
||||
|
||||
|
@ -123,13 +73,13 @@ public:
|
|||
|
||||
static bool
|
||||
EnableLogChannel(const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
|
||||
uint32_t log_options, llvm::StringRef channel,
|
||||
uint32_t log_options, const char *channel,
|
||||
const char **categories, Stream &error_stream);
|
||||
|
||||
static bool DisableLogChannel(llvm::StringRef channel,
|
||||
const char **categories, Stream &error_stream);
|
||||
|
||||
static bool ListChannelCategories(llvm::StringRef channel, Stream &stream);
|
||||
static void
|
||||
EnableAllLogChannels(const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
|
||||
uint32_t log_options, const char **categories,
|
||||
Stream *feedback_strm);
|
||||
|
||||
static void DisableAllLogChannels(Stream *feedback_strm);
|
||||
|
||||
|
@ -139,6 +89,12 @@ public:
|
|||
|
||||
static void Terminate();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Auto completion
|
||||
//------------------------------------------------------------------
|
||||
static void AutoCompleteChannelName(const char *channel_name,
|
||||
StringList &matches);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Member functions
|
||||
//------------------------------------------------------------------
|
||||
|
@ -206,6 +162,34 @@ private:
|
|||
const llvm::formatv_object_base &payload);
|
||||
};
|
||||
|
||||
class LogChannel : public PluginInterface {
|
||||
public:
|
||||
LogChannel();
|
||||
|
||||
~LogChannel() override;
|
||||
|
||||
static lldb::LogChannelSP FindPlugin(const char *plugin_name);
|
||||
|
||||
// categories is an array of chars that ends with a NULL element.
|
||||
virtual void Disable(const char **categories, Stream *feedback_strm) = 0;
|
||||
|
||||
virtual bool
|
||||
Enable(const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
|
||||
uint32_t log_options,
|
||||
Stream *feedback_strm, // Feedback stream for argument errors etc
|
||||
const char **categories) = 0; // The categories to enable within this
|
||||
// logging stream, if empty, enable
|
||||
// default set
|
||||
|
||||
virtual void ListCategories(Stream *strm) = 0;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<Log> m_log_ap;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(LogChannel);
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#define LLDB_LOG(log, ...) \
|
||||
|
|
|
@ -209,6 +209,22 @@ public:
|
|||
static ObjectFileGetModuleSpecifications
|
||||
GetObjectContainerGetModuleSpecificationsCallbackAtIndex(uint32_t idx);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// LogChannel
|
||||
//------------------------------------------------------------------
|
||||
static bool RegisterPlugin(const ConstString &name, const char *description,
|
||||
LogChannelCreateInstance create_callback);
|
||||
|
||||
static bool UnregisterPlugin(LogChannelCreateInstance create_callback);
|
||||
|
||||
static LogChannelCreateInstance
|
||||
GetLogChannelCreateCallbackAtIndex(uint32_t idx);
|
||||
|
||||
static LogChannelCreateInstance
|
||||
GetLogChannelCreateCallbackForPluginName(const ConstString &name);
|
||||
|
||||
static const char *GetLogChannelCreateNameAtIndex(uint32_t idx);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Platform
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -127,6 +127,7 @@ class MemoryRegionInfo;
|
|||
class LineTable;
|
||||
class Listener;
|
||||
class Log;
|
||||
class LogChannel;
|
||||
class Mangled;
|
||||
class Materializer;
|
||||
class MemoryHistory;
|
||||
|
@ -361,6 +362,7 @@ typedef std::unique_ptr<lldb_private::SystemRuntime> SystemRuntimeUP;
|
|||
typedef std::shared_ptr<lldb_private::LineTable> LineTableSP;
|
||||
typedef std::shared_ptr<lldb_private::Listener> ListenerSP;
|
||||
typedef std::weak_ptr<lldb_private::Listener> ListenerWP;
|
||||
typedef std::shared_ptr<lldb_private::LogChannel> LogChannelSP;
|
||||
typedef std::shared_ptr<lldb_private::MemoryHistory> MemoryHistorySP;
|
||||
typedef std::shared_ptr<lldb_private::MemoryRegionInfo> MemoryRegionInfoSP;
|
||||
typedef std::unique_ptr<lldb_private::MemoryRegionInfo> MemoryRegionInfoUP;
|
||||
|
|
|
@ -45,6 +45,7 @@ typedef ObjectFile *(*ObjectFileCreateMemoryInstance)(
|
|||
const lldb::ProcessSP &process_sp, lldb::addr_t offset);
|
||||
typedef bool (*ObjectFileSaveCore)(const lldb::ProcessSP &process_sp,
|
||||
const FileSpec &outfile, Error &error);
|
||||
typedef LogChannel *(*LogChannelCreateInstance)();
|
||||
typedef EmulateInstruction *(*EmulateInstructionCreateInstance)(
|
||||
const ArchSpec &arch, InstructionType inst_type);
|
||||
typedef OperatingSystem *(*OperatingSystemCreateInstance)(Process *process,
|
||||
|
|
|
@ -227,15 +227,25 @@ protected:
|
|||
return false;
|
||||
}
|
||||
|
||||
Log::Callbacks log_callbacks;
|
||||
|
||||
const std::string channel = args[0].ref;
|
||||
args.Shift(); // Shift off the channel
|
||||
if (channel == "all") {
|
||||
Log::DisableAllLogChannels(&result.GetErrorStream());
|
||||
if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
|
||||
log_callbacks.disable(args.GetConstArgumentVector(),
|
||||
&result.GetErrorStream());
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
} else if (channel == "all") {
|
||||
Log::DisableAllLogChannels(&result.GetErrorStream());
|
||||
} else {
|
||||
if (Log::DisableLogChannel(channel, args.GetConstArgumentVector(),
|
||||
result.GetErrorStream()))
|
||||
LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel.data()));
|
||||
if (log_channel_sp) {
|
||||
log_channel_sp->Disable(args.GetConstArgumentVector(),
|
||||
&result.GetErrorStream());
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
} else
|
||||
result.AppendErrorWithFormat("Invalid log channel '%s'.\n",
|
||||
channel.data());
|
||||
}
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
@ -274,12 +284,26 @@ protected:
|
|||
Log::ListAllLogChannels(&result.GetOutputStream());
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
} else {
|
||||
bool success = true;
|
||||
for (const auto &entry : args.entries())
|
||||
success = success && Log::ListChannelCategories(
|
||||
entry.ref, result.GetOutputStream());
|
||||
if (success)
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
for (auto &entry : args.entries()) {
|
||||
Log::Callbacks log_callbacks;
|
||||
|
||||
if (Log::GetLogChannelCallbacks(ConstString(entry.ref),
|
||||
log_callbacks)) {
|
||||
log_callbacks.list_categories(&result.GetOutputStream());
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
} else if (entry.ref == "all") {
|
||||
Log::ListAllLogChannels(&result.GetOutputStream());
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
} else {
|
||||
LogChannelSP log_channel_sp(LogChannel::FindPlugin(entry.c_str()));
|
||||
if (log_channel_sp) {
|
||||
log_channel_sp->ListCategories(&result.GetOutputStream());
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
} else
|
||||
result.AppendErrorWithFormat("Invalid log channel '%s'.\n",
|
||||
entry.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
|
|
@ -18,10 +18,8 @@
|
|||
#include "lldb/Utility/StreamString.h"
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/Chrono.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
@ -38,76 +36,6 @@
|
|||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
namespace {
|
||||
struct ChannelAndLog {
|
||||
Log log;
|
||||
Log::Channel &channel;
|
||||
|
||||
ChannelAndLog(Log::Channel &channel) : channel(channel) {}
|
||||
};
|
||||
typedef llvm::StringMap<ChannelAndLog> ChannelMap;
|
||||
}
|
||||
|
||||
static llvm::ManagedStatic<ChannelMap> g_channel_map;
|
||||
|
||||
static void ListCategories(Stream &stream, const ChannelMap::value_type &entry) {
|
||||
stream.Format("Logging categories for '{0}':\n", entry.first());
|
||||
stream.Format(" all - all available logging categories\n");
|
||||
stream.Format(" default - default set of logging categories\n");
|
||||
for (const auto &category : entry.second.channel.categories)
|
||||
stream.Format(" {0} - {1}\n", category.name, category.description);
|
||||
}
|
||||
|
||||
static uint32_t GetFlags(Stream &stream, const ChannelMap::value_type &entry,
|
||||
const char **categories) {
|
||||
bool list_categories = false;
|
||||
uint32_t flags = 0;
|
||||
for (size_t i = 0; categories[i]; ++i) {
|
||||
if (llvm::StringRef("all").equals_lower(categories[i])) {
|
||||
flags |= UINT32_MAX;
|
||||
continue;
|
||||
}
|
||||
if (llvm::StringRef("default").equals_lower(categories[i])) {
|
||||
flags |= entry.second.channel.default_flags;
|
||||
continue;
|
||||
}
|
||||
auto cat = llvm::find_if(entry.second.channel.categories,
|
||||
[&](const Log::Category &c) {
|
||||
return c.name.equals_lower(categories[i]);
|
||||
});
|
||||
if (cat != entry.second.channel.categories.end()) {
|
||||
flags |= cat->flag;
|
||||
continue;
|
||||
}
|
||||
stream.Format("error: unrecognized log category '{0}'\n", categories[i]);
|
||||
list_categories = true;
|
||||
}
|
||||
if (list_categories)
|
||||
ListCategories(stream, entry);
|
||||
return flags;
|
||||
}
|
||||
|
||||
void Log::Channel::Enable(Log &log,
|
||||
const std::shared_ptr<llvm::raw_ostream> &stream_sp,
|
||||
uint32_t flags) {
|
||||
log.GetMask().Set(flags);
|
||||
if (log.GetMask().Get()) {
|
||||
log.SetStream(stream_sp);
|
||||
log_ptr.store(&log, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::Channel::Disable(uint32_t flags) {
|
||||
Log *log = log_ptr.load(std::memory_order_acquire);
|
||||
if (!log)
|
||||
return;
|
||||
log->GetMask().Clear(flags);
|
||||
if (!log->GetMask().Get()) {
|
||||
log->SetStream(nullptr);
|
||||
log_ptr.store(nullptr, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
Log::Log() : m_stream_sp(), m_options(0), m_mask_bits(0) {}
|
||||
|
||||
Log::Log(const std::shared_ptr<llvm::raw_ostream> &stream_sp)
|
||||
|
@ -224,6 +152,9 @@ void Log::Warning(const char *format, ...) {
|
|||
typedef std::map<ConstString, Log::Callbacks> CallbackMap;
|
||||
typedef CallbackMap::iterator CallbackMapIter;
|
||||
|
||||
typedef std::map<ConstString, LogChannelSP> LogChannelMap;
|
||||
typedef LogChannelMap::iterator LogChannelMapIter;
|
||||
|
||||
// Surround our callback map with a singleton function so we don't have any
|
||||
// global initializers.
|
||||
static CallbackMap &GetCallbackMap() {
|
||||
|
@ -231,17 +162,9 @@ static CallbackMap &GetCallbackMap() {
|
|||
return g_callback_map;
|
||||
}
|
||||
|
||||
void Log::Register(llvm::StringRef name, Channel &channel) {
|
||||
auto iter = g_channel_map->try_emplace(name, channel);
|
||||
assert(iter.second == true);
|
||||
(void)iter;
|
||||
}
|
||||
|
||||
void Log::Unregister(llvm::StringRef name) {
|
||||
auto iter = g_channel_map->find(name);
|
||||
assert(iter != g_channel_map->end());
|
||||
iter->second.channel.Disable(UINT32_MAX);
|
||||
g_channel_map->erase(iter);
|
||||
static LogChannelMap &GetChannelMap() {
|
||||
static LogChannelMap g_channel_map;
|
||||
return g_channel_map;
|
||||
}
|
||||
|
||||
void Log::RegisterLogChannel(const ConstString &channel,
|
||||
|
@ -267,7 +190,7 @@ bool Log::GetLogChannelCallbacks(const ConstString &channel,
|
|||
|
||||
bool Log::EnableLogChannel(
|
||||
const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
|
||||
uint32_t log_options, llvm::StringRef channel, const char **categories,
|
||||
uint32_t log_options, const char *channel, const char **categories,
|
||||
Stream &error_stream) {
|
||||
Log::Callbacks log_callbacks;
|
||||
if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
|
||||
|
@ -275,52 +198,52 @@ bool Log::EnableLogChannel(
|
|||
return true;
|
||||
}
|
||||
|
||||
auto iter = g_channel_map->find(channel);
|
||||
if (iter == g_channel_map->end()) {
|
||||
error_stream.Format("Invalid log channel '{0}'.\n", channel);
|
||||
LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel));
|
||||
if (log_channel_sp) {
|
||||
if (log_channel_sp->Enable(log_stream_sp, log_options, &error_stream,
|
||||
categories)) {
|
||||
return true;
|
||||
} else {
|
||||
error_stream.Printf("Invalid log channel '%s'.\n", channel);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
error_stream.Printf("Invalid log channel '%s'.\n", channel);
|
||||
return false;
|
||||
}
|
||||
uint32_t flags = categories && categories[0]
|
||||
? GetFlags(error_stream, *iter, categories)
|
||||
: iter->second.channel.default_flags;
|
||||
iter->second.channel.Enable(iter->second.log, log_stream_sp, flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Log::DisableLogChannel(llvm::StringRef channel, const char **categories,
|
||||
Stream &error_stream) {
|
||||
Log::Callbacks log_callbacks;
|
||||
if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
|
||||
log_callbacks.disable(categories, &error_stream);
|
||||
return true;
|
||||
}
|
||||
void Log::EnableAllLogChannels(
|
||||
const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
|
||||
uint32_t log_options, const char **categories, Stream *feedback_strm) {
|
||||
CallbackMap &callback_map = GetCallbackMap();
|
||||
CallbackMapIter pos, end = callback_map.end();
|
||||
|
||||
auto iter = g_channel_map->find(channel);
|
||||
if (iter == g_channel_map->end()) {
|
||||
error_stream.Format("Invalid log channel '{0}'.\n", channel);
|
||||
return false;
|
||||
for (pos = callback_map.begin(); pos != end; ++pos)
|
||||
pos->second.enable(log_stream_sp, log_options, categories, feedback_strm);
|
||||
|
||||
LogChannelMap &channel_map = GetChannelMap();
|
||||
LogChannelMapIter channel_pos, channel_end = channel_map.end();
|
||||
for (channel_pos = channel_map.begin(); channel_pos != channel_end;
|
||||
++channel_pos) {
|
||||
channel_pos->second->Enable(log_stream_sp, log_options, feedback_strm,
|
||||
categories);
|
||||
}
|
||||
uint32_t flags = categories && categories[0]
|
||||
? GetFlags(error_stream, *iter, categories)
|
||||
: UINT32_MAX;
|
||||
iter->second.channel.Disable(flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Log::ListChannelCategories(llvm::StringRef channel, Stream &stream) {
|
||||
Log::Callbacks log_callbacks;
|
||||
if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
|
||||
log_callbacks.list_categories(&stream);
|
||||
return true;
|
||||
void Log::AutoCompleteChannelName(const char *channel_name,
|
||||
StringList &matches) {
|
||||
LogChannelMap &map = GetChannelMap();
|
||||
LogChannelMapIter pos, end = map.end();
|
||||
for (pos = map.begin(); pos != end; ++pos) {
|
||||
const char *pos_channel_name = pos->first.GetCString();
|
||||
if (channel_name && channel_name[0]) {
|
||||
if (NameMatches(channel_name, eNameMatchStartsWith, pos_channel_name)) {
|
||||
matches.AppendString(pos_channel_name);
|
||||
}
|
||||
} else
|
||||
matches.AppendString(pos_channel_name);
|
||||
}
|
||||
|
||||
auto ch = g_channel_map->find(channel);
|
||||
if (ch == g_channel_map->end()) {
|
||||
stream.Format("Invalid log channel '{0}'.\n", channel);
|
||||
return false;
|
||||
}
|
||||
ListCategories(stream, *ch);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Log::DisableAllLogChannels(Stream *feedback_strm) {
|
||||
|
@ -331,8 +254,11 @@ void Log::DisableAllLogChannels(Stream *feedback_strm) {
|
|||
for (pos = callback_map.begin(); pos != end; ++pos)
|
||||
pos->second.disable(categories, feedback_strm);
|
||||
|
||||
for (auto &entry : *g_channel_map)
|
||||
entry.second.channel.Disable(UINT32_MAX);
|
||||
LogChannelMap &channel_map = GetChannelMap();
|
||||
LogChannelMapIter channel_pos, channel_end = channel_map.end();
|
||||
for (channel_pos = channel_map.begin(); channel_pos != channel_end;
|
||||
++channel_pos)
|
||||
channel_pos->second->Disable(categories, feedback_strm);
|
||||
}
|
||||
|
||||
void Log::Initialize() {
|
||||
|
@ -344,8 +270,9 @@ void Log::Terminate() { DisableAllLogChannels(nullptr); }
|
|||
|
||||
void Log::ListAllLogChannels(Stream *strm) {
|
||||
CallbackMap &callback_map = GetCallbackMap();
|
||||
LogChannelMap &channel_map = GetChannelMap();
|
||||
|
||||
if (callback_map.empty() && g_channel_map->empty()) {
|
||||
if (callback_map.empty() && channel_map.empty()) {
|
||||
strm->PutCString("No logging channels are currently registered.\n");
|
||||
return;
|
||||
}
|
||||
|
@ -354,9 +281,17 @@ void Log::ListAllLogChannels(Stream *strm) {
|
|||
for (pos = callback_map.begin(); pos != end; ++pos)
|
||||
pos->second.list_categories(strm);
|
||||
|
||||
for (const auto &channel : *g_channel_map)
|
||||
ListCategories(*strm, channel);
|
||||
uint32_t idx = 0;
|
||||
const char *name;
|
||||
for (idx = 0;
|
||||
(name = PluginManager::GetLogChannelCreateNameAtIndex(idx)) != nullptr;
|
||||
++idx) {
|
||||
LogChannelSP log_channel_sp(LogChannel::FindPlugin(name));
|
||||
if (log_channel_sp)
|
||||
log_channel_sp->ListCategories(strm);
|
||||
}
|
||||
}
|
||||
|
||||
bool Log::GetVerbose() const { return m_options.Test(LLDB_LOG_OPTION_VERBOSE); }
|
||||
|
||||
void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
|
||||
|
@ -423,3 +358,33 @@ void Log::Format(llvm::StringRef file, llvm::StringRef function,
|
|||
message << payload << "\n";
|
||||
WriteMessage(message.str());
|
||||
}
|
||||
|
||||
LogChannelSP LogChannel::FindPlugin(const char *plugin_name) {
|
||||
LogChannelSP log_channel_sp;
|
||||
LogChannelMap &channel_map = GetChannelMap();
|
||||
ConstString log_channel_name(plugin_name);
|
||||
LogChannelMapIter pos = channel_map.find(log_channel_name);
|
||||
if (pos == channel_map.end()) {
|
||||
ConstString const_plugin_name(plugin_name);
|
||||
LogChannelCreateInstance create_callback =
|
||||
PluginManager::GetLogChannelCreateCallbackForPluginName(
|
||||
const_plugin_name);
|
||||
if (create_callback) {
|
||||
log_channel_sp.reset(create_callback());
|
||||
if (log_channel_sp) {
|
||||
// Cache the one and only loaded instance of each log channel
|
||||
// plug-in after it has been loaded once.
|
||||
channel_map[log_channel_name] = log_channel_sp;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We have already loaded an instance of this log channel class,
|
||||
// so just return the cached instance.
|
||||
log_channel_sp = pos->second;
|
||||
}
|
||||
return log_channel_sp;
|
||||
}
|
||||
|
||||
LogChannel::LogChannel() : m_log_ap() {}
|
||||
|
||||
LogChannel::~LogChannel() = default;
|
||||
|
|
|
@ -1167,6 +1167,93 @@ PluginManager::GetObjectContainerGetModuleSpecificationsCallbackAtIndex(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
#pragma mark LogChannel
|
||||
|
||||
struct LogInstance {
|
||||
LogInstance() : name(), description(), create_callback(nullptr) {}
|
||||
|
||||
ConstString name;
|
||||
std::string description;
|
||||
LogChannelCreateInstance create_callback;
|
||||
};
|
||||
|
||||
typedef std::vector<LogInstance> LogInstances;
|
||||
|
||||
static std::recursive_mutex &GetLogMutex() {
|
||||
static std::recursive_mutex g_instances_mutex;
|
||||
return g_instances_mutex;
|
||||
}
|
||||
|
||||
static LogInstances &GetLogInstances() {
|
||||
static LogInstances g_instances;
|
||||
return g_instances;
|
||||
}
|
||||
|
||||
bool PluginManager::RegisterPlugin(const ConstString &name,
|
||||
const char *description,
|
||||
LogChannelCreateInstance create_callback) {
|
||||
if (create_callback) {
|
||||
LogInstance instance;
|
||||
assert((bool)name);
|
||||
instance.name = name;
|
||||
if (description && description[0])
|
||||
instance.description = description;
|
||||
instance.create_callback = create_callback;
|
||||
std::lock_guard<std::recursive_mutex> gard(GetLogMutex());
|
||||
GetLogInstances().push_back(instance);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PluginManager::UnregisterPlugin(LogChannelCreateInstance create_callback) {
|
||||
if (create_callback) {
|
||||
std::lock_guard<std::recursive_mutex> gard(GetLogMutex());
|
||||
LogInstances &instances = GetLogInstances();
|
||||
|
||||
LogInstances::iterator pos, end = instances.end();
|
||||
for (pos = instances.begin(); pos != end; ++pos) {
|
||||
if (pos->create_callback == create_callback) {
|
||||
instances.erase(pos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *PluginManager::GetLogChannelCreateNameAtIndex(uint32_t idx) {
|
||||
std::lock_guard<std::recursive_mutex> gard(GetLogMutex());
|
||||
LogInstances &instances = GetLogInstances();
|
||||
if (idx < instances.size())
|
||||
return instances[idx].name.GetCString();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LogChannelCreateInstance
|
||||
PluginManager::GetLogChannelCreateCallbackAtIndex(uint32_t idx) {
|
||||
std::lock_guard<std::recursive_mutex> gard(GetLogMutex());
|
||||
LogInstances &instances = GetLogInstances();
|
||||
if (idx < instances.size())
|
||||
return instances[idx].create_callback;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LogChannelCreateInstance
|
||||
PluginManager::GetLogChannelCreateCallbackForPluginName(
|
||||
const ConstString &name) {
|
||||
if (name) {
|
||||
std::lock_guard<std::recursive_mutex> gard(GetLogMutex());
|
||||
LogInstances &instances = GetLogInstances();
|
||||
|
||||
LogInstances::iterator pos, end = instances.end();
|
||||
for (pos = instances.begin(); pos != end; ++pos) {
|
||||
if (name == pos->name)
|
||||
return pos->create_callback;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#pragma mark Platform
|
||||
|
||||
struct PlatformInstance {
|
||||
|
|
|
@ -9,28 +9,192 @@
|
|||
|
||||
#include "LogChannelDWARF.h"
|
||||
|
||||
#include "SymbolFileDWARF.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Core/StreamFile.h"
|
||||
#include "lldb/Interpreter/Args.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
static constexpr Log::Category g_categories[] = {
|
||||
{"aranges", "log the parsing of .debug_aranges", DWARF_LOG_DEBUG_ARANGES},
|
||||
{"comp", "log insertions of object files into DWARF debug maps",
|
||||
DWARF_LOG_TYPE_COMPLETION},
|
||||
{"info", "log the parsing of .debug_info", DWARF_LOG_DEBUG_INFO},
|
||||
{"line", "log the parsing of .debug_line", DWARF_LOG_DEBUG_LINE},
|
||||
{"lookups", "log any lookups that happen by name, regex, or address",
|
||||
DWARF_LOG_LOOKUPS},
|
||||
{"map", "log struct/unions/class type completions", DWARF_LOG_DEBUG_MAP},
|
||||
{"pubnames", "log the parsing of .debug_pubnames",
|
||||
DWARF_LOG_DEBUG_PUBNAMES},
|
||||
{"pubtypes", "log the parsing of .debug_pubtypes",
|
||||
DWARF_LOG_DEBUG_PUBTYPES},
|
||||
};
|
||||
// when the one and only logging channel is enabled, then this will be non NULL.
|
||||
static LogChannelDWARF *g_log_channel = NULL;
|
||||
|
||||
Log::Channel LogChannelDWARF::g_channel(g_categories, DWARF_LOG_DEFAULT);
|
||||
LogChannelDWARF::LogChannelDWARF() : LogChannel() {}
|
||||
|
||||
LogChannelDWARF::~LogChannelDWARF() {}
|
||||
|
||||
void LogChannelDWARF::Initialize() {
|
||||
Log::Register("dwarf", g_channel);
|
||||
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
||||
GetPluginDescriptionStatic(),
|
||||
LogChannelDWARF::CreateInstance);
|
||||
}
|
||||
|
||||
void LogChannelDWARF::Terminate() { Log::Unregister("dwarf"); }
|
||||
void LogChannelDWARF::Terminate() {
|
||||
PluginManager::UnregisterPlugin(LogChannelDWARF::CreateInstance);
|
||||
}
|
||||
|
||||
LogChannel *LogChannelDWARF::CreateInstance() { return new LogChannelDWARF(); }
|
||||
|
||||
lldb_private::ConstString LogChannelDWARF::GetPluginNameStatic() {
|
||||
return SymbolFileDWARF::GetPluginNameStatic();
|
||||
}
|
||||
|
||||
const char *LogChannelDWARF::GetPluginDescriptionStatic() {
|
||||
return "DWARF log channel for debugging plug-in issues.";
|
||||
}
|
||||
|
||||
lldb_private::ConstString LogChannelDWARF::GetPluginName() {
|
||||
return GetPluginNameStatic();
|
||||
}
|
||||
|
||||
uint32_t LogChannelDWARF::GetPluginVersion() { return 1; }
|
||||
|
||||
void LogChannelDWARF::Delete() { g_log_channel = NULL; }
|
||||
|
||||
void LogChannelDWARF::Disable(const char **categories, Stream *feedback_strm) {
|
||||
if (m_log_ap.get() == NULL)
|
||||
return;
|
||||
|
||||
uint32_t flag_bits = m_log_ap->GetMask().Get();
|
||||
for (size_t i = 0; categories[i] != NULL; ++i) {
|
||||
const char *arg = categories[i];
|
||||
|
||||
if (::strcasecmp(arg, "all") == 0)
|
||||
flag_bits &= ~DWARF_LOG_ALL;
|
||||
else if (::strcasecmp(arg, "info") == 0)
|
||||
flag_bits &= ~DWARF_LOG_DEBUG_INFO;
|
||||
else if (::strcasecmp(arg, "line") == 0)
|
||||
flag_bits &= ~DWARF_LOG_DEBUG_LINE;
|
||||
else if (::strcasecmp(arg, "pubnames") == 0)
|
||||
flag_bits &= ~DWARF_LOG_DEBUG_PUBNAMES;
|
||||
else if (::strcasecmp(arg, "pubtypes") == 0)
|
||||
flag_bits &= ~DWARF_LOG_DEBUG_PUBTYPES;
|
||||
else if (::strcasecmp(arg, "aranges") == 0)
|
||||
flag_bits &= ~DWARF_LOG_DEBUG_ARANGES;
|
||||
else if (::strcasecmp(arg, "lookups") == 0)
|
||||
flag_bits &= ~DWARF_LOG_LOOKUPS;
|
||||
else if (::strcasecmp(arg, "map") == 0)
|
||||
flag_bits &= ~DWARF_LOG_DEBUG_MAP;
|
||||
else if (::strcasecmp(arg, "default") == 0)
|
||||
flag_bits &= ~DWARF_LOG_DEFAULT;
|
||||
else if (::strncasecmp(arg, "comp", 4) == 0)
|
||||
flag_bits &= ~DWARF_LOG_TYPE_COMPLETION;
|
||||
else {
|
||||
feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
|
||||
ListCategories(feedback_strm);
|
||||
}
|
||||
}
|
||||
|
||||
if (flag_bits == 0)
|
||||
Delete();
|
||||
else
|
||||
m_log_ap->GetMask().Reset(flag_bits);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool LogChannelDWARF::Enable(
|
||||
const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
|
||||
uint32_t log_options,
|
||||
Stream *feedback_strm, // Feedback stream for argument errors etc
|
||||
const char **categories // The categories to enable within this logging
|
||||
// stream, if empty, enable default set
|
||||
) {
|
||||
Delete();
|
||||
|
||||
if (m_log_ap)
|
||||
m_log_ap->SetStream(log_stream_sp);
|
||||
else
|
||||
m_log_ap.reset(new Log(log_stream_sp));
|
||||
|
||||
g_log_channel = this;
|
||||
uint32_t flag_bits = 0;
|
||||
bool got_unknown_category = false;
|
||||
for (size_t i = 0; categories[i] != NULL; ++i) {
|
||||
const char *arg = categories[i];
|
||||
|
||||
if (::strcasecmp(arg, "all") == 0)
|
||||
flag_bits |= DWARF_LOG_ALL;
|
||||
else if (::strcasecmp(arg, "info") == 0)
|
||||
flag_bits |= DWARF_LOG_DEBUG_INFO;
|
||||
else if (::strcasecmp(arg, "line") == 0)
|
||||
flag_bits |= DWARF_LOG_DEBUG_LINE;
|
||||
else if (::strcasecmp(arg, "pubnames") == 0)
|
||||
flag_bits |= DWARF_LOG_DEBUG_PUBNAMES;
|
||||
else if (::strcasecmp(arg, "pubtypes") == 0)
|
||||
flag_bits |= DWARF_LOG_DEBUG_PUBTYPES;
|
||||
else if (::strcasecmp(arg, "aranges") == 0)
|
||||
flag_bits |= DWARF_LOG_DEBUG_ARANGES;
|
||||
else if (::strcasecmp(arg, "lookups") == 0)
|
||||
flag_bits |= DWARF_LOG_LOOKUPS;
|
||||
else if (::strcasecmp(arg, "map") == 0)
|
||||
flag_bits |= DWARF_LOG_DEBUG_MAP;
|
||||
else if (::strcasecmp(arg, "default") == 0)
|
||||
flag_bits |= DWARF_LOG_DEFAULT;
|
||||
else if (::strncasecmp(arg, "comp", 4) == 0)
|
||||
flag_bits |= DWARF_LOG_TYPE_COMPLETION;
|
||||
else {
|
||||
feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
|
||||
if (got_unknown_category == false) {
|
||||
got_unknown_category = true;
|
||||
ListCategories(feedback_strm);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag_bits == 0)
|
||||
flag_bits = DWARF_LOG_DEFAULT;
|
||||
m_log_ap->GetMask().Reset(flag_bits);
|
||||
m_log_ap->GetOptions().Reset(log_options);
|
||||
return m_log_ap.get() != NULL;
|
||||
}
|
||||
|
||||
void LogChannelDWARF::ListCategories(Stream *strm) {
|
||||
strm->Printf(
|
||||
"Logging categories for '%s':\n"
|
||||
" all - turn on all available logging categories\n"
|
||||
" info - log the parsing of .debug_info\n"
|
||||
" line - log the parsing of .debug_line\n"
|
||||
" pubnames - log the parsing of .debug_pubnames\n"
|
||||
" pubtypes - log the parsing of .debug_pubtypes\n"
|
||||
" aranges - log the parsing of .debug_aranges\n"
|
||||
" lookups - log any lookups that happen by name, regex, or address\n"
|
||||
" completion - log struct/unions/class type completions\n"
|
||||
" map - log insertions of object files into DWARF debug maps\n",
|
||||
SymbolFileDWARF::GetPluginNameStatic().GetCString());
|
||||
}
|
||||
|
||||
Log *LogChannelDWARF::GetLog() {
|
||||
if (g_log_channel)
|
||||
return g_log_channel->m_log_ap.get();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Log *LogChannelDWARF::GetLogIfAll(uint32_t mask) {
|
||||
if (g_log_channel && g_log_channel->m_log_ap.get()) {
|
||||
if (g_log_channel->m_log_ap->GetMask().AllSet(mask))
|
||||
return g_log_channel->m_log_ap.get();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Log *LogChannelDWARF::GetLogIfAny(uint32_t mask) {
|
||||
if (g_log_channel && g_log_channel->m_log_ap.get()) {
|
||||
if (g_log_channel->m_log_ap->GetMask().AnySet(mask))
|
||||
return g_log_channel->m_log_ap.get();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LogChannelDWARF::LogIf(uint32_t mask, const char *format, ...) {
|
||||
if (g_log_channel) {
|
||||
Log *log = g_log_channel->m_log_ap.get();
|
||||
if (log && log->GetMask().AnySet(mask)) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log->VAPrintf(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,17 +27,48 @@
|
|||
#define DWARF_LOG_ALL (UINT32_MAX)
|
||||
#define DWARF_LOG_DEFAULT (DWARF_LOG_DEBUG_INFO)
|
||||
|
||||
namespace lldb_private {
|
||||
class LogChannelDWARF {
|
||||
static Log::Channel g_channel;
|
||||
|
||||
class LogChannelDWARF : public lldb_private::LogChannel {
|
||||
public:
|
||||
LogChannelDWARF();
|
||||
|
||||
~LogChannelDWARF() override;
|
||||
|
||||
static void Initialize();
|
||||
|
||||
static void Terminate();
|
||||
|
||||
static Log *GetLogIfAll(uint32_t mask) { return g_channel.GetLogIfAll(mask); }
|
||||
static Log *GetLogIfAny(uint32_t mask) { return g_channel.GetLogIfAny(mask); }
|
||||
static lldb_private::ConstString GetPluginNameStatic();
|
||||
|
||||
static const char *GetPluginDescriptionStatic();
|
||||
|
||||
static lldb_private::LogChannel *CreateInstance();
|
||||
|
||||
lldb_private::ConstString GetPluginName() override;
|
||||
|
||||
uint32_t GetPluginVersion() override;
|
||||
|
||||
void Disable(const char **categories,
|
||||
lldb_private::Stream *feedback_strm) override;
|
||||
|
||||
void Delete();
|
||||
|
||||
bool Enable(const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
|
||||
uint32_t log_options,
|
||||
lldb_private::Stream
|
||||
*feedback_strm, // Feedback stream for argument errors etc
|
||||
const char **categories) override; // The categories to enable
|
||||
// within this logging stream,
|
||||
// if empty, enable default set
|
||||
|
||||
void ListCategories(lldb_private::Stream *strm) override;
|
||||
|
||||
static lldb_private::Log *GetLog();
|
||||
|
||||
static lldb_private::Log *GetLogIfAll(uint32_t mask);
|
||||
|
||||
static lldb_private::Log *GetLogIfAny(uint32_t mask);
|
||||
|
||||
static void LogIf(uint32_t mask, const char *format, ...);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SymbolFileDWARF_LogChannelDWARF_h_
|
||||
|
|
|
@ -223,7 +223,7 @@ void SymbolFileDWARF::DebuggerInitialize(Debugger &debugger) {
|
|||
|
||||
void SymbolFileDWARF::Terminate() {
|
||||
PluginManager::UnregisterPlugin(CreateInstance);
|
||||
LogChannelDWARF::Terminate();
|
||||
LogChannelDWARF::Initialize();
|
||||
}
|
||||
|
||||
lldb_private::ConstString SymbolFileDWARF::GetPluginNameStatic() {
|
||||
|
|
|
@ -12,30 +12,10 @@
|
|||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Utility/StreamString.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
enum { FOO = 1, BAR = 2 };
|
||||
static constexpr Log::Category test_categories[] = {
|
||||
{"foo", "log foo", FOO}, {"bar", "log bar", BAR},
|
||||
};
|
||||
static constexpr uint32_t default_flags = FOO;
|
||||
|
||||
static Log::Channel test_channel(test_categories, default_flags);
|
||||
|
||||
struct LogChannelTest : public ::testing::Test {
|
||||
static void SetUpTestCase() {
|
||||
Log::Register("chan", test_channel);
|
||||
}
|
||||
|
||||
static void TearDownTestCase() {
|
||||
Log::Unregister("chan");
|
||||
llvm::llvm_shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
static std::string GetLogString(uint32_t log_options, const char *format,
|
||||
int arg) {
|
||||
std::string stream_string;
|
||||
|
@ -77,96 +57,3 @@ TEST(LogTest, log_options) {
|
|||
GetLogString(LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD,
|
||||
"Hello World {0}", 47));
|
||||
}
|
||||
|
||||
TEST(LogTest, Register) {
|
||||
llvm::llvm_shutdown_obj obj;
|
||||
Log::Register("chan", test_channel);
|
||||
Log::Unregister("chan");
|
||||
Log::Register("chan", test_channel);
|
||||
Log::Unregister("chan");
|
||||
}
|
||||
|
||||
TEST(LogTest, Unregister) {
|
||||
llvm::llvm_shutdown_obj obj;
|
||||
Log::Register("chan", test_channel);
|
||||
EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO));
|
||||
const char *cat1[] = {"foo", nullptr};
|
||||
std::string message;
|
||||
std::shared_ptr<llvm::raw_string_ostream> stream_sp(
|
||||
new llvm::raw_string_ostream(message));
|
||||
StreamString err;
|
||||
EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat1, err));
|
||||
EXPECT_NE(nullptr, test_channel.GetLogIfAny(FOO));
|
||||
Log::Unregister("chan");
|
||||
EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO));
|
||||
}
|
||||
|
||||
TEST_F(LogChannelTest, Enable) {
|
||||
EXPECT_EQ(nullptr, test_channel.GetLogIfAll(FOO));
|
||||
std::string message;
|
||||
std::shared_ptr<llvm::raw_string_ostream> stream_sp(
|
||||
new llvm::raw_string_ostream(message));
|
||||
StreamString err;
|
||||
EXPECT_FALSE(Log::EnableLogChannel(stream_sp, 0, "chanchan", nullptr, err));
|
||||
EXPECT_EQ("Invalid log channel 'chanchan'.\n", err.GetString());
|
||||
err.Clear();
|
||||
|
||||
EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", nullptr, err));
|
||||
EXPECT_EQ("", err.GetString());
|
||||
EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO));
|
||||
EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR));
|
||||
|
||||
const char *cat2[] = {"bar", nullptr};
|
||||
EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat2, err));
|
||||
EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR));
|
||||
|
||||
const char *cat3[] = {"baz", nullptr};
|
||||
EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat3, err));
|
||||
EXPECT_TRUE(err.GetString().contains("unrecognized log category 'baz'"))
|
||||
<< "err: " << err.GetString().str();
|
||||
EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR));
|
||||
}
|
||||
|
||||
TEST_F(LogChannelTest, Disable) {
|
||||
EXPECT_EQ(nullptr, test_channel.GetLogIfAll(FOO));
|
||||
const char *cat12[] = {"foo", "bar", nullptr};
|
||||
std::string message;
|
||||
std::shared_ptr<llvm::raw_string_ostream> stream_sp(
|
||||
new llvm::raw_string_ostream(message));
|
||||
StreamString err;
|
||||
EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat12, err));
|
||||
EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR));
|
||||
|
||||
const char *cat2[] = {"bar", nullptr};
|
||||
EXPECT_TRUE(Log::DisableLogChannel("chan", cat2, err));
|
||||
EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO));
|
||||
EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR));
|
||||
|
||||
const char *cat3[] = {"baz", nullptr};
|
||||
EXPECT_TRUE(Log::DisableLogChannel("chan", cat3, err));
|
||||
EXPECT_TRUE(err.GetString().contains("unrecognized log category 'baz'"))
|
||||
<< "err: " << err.GetString().str();
|
||||
EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO));
|
||||
EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR));
|
||||
err.Clear();
|
||||
|
||||
EXPECT_TRUE(Log::DisableLogChannel("chan", nullptr, err));
|
||||
EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO | BAR));
|
||||
}
|
||||
|
||||
TEST_F(LogChannelTest, List) {
|
||||
StreamString str;
|
||||
EXPECT_TRUE(Log::ListChannelCategories("chan", str));
|
||||
std::string expected =
|
||||
R"(Logging categories for 'chan':
|
||||
all - all available logging categories
|
||||
default - default set of logging categories
|
||||
foo - log foo
|
||||
bar - log bar
|
||||
)";
|
||||
EXPECT_EQ(expected, str.GetString().str());
|
||||
str.Clear();
|
||||
|
||||
EXPECT_FALSE(Log::ListChannelCategories("chanchan", str));
|
||||
EXPECT_EQ("Invalid log channel 'chanchan'.\n", str.GetString().str());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue