Is there an existing way to disable every code's lines of a logger depends on log_level without surrounding every call by an ifndef
?
// 5 debug
// 4 info
// 3 warning
// 2 error
// 1 fatal
My problem is that even with a log_level set to 3 for exemple, only the warning logger and less will be printed obviously, but the rvalue arguments of every function of my logger are consuming time, Exemple :
Globals::LOGGER.logger_DEBUG("MyFunction", "rvalue is " + std::to_string(8));
Even with a log_level = 3
, this function will be called, will print nothing, but will create 2 temporary strings and assigns bytes.
My target is to disable every Globals::LOGGER.logger_xxxx
line depends on the log_level
My logger definition :
logger.hpp :
#pragma once
#include <string>
#include <iostream>
/**
* Class used to make logs
*/
class Logger
{
private:
int _Log_level;
public:
/**
* Contructor
* @param Log_level Level of log we want to print
* @param Name_Log_File Name of the log.txt
*/
Logger(int pLog_level = 4, const std::string &pName_Log_File = "cmd");
/**
* Destructor
*/
~Logger();
/**
* Logger printed when the Log_level is 5
* @param Class_function String that represent the class::function
* @param Message String that we want to print
*/
void logger_DEBUG(const std::string &pClass_function, const std::string &pMessage);
/**
* Logger printed when the Log_level is 4 and higher
* @param Message String that we want to print
*/
void logger_INFO(const std::string &pMessage);
/**
* Logger printed when the Log_level is 3 and higher
* @param Class_function String that represent the class::function
* @param Message String that we want to print
*/
void logger_WARNING(const std::string &pClass_function, const std::string &pMessage);
/**
* Logger printed when the Log_level is 2 and higher
* @param Class_function String that represent the class::function
* @param Message String that we want to print
*/
void logger_ERROR(const std::string &pClass_function, const std::string &pMessage);
/**
* Getter of the Log_level
*/
int get_Log_level();
/**
* Setter of the Log_level
* @param pLog_level
*/
void set_Log_level(const int &pLog_level);
private:
std::string date_time();
};
logger.cpp :
#include "Logger.hpp"
#include <filesystem>
#include <chrono>
#include <ctime>
Logger::Logger(int pLog_level, const std::string &pName_Log_File) : _Log_level(pLog_level)
{
std::cout << "LOGGER created" << std::endl;
if (pName_Log_File != "cmd")
{
std::filesystem::create_directory("LOG");
std::string output_file = "./LOG/" + pName_Log_File + ".txt";
std::freopen(const_cast<char *>(output_file.c_str()), "w", stdout);
}
}
Logger::~Logger()
{
}
void Logger::logger_DEBUG(const std::string &pClass_function, const std::string &pMessage)
{
if (this->_Log_level > 4)
{
std::cout << "[" << this->date_time() << "]"
<< " | [DEBUG] | [" << pClass_function << "] : " << pMessage << std::endl;
}
}
void Logger::logger_INFO(const std::string &pMessage)
{
if (this->_Log_level > 3)
{
std::cout << "[" << this->date_time() << "]"
<< " | [INFO] : " << pMessage << std::endl;
}
}
void Logger::logger_WARNING(const std::string &pClass_function, const std::string &pMessage)
{
if (this->_Log_level > 2)
{
std::cout << "[" << this->date_time() << "]"
<< " | [WARNING] | [" << pClass_function << "] : " << pMessage << std::endl;
}
}
void Logger::logger_ERROR(const std::string &pClass_function, const std::string &pMessage)
{
if (this->_Log_level > 1)
{
std::cout << "[" << this->date_time() << "]"
<< " | [ERROR] | [" << pClass_function << "] : " << pMessage << std::endl;
}
}
int Logger::get_Log_level()
{
return this->_Log_level;
}
void Logger::set_Log_level(const int &pLog_level)
{
this->_Log_level = pLog_level;
}
std::string Logger::date_time()
{
auto start = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(start);
auto res = std::string(std::ctime(&time));
res.pop_back();
return res;
}
To reprensent in a better way the problem : Commenting every line of the logger in my application valgrind :
total heap usage: 312,852 allocs, 312,852 frees, 7,055,259 bytes allocated
log_level is 0, nothing is printed but functions are called, valgrind :
518,672 allocs, 518,672 frees, 23,963,961 bytes allocated
log_level is 5, everything is printed, valgrind :
total heap usage: 857,872 allocs, 857,872 frees, 30,917,557 bytes allocated
A better solution would be not to call the log function when the log level is under the threshold.
enum LEVEL {
FATAL = 1,
ERROR = 2,
WARN = 3,
INFO = 4,
DEBUG = 5,
};
#define MLOG(logger, level, func, msg) \
do { \
if (logger.get_Log_level() >= level) { \
logger.logger_##level(func, msg); \
} \
} while(0);
// logger.logger_INFO("", "");
MLOG(logger, INFO, "", "");
By the way, the logic of the logger for different levels in your code is almost the same and you can replace it with macro.