Program Listing for File Logger.cpp

Return to documentation for file (gui/logging/Logger.cpp)

#include <array>

#include "Logger.hpp"

LogSettings LogStream::SETTINGS;

LogStream::LogStream(LogLevel level, const char *file, int line)
  : _level(level), _file(file), _line(line)
{
}

LogStream::~LogStream()
{
  flush();
}

void LogStream::flush()
{
  if (_level < SETTINGS.filter)
    return;

  std::array<char, sizeof "YYYY-MM-DDTHH:MM:SSZ" - 1> timebuf;
  std::time_t now = std::time(nullptr);
  std::strftime(timebuf.data(), sizeof timebuf, "%FT%TZ", std::gmtime(&now));

  const char *level_str;
  switch (_level) {
    case LogLevel::DEBUG:
      level_str = "DEBUG";
      break;
    case LogLevel::INFO:
      level_str = "INFO";
      break;
    case LogLevel::WARN:
      level_str = "WARN";
      break;
    case LogLevel::CRIT:
      level_str = "CRITICAL";
      break;
    default:
      __builtin_unreachable();
  }

  std::string rendered = _ss.str();
  bool truncated = false;

  if (rendered.ends_with('\n')) {
    rendered.pop_back();
    truncated = true;
  }

  if (SETTINGS.type == LogType::JSON) {
    std::fprintf(
      stdout,
      "{"
      "\"timestamp\":\"%s\","
      "\"level\":\"%s\","
      "\"file\":\"%s\","
      "\"line\":%d,"
      "\"message\":\"%s\""
      "}\n",
      timebuf.data(),
      level_str,
      _file,
      _line,
      rendered.c_str());
  } else {
    std::fprintf(
      stdout,
      "[%s] %s (%s:%d): %s\n",
      timebuf.data(),
      level_str,
      _file,
      _line,
      rendered.c_str());
  }

  std::fflush(stdout);
  if (truncated)
    Log::warn << "Incorect Log format, truncating newline!";
}

auto LogStream::log(LogLevel lvl, const char *file, int line) -> LogStream
{
  return {lvl, file, line};
}

void LogStream::
  logger_configure(const std::string &log_path, LogLevel level, LogType type)
{
  LogStream::SETTINGS.filter = level;
  LogStream::SETTINGS.type = type;

  if (!log_path.empty()) {
    FILE *fp = std::fopen(log_path.c_str(), "w");
    if (!fp) {
      std::perror("Failed to open log file");
      std::exit(1);
    }
  }
}

std::string LogStream::cleanString(std::string str)
{
  if (str.back() == '\n')
    str.pop_back();
  return str;
}