The goal of this code is to format any log to STDOUT and STDERR with the file and the line of where the call is made. I took inspiration from different C loggers that I found on the internet. I want it to be small and efficient while using C++17.
I'm a bit suspicious about the call to std::data at line 30 not being null-terminated.
#include <iostream>
#include <string_view>
#include <array>
enum Log_level
{
L_SILENT = 0,
L_ERROR = 1,
L_INFO = 2,
L_DEBUG = 3,
};
static Log_level log_level = L_ERROR;
static constexpr std::array log_colors
{
"",
"\x1B[1;31m",
"\x1B[1;34m",
"\x1B[1;30m"
};
template<typename... Args>
void vlk_log_internal(const Log_level level, const std::string_view s, Args... args)
{
std::FILE* output = (level == L_ERROR ? stderr : stdout);
if (level <= log_level)
{
std::fprintf(output, "%s", log_colors[level]);
std::fprintf(output, std::data(s), args...);
std::fprintf(output, "\x1B[0m");
std::fprintf(output, "\n");
}
}
#define vlk_log(lvl, msg, ...) { vlk_log_internal(lvl, "[%s:%d] " msg, __FILE__, __LINE__, ##__VA_ARGS__); } (void)0
int main()
{
log_level = L_SILENT;
vlk_log(L_ERROR, "Error will not show");
log_level = L_ERROR;
vlk_log(L_ERROR, "Error %s", "msg");
vlk_log(L_INFO, "Info will not show");
log_level = L_INFO;
vlk_log(L_INFO, "Info %s", "msg");
vlk_log(L_DEBUG, "Debug will not show");
log_level = L_DEBUG;
vlk_log(L_DEBUG, "Debug %s", "msg");
return 0;
}