4
\$\begingroup\$

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
\$\endgroup\$
6
  • \$\begingroup\$ Are the severity levels configurable? Could you configure a minimum level? Is Debug allowed in production environment? \$\endgroup\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented Jul 18, 2019 at 16:21
  • \$\begingroup\$ I would expect compiler flags or configuration files. \$\endgroup\$ Commented Jul 18, 2019 at 16:24

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.