diff --git a/src/Environment.hpp b/src/Environment.hpp index 7fe253a6d..5bf2d43d4 100644 --- a/src/Environment.hpp +++ b/src/Environment.hpp @@ -44,8 +44,8 @@ class PowerPlant; */ class Environment { public: - Environment(PowerPlant& powerplant, std::string reactor_name, const LogLevel& log_level) - : powerplant(powerplant), reactor_name(std::move(reactor_name)), log_level(log_level) {} + Environment(PowerPlant& powerplant, std::string reactor_name) + : powerplant(powerplant), reactor_name(std::move(reactor_name)) {} private: friend class PowerPlant; @@ -55,8 +55,6 @@ class Environment { PowerPlant& powerplant; /// @brief The name of the reactor std::string reactor_name; - /// @brief The log level for this reactor - LogLevel log_level; }; } // namespace NUClear diff --git a/src/LogLevel.hpp b/src/LogLevel.hpp index 2ec8375b9..ebf1494c3 100644 --- a/src/LogLevel.hpp +++ b/src/LogLevel.hpp @@ -39,6 +39,15 @@ namespace NUClear { * The logging level of a reactor can be changed by setting it in the install function. */ enum LogLevel { + /** + * @brief + * Don't use this log level when emitting logs, it is for setting reactor log level from non reactor sources. + * + * Specifically when a NUClear::log is called from code that is not running in a reaction (even transitively) then + * the reactor_level will be set to UNKNOWN. + */ + UNKNOWN, + /** * @brief * The Trace level contains messages that are used to trace the exact flow of execution. diff --git a/src/PowerPlant.hpp b/src/PowerPlant.hpp index 0a76090c3..099f8091e 100644 --- a/src/PowerPlant.hpp +++ b/src/PowerPlant.hpp @@ -122,7 +122,7 @@ class PowerPlant { * @tparam T The type of the reactor to build and install * @tparam level The initial logging level for this reactor to use */ - template + template void install(); /** diff --git a/src/PowerPlant.ipp b/src/PowerPlant.ipp index dfd328a6b..e31d4115c 100644 --- a/src/PowerPlant.ipp +++ b/src/PowerPlant.ipp @@ -52,15 +52,14 @@ inline PowerPlant::PowerPlant(Configuration config, int argc, const char* argv[] emit(std::make_unique(args)); } -template +template void PowerPlant::install() { // Make sure that the class that we received is a reactor static_assert(std::is_base_of::value, "You must install Reactors"); // The reactor constructor should handle subscribing to events - reactors.push_back( - std::make_unique(std::make_unique(*this, util::demangle(typeid(T).name()), level))); + reactors.push_back(std::make_unique(std::make_unique(*this, util::demangle(typeid(T).name())))); } // Default emit with no types @@ -172,16 +171,16 @@ void PowerPlant::log(Arguments&&... args) { // Get the current task const auto* current_task = threading::ReactionTask::get_current_task(); - // Only log if we are not from a reaction, or if our reactor's log level is high enough - if (current_task == nullptr || level >= current_task->parent.reactor.log_level) { - // Build our log message by concatenating everything to a stream - std::stringstream output_stream; - log_impl(output_stream, std::forward(args)...); + // Build our log message by concatenating everything to a stream + std::stringstream output_stream; + log_impl(output_stream, std::forward(args)...); - // Direct emit the log message so that any direct loggers can use it - powerplant->emit(std::make_unique( - message::LogMessage{level, output_stream.str(), current_task != nullptr ? current_task->stats : nullptr})); - } + // Direct emit the log message so that any direct loggers can use it + powerplant->emit(std::make_unique( + level, + current_task != nullptr ? current_task->parent.reactor.log_level : LogLevel::UNKNOWN, + output_stream.str(), + current_task != nullptr ? current_task->stats : nullptr)); } } // namespace NUClear diff --git a/src/Reactor.hpp b/src/Reactor.hpp index bf1b6f04e..9d8dea7cb 100644 --- a/src/Reactor.hpp +++ b/src/Reactor.hpp @@ -143,9 +143,7 @@ class Reactor { friend class PowerPlant; explicit Reactor(std::unique_ptr environment) - : powerplant(environment->powerplant) - , reactor_name(environment->reactor_name) - , log_level(environment->log_level) {} + : powerplant(environment->powerplant), reactor_name(environment->reactor_name) {} Reactor(const Reactor& /*other*/) = default; Reactor(Reactor&& /*other*/) noexcept = default; Reactor& operator=(const Reactor& /*rhs*/) = delete; @@ -413,7 +411,7 @@ class Reactor { * @param args The arguments we are logging */ template - void log(Arguments&&... args) { + void log(Arguments&&... args) const { // If the log is above or equal to our log level PowerPlant::log(std::forward(args)...); diff --git a/src/message/LogMessage.hpp b/src/message/LogMessage.hpp index 237ade468..342880019 100644 --- a/src/message/LogMessage.hpp +++ b/src/message/LogMessage.hpp @@ -36,9 +36,26 @@ namespace message { */ struct LogMessage { + /** + * @brief Construct a new Log Message object + * + * @param level the logging level of the log + * @param display_level the logging level of the reactor that made this log + * @param message the string contents of the message + * @param task the currently executing task that made this message or nullptr if not in a task + */ + LogMessage(const LogLevel& level, + const LogLevel& display_level, + std::string message, + std::shared_ptr task) + : level(level), display_level(display_level), message(std::move(message)), task(std::move(task)) {} + /// @brief The logging level of the log. LogLevel level{}; + /// @brief The logging level of the reactor that made the log (the level to display at). + LogLevel display_level{}; + /// @brief The string contents of the message. std::string message{}; diff --git a/tests/log/Log.cpp b/tests/log/Log.cpp index ca2bbbcfd..64c3f1af4 100644 --- a/tests/log/Log.cpp +++ b/tests/log/Log.cpp @@ -59,7 +59,9 @@ class TestReactor : public NUClear::Reactor { // Capture the log messages on>().then([](const NUClear::message::LogMessage& log_message) { - messages.push_back(LogTestOutput{log_message.message, log_message.level, log_message.task != nullptr}); + if (log_message.level >= log_message.display_level) { + messages.push_back(LogTestOutput{log_message.message, log_message.level, log_message.task != nullptr}); + } }); // Run each test