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:
Is my code thread safe? If not, how do I make it thread safe?
Is there a way to make the interface a bit cleaner for use? Right now
#define
feels a bit hacky.Is there a way to avoid the use of a global
unique_ptr
?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();
}
}