\$\begingroup\$
\$\endgroup\$
6
So I had previously posted this question and asked for some feedback regarding my (now) header-only logging system and figured it would be a good time to go back to the changes I made it and see if it can be further improved before starting a larger project.
#pragma once
/*
Header only logging system.
Should be thread-safe and type-safe, as well as easier to use.
Hopefully no major errors to deal with.
*/
// Standard Headers.
#include <ostream>
#include <variant>
#include <memory>
#include <utility>
#include <mutex>
#include <array>
#include <string_view>
// Everything will take place in this namespace, so we can use the Logger:: prefix for functions.
namespace Logger {
// Various logging severity levels.
enum class Level {
Info, Debug, Warning, Error, Fatal
};
class Log {
public:
// Takes standard streams cout, cerr, etc.
explicit Log(std::ostream& p_stream) : m_log(&p_stream) {}
// Create logger using std::make_unique<std::ofstream>(...) so ownership is passed.
explicit Log(std::unique_ptr<std::ostream> p_stream) : m_log(std::move(p_stream)) {}
template <typename T>
inline void info(T&& p_message);
template <typename T>
inline void debug(T&& p_message);
template <typename T>
inline void warning(T&& p_message);
template <typename T>
inline void error(T&& p_message);
template <typename T>
inline void fatal(T&& p_message);
private:
template <typename T>
void log(T&& p_msg) const {
auto const t_lock = std::lock_guard(*m_lock);
std::visit([&](auto&& p_ptr) {
(*p_ptr) << p_msg;
}, m_log);
};
std::ostream& stream() const {
return std::visit([](auto&& ptr) -> std::ostream& {
return *ptr;
}, m_log);
}
template <typename T>
inline void add(Logger::Level p_level, T&& p_message);
std::variant<std::unique_ptr<std::ostream>, std::ostream*> m_log;
std::unique_ptr<std::mutex> m_lock = std::make_unique<std::mutex>();
std::array<std::string_view, 5> m_levels = { "Info", "Debug", "Warning", "Error", "Fatal" };
};
template <typename T>
void Log::add(Level p_level, T&& p_message) {
auto const f_lock = std::lock_guard(*m_lock);
stream() << m_levels[static_cast<size_t>(p_level)] << ": " << p_message << '\n';
}
template <typename T>
inline void Log::info(T&& p_message) {
add(Level::Info, p_message);
}
template <typename T>
inline void Log::debug(T&& p_message) {
add(Level::Debug, p_message);
}
template <typename T>
inline void Log::warning(T&& p_message) {
add(Level::Warning, p_message);
}
template <typename T>
inline void Log::error(T&& p_message) {
add(Level::Error, p_message);
}
template <typename T>
inline void Log::fatal(T&& p_message) {
add(Level::Fatal, p_message);
}
}
Is this thread-safe? Is it type-safe? How can I improve on it? What have I done badly? What have I done correctly so I know to keep that for the future?
Thank you!
asked Jul 17, 2019 at 18:49
-
\$\begingroup\$ Are the severity levels configurable? Could you configure a minimum level? Is Debug allowed in production environment? \$\endgroup\$dfhwze– dfhwze2019年07月17日 18:52:42 +00:00Commented Jul 17, 2019 at 18:52
-
\$\begingroup\$ @dfhwze No, no, and I don't understand the last point. Can you clarify a bit I would add that in and set up a minimum level? \$\endgroup\$Rietty– Rietty2019年07月18日 15:15:07 +00:00Commented Jul 18, 2019 at 15:15
-
\$\begingroup\$ Logging at Debug level could indicate that you only want these logs in test environments, not in production. A minimum level would indicate that all calls to the logger below this level would be silently ignored. This way, you can put a very fine trace log level when introspecting some issues, and reset the log level afterwards. \$\endgroup\$dfhwze– dfhwze2019年07月18日 15:36:30 +00:00Commented Jul 18, 2019 at 15:36
-
\$\begingroup\$ How would I specify those switches during build? I.e. How would the code know it's being built for a particular environment? \$\endgroup\$Rietty– Rietty2019年07月18日 16:21:00 +00:00Commented Jul 18, 2019 at 16:21
-
\$\begingroup\$ I would expect compiler flags or configuration files. \$\endgroup\$dfhwze– dfhwze2019年07月18日 16:24:03 +00:00Commented Jul 18, 2019 at 16:24
lang-cpp