You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Conception/drake-master/common/text_logging.cc

152 lines
4.6 KiB

#include "drake/common/text_logging.h"
#include <memory>
#include <mutex>
#include <utility>
#ifdef HAVE_SPDLOG
#include <spdlog/sinks/dist_sink.h>
#include <spdlog/sinks/stdout_sinks.h>
#endif
#include "drake/common/never_destroyed.h"
namespace drake {
#ifdef HAVE_SPDLOG
namespace {
// Returns the default logger. NOTE: This function assumes that it is mutexed,
// as in the initializer of a static local.
std::shared_ptr<logging::logger> onetime_create_log() {
// Check if anyone has already set up a logger named "console". If so, we
// will just return it; if not, we'll create our own default one.
std::shared_ptr<logging::logger> result(spdlog::get("console"));
if (!result) {
// We wrap our stderr sink in a dist_sink so that users can atomically swap
// out the sinks used by all Drake logging, via dist_sink_mt's APIs.
auto wrapper = std::make_shared<spdlog::sinks::dist_sink_mt>();
// We use the stderr_sink_mt (instead of stderr_sink_st) so more than one
// thread can use this logger and have their messages be staggered by line,
// instead of co-mingling their character bytes.
wrapper->add_sink(std::make_shared<spdlog::sinks::stderr_sink_mt>());
result = std::make_shared<logging::logger>("console", std::move(wrapper));
result->set_level(spdlog::level::info);
}
return result;
}
} // namespace
logging::logger* log() {
static const never_destroyed<std::shared_ptr<logging::logger>> g_logger(
onetime_create_log());
return g_logger.access().get();
}
logging::sink* logging::get_dist_sink() {
// Extract the dist_sink_mt from Drake's logger instance.
auto* sink = log()->sinks().empty() ? nullptr : log()->sinks().front().get();
auto* result = dynamic_cast<spdlog::sinks::dist_sink_mt*>(sink);
if (result == nullptr) {
throw std::logic_error(
"drake::logging::get_sink(): error: the spdlog sink configuration has"
"unexpectedly changed.");
}
return result;
}
std::string logging::set_log_level(const std::string& level) {
spdlog::level::level_enum prev_value = drake::log()->level();
spdlog::level::level_enum value{};
if (level == "trace") {
value = spdlog::level::trace;
} else if (level == "debug") {
value = spdlog::level::debug;
} else if (level == "info") {
value = spdlog::level::info;
} else if (level == "warn") {
value = spdlog::level::warn;
} else if (level == "err") {
value = spdlog::level::err;
} else if (level == "critical") {
value = spdlog::level::critical;
} else if (level == "off") {
value = spdlog::level::off;
} else if (level == "unchanged") {
value = prev_value;
} else {
throw std::runtime_error(fmt::format("Unknown spdlog level: {}", level));
}
drake::log()->set_level(value);
switch (prev_value) {
case spdlog::level::trace: return "trace";
case spdlog::level::debug: return "debug";
case spdlog::level::info: return "info";
case spdlog::level::warn: return "warn";
case spdlog::level::err: return "err";
case spdlog::level::critical: return "critical";
case spdlog::level::off: return "off";
default: {
// N.B. `spdlog::level::level_enum` is not a `enum class`, so the
// compiler does not know that it has a closed set of values. For
// simplicity in linking, we do not use `DRAKE_UNREACHABLE`.
throw std::runtime_error("Should not reach here!");
}
}
}
const char* const logging::kSetLogLevelHelpMessage =
"sets the spdlog output threshold; possible values are "
"'unchanged', "
"'trace', "
"'debug', "
"'info', "
"'warn', "
"'err', "
"'critical', "
"'off'";
void logging::set_log_pattern(const std::string& pattern) {
drake::log()->set_pattern(pattern);
}
const char* const logging::kSetLogPatternHelpMessage =
"sets the spdlog pattern for formatting; for more information, see "
"https://github.com/gabime/spdlog/wiki/3.-Custom-formatting";
#else // HAVE_SPDLOG
logging::logger::logger() {}
logging::sink::sink() {}
logging::logger* log() {
// A do-nothing logger instance.
static logging::logger g_logger;
return &g_logger;
}
logging::sink* logging::get_dist_sink() {
// An empty sink instance.
static logging::sink g_sink;
return &g_sink;
}
std::string logging::set_log_level(const std::string&) {
return "";
}
const char* const logging::kSetLogLevelHelpMessage =
"(Text logging is unavailable.)";
void logging::set_log_pattern(const std::string&) {}
const char* const logging::kSetLogPatternHelpMessage =
"(Text logging is unavailable.)";
#endif // HAVE_SPDLOG
const char* const logging::kSetLogLevelUnchanged = "unchanged";
} // namespace drake