forked from OSchip/llvm-project
Refactor log channel registration mechanism
Summary: We currently have two log channel registration mechanisms. One uses a set of function pointers and the other one is based on the PluginManager. The PluginManager dependency is unfortunate, as logging is also used in lldb-server, and the PluginManager pulls in a lot of classes which are not used in lldb-server. Both approach have the problem that they leave too much to do for the user, and so the individual log channels end up reimplementing command line argument parsing, category listing, etc. Here, I replace the PluginManager-based approach with a one. The new API is more declarative, so the user only needs to specify the list of list of channels, their descriptions, etc., and all the common tasks like enabling/disabling categories are hadled by common code. I migrate the LogChannelDWARF (only user of the PluginManager method) to the new API. In the follow-up commits I'll replace the other channels with something similar. Reviewers: clayborg, zturner, beanz Subscribers: aprantl, lldb-commits Differential Revision: https://reviews.llvm.org/D29895 llvm-svn: 295190
This commit is contained in:
parent
cf8af0ad61
commit
5fb8af40df
|
@ -44,6 +44,53 @@ 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.
|
||||
//------------------------------------------------------------------
|
||||
|
@ -63,6 +110,9 @@ 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);
|
||||
|
||||
|
@ -73,13 +123,13 @@ public:
|
|||
|
||||
static bool
|
||||
EnableLogChannel(const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
|
||||
uint32_t log_options, const char *channel,
|
||||
uint32_t log_options, llvm::StringRef channel,
|
||||
const char **categories, Stream &error_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 bool DisableLogChannel(llvm::StringRef channel,
|
||||
const char **categories, Stream &error_stream);
|
||||
|
||||
static bool ListChannelCategories(llvm::StringRef channel, Stream &stream);
|
||||
|
||||
static void DisableAllLogChannels(Stream *feedback_strm);
|
||||
|
||||
|
@ -89,12 +139,6 @@ public:
|
|||
|
||||
static void Terminate();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Auto completion
|
||||
//------------------------------------------------------------------
|
||||
static void AutoCompleteChannelName(const char *channel_name,
|
||||
StringList &matches);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Member functions
|
||||
//------------------------------------------------------------------
|
||||
|
@ -162,34 +206,6 @@ 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,22 +209,6 @@ 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,7 +127,6 @@ class MemoryRegionInfo;
|
|||
class LineTable;
|
||||
class Listener;
|
||||
class Log;
|
||||
class LogChannel;
|
||||
class Mangled;
|
||||
class Materializer;
|
||||
class MemoryHistory;
|
||||
|
@ -362,7 +361,6 @@ 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,7 +45,6 @@ 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,25 +227,15 @@ protected:
|
|||
return false;
|
||||
}
|
||||
|
||||
Log::Callbacks log_callbacks;
|
||||
|
||||
const std::string channel = args[0].ref;
|
||||
args.Shift(); // Shift off the channel
|
||||
if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
|
||||
log_callbacks.disable(args.GetConstArgumentVector(),
|
||||
&result.GetErrorStream());
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
} else if (channel == "all") {
|
||||
if (channel == "all") {
|
||||
Log::DisableAllLogChannels(&result.GetErrorStream());
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
} else {
|
||||
LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel.data()));
|
||||
if (log_channel_sp) {
|
||||
log_channel_sp->Disable(args.GetConstArgumentVector(),
|
||||
&result.GetErrorStream());
|
||||
if (Log::DisableLogChannel(channel, args.GetConstArgumentVector(),
|
||||
result.GetErrorStream()))
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
} else
|
||||
result.AppendErrorWithFormat("Invalid log channel '%s'.\n",
|
||||
channel.data());
|
||||
}
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
@ -284,26 +274,12 @@ protected:
|
|||
Log::ListAllLogChannels(&result.GetOutputStream());
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
} else {
|
||||
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());
|
||||
}
|
||||
}
|
||||
bool success = true;
|
||||
for (const auto &entry : args.entries())
|
||||
success = success && Log::ListChannelCategories(
|
||||
entry.ref, result.GetOutputStream());
|
||||
if (success)
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
}
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
#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"
|
||||
|
@ -36,6 +38,76 @@
|
|||
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)
|
||||
|
@ -152,9 +224,6 @@ 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() {
|
||||
|
@ -162,9 +231,17 @@ static CallbackMap &GetCallbackMap() {
|
|||
return g_callback_map;
|
||||
}
|
||||
|
||||
static LogChannelMap &GetChannelMap() {
|
||||
static LogChannelMap g_channel_map;
|
||||
return g_channel_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);
|
||||
}
|
||||
|
||||
void Log::RegisterLogChannel(const ConstString &channel,
|
||||
|
@ -190,7 +267,7 @@ bool Log::GetLogChannelCallbacks(const ConstString &channel,
|
|||
|
||||
bool Log::EnableLogChannel(
|
||||
const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
|
||||
uint32_t log_options, const char *channel, const char **categories,
|
||||
uint32_t log_options, llvm::StringRef channel, const char **categories,
|
||||
Stream &error_stream) {
|
||||
Log::Callbacks log_callbacks;
|
||||
if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
|
||||
|
@ -198,52 +275,52 @@ bool Log::EnableLogChannel(
|
|||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
auto iter = g_channel_map->find(channel);
|
||||
if (iter == g_channel_map->end()) {
|
||||
error_stream.Format("Invalid log channel '{0}'.\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;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
auto iter = g_channel_map->find(channel);
|
||||
if (iter == g_channel_map->end()) {
|
||||
error_stream.Format("Invalid log channel '{0}'.\n", channel);
|
||||
return false;
|
||||
}
|
||||
uint32_t flags = categories && categories[0]
|
||||
? GetFlags(error_stream, *iter, categories)
|
||||
: UINT32_MAX;
|
||||
iter->second.channel.Disable(flags);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -254,11 +331,8 @@ void Log::DisableAllLogChannels(Stream *feedback_strm) {
|
|||
for (pos = callback_map.begin(); pos != end; ++pos)
|
||||
pos->second.disable(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->Disable(categories, feedback_strm);
|
||||
for (auto &entry : *g_channel_map)
|
||||
entry.second.channel.Disable(UINT32_MAX);
|
||||
}
|
||||
|
||||
void Log::Initialize() {
|
||||
|
@ -270,9 +344,8 @@ void Log::Terminate() { DisableAllLogChannels(nullptr); }
|
|||
|
||||
void Log::ListAllLogChannels(Stream *strm) {
|
||||
CallbackMap &callback_map = GetCallbackMap();
|
||||
LogChannelMap &channel_map = GetChannelMap();
|
||||
|
||||
if (callback_map.empty() && channel_map.empty()) {
|
||||
if (callback_map.empty() && g_channel_map->empty()) {
|
||||
strm->PutCString("No logging channels are currently registered.\n");
|
||||
return;
|
||||
}
|
||||
|
@ -281,17 +354,9 @@ void Log::ListAllLogChannels(Stream *strm) {
|
|||
for (pos = callback_map.begin(); pos != end; ++pos)
|
||||
pos->second.list_categories(strm);
|
||||
|
||||
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);
|
||||
}
|
||||
for (const auto &channel : *g_channel_map)
|
||||
ListCategories(*strm, channel);
|
||||
}
|
||||
|
||||
bool Log::GetVerbose() const { return m_options.Test(LLDB_LOG_OPTION_VERBOSE); }
|
||||
|
||||
void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
|
||||
|
@ -358,33 +423,3 @@ 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,93 +1167,6 @@ 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,192 +9,28 @@
|
|||
|
||||
#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;
|
||||
|
||||
// when the one and only logging channel is enabled, then this will be non NULL.
|
||||
static LogChannelDWARF *g_log_channel = NULL;
|
||||
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},
|
||||
};
|
||||
|
||||
LogChannelDWARF::LogChannelDWARF() : LogChannel() {}
|
||||
|
||||
LogChannelDWARF::~LogChannelDWARF() {}
|
||||
Log::Channel LogChannelDWARF::g_channel(g_categories, DWARF_LOG_DEFAULT);
|
||||
|
||||
void LogChannelDWARF::Initialize() {
|
||||
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
||||
GetPluginDescriptionStatic(),
|
||||
LogChannelDWARF::CreateInstance);
|
||||
Log::Register("dwarf", g_channel);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
void LogChannelDWARF::Terminate() { Log::Unregister("dwarf"); }
|
||||
|
|
|
@ -27,48 +27,17 @@
|
|||
#define DWARF_LOG_ALL (UINT32_MAX)
|
||||
#define DWARF_LOG_DEFAULT (DWARF_LOG_DEBUG_INFO)
|
||||
|
||||
class LogChannelDWARF : public lldb_private::LogChannel {
|
||||
namespace lldb_private {
|
||||
class LogChannelDWARF {
|
||||
static Log::Channel g_channel;
|
||||
|
||||
public:
|
||||
LogChannelDWARF();
|
||||
|
||||
~LogChannelDWARF() override;
|
||||
|
||||
static void Initialize();
|
||||
|
||||
static void Terminate();
|
||||
|
||||
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, ...);
|
||||
static Log *GetLogIfAll(uint32_t mask) { return g_channel.GetLogIfAll(mask); }
|
||||
static Log *GetLogIfAny(uint32_t mask) { return g_channel.GetLogIfAny(mask); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SymbolFileDWARF_LogChannelDWARF_h_
|
||||
|
|
|
@ -223,7 +223,7 @@ void SymbolFileDWARF::DebuggerInitialize(Debugger &debugger) {
|
|||
|
||||
void SymbolFileDWARF::Terminate() {
|
||||
PluginManager::UnregisterPlugin(CreateInstance);
|
||||
LogChannelDWARF::Initialize();
|
||||
LogChannelDWARF::Terminate();
|
||||
}
|
||||
|
||||
lldb_private::ConstString SymbolFileDWARF::GetPluginNameStatic() {
|
||||
|
|
|
@ -12,10 +12,30 @@
|
|||
#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;
|
||||
|
@ -57,3 +77,96 @@ 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