Skip to main content
4 of 4
deleted 1 character in body
Rietty
  • 375
  • 1
  • 2
  • 8

Implementing a logging system in C++17

I've been programming for what is a probably a little bit and made a very simple logging system for my personal projects. While it works out fairly well so far, I would like advice on how to make it perform better and stuff I can do to make it more usable in general.

Main questions include:

  1. Is my code thread safe? If not, how do I make it thread safe?

  2. Is there a way to make the interface a bit cleaner for use? Right now #define feels a bit hacky.

  3. Is there a way to avoid the use of a global unique_ptr?

  4. Should I just make it a header only library? Is there any benefits in doing so?

.hpp:

#pragma once

/*
Use it by including this header in every file required, and in your main function start a new log.
    Logger::startLog("Log.txt");
Use the various error levels by naming them and simply passing the info and what you want to output.
    Logger::log(ERROR, "Something went wrong.");
*/

// For the unique pointers.
#include <memory>
// Filestream.
#include <fstream>
// String class for names and parameters passed around.
#include <string>

#define FATAL Logger::Level::Fatal
#define ERROR Logger::Level::Error
#define WARNING Logger::Level::Warning
#define INFO Logger::Level::Info
#define DEBUG Logger::Level::Debug

namespace Logger {
    // Severity level enum.
    enum class Level {
        Fatal,
        Error,
        Warning,
        Info,
        Debug
    };

    // Initialize the log.
    void startLog(const std::string& filepath);

    // Log a message.
    void log(Level s, const std::string& msg);

    // Logging class.
    class Log {
    public:
        Log(const std::string& filepath);
        void addLog(Level s, const std::string& msg);
        ~Log();
    private:
        // File for logging.
        std::ofstream m_logfile;
        std::string levels[5] = {"Fatal", "Error", "Warning", "Info", "Debug"};
    };
}

.cpp:

#include "Log.hpp"

namespace Logger {
    // Global Logging Object.
    std::unique_ptr<Log> g_log;

    // Initalize our logging object.
    void startLog(const std::string& filepath) {
        g_log = std::make_unique<Log>(filepath);
        Logger::log(Level::Info, "Started logging system.");
    }

    // Method which logs.
    void log(Level s, const std::string& msg) {
        g_log->addLog(s, msg);
    }

    // Create our global logging object.
    Log::Log(const std::string& filepath) : m_logfile{} {
        m_logfile.open(filepath);
    }

    // Add a message to our log.
    void Log::addLog(Level s, const std::string& msg) {
        if (m_logfile.is_open()) {
            m_logfile << levels[static_cast<int>(s)] << ": " << msg << std::endl;
        }
    }

    Log::~Log() {
        addLog(Level::Info, "Stopped logging system.");
        m_logfile.close();
    }
}
Rietty
  • 375
  • 1
  • 2
  • 8