blob: 7b83dc0b9ce1c512231d235a82ae40ff10958e35 [file] [log] [blame]
#pragma once
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <filesystem>
#include <iostream>
#include <sstream>
#include <string>
namespace crow
{
enum class LogLevel : std::uint8_t
{
Debug = 0,
Info,
Warning,
Error,
Critical,
Always,
};
class Logger
{
private:
//
static std::string timestamp()
{
std::string date;
date.resize(32, '\0');
time_t t = time(nullptr);
tm myTm{};
gmtime_r(&t, &myTm);
size_t sz =
strftime(date.data(), date.size(), "%Y-%m-%d %H:%M:%S", &myTm);
date.resize(sz);
return date;
}
public:
Logger([[maybe_unused]] const std::string& prefix,
[[maybe_unused]] const std::string& filename,
[[maybe_unused]] const size_t line, LogLevel levelIn) :
level(levelIn)
{
#ifdef BMCWEB_ENABLE_LOGGING
stringstream << "(" << timestamp() << ") [" << prefix << " "
<< std::filesystem::path(filename).filename() << ":"
<< line << "] ";
#endif
}
~Logger()
{
if (level >= getCurrentLogLevel())
{
#ifdef BMCWEB_ENABLE_LOGGING
stringstream << '\n';
std::cerr << stringstream.str();
#endif
}
}
Logger(const Logger&) = delete;
Logger(Logger&&) = delete;
Logger& operator=(const Logger&) = delete;
Logger& operator=(const Logger&&) = delete;
//
template <typename T>
Logger& operator<<([[maybe_unused]] T const& value)
{
if (level >= getCurrentLogLevel())
{
#ifdef BMCWEB_ENABLE_LOGGING
// Somewhere in the code we're implicitly casting an array to a
// pointer in logging code. It's non-trivial to find, so disable
// the check here for now
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
stringstream << value;
#endif
}
return *this;
}
//
static void setLogLevel(LogLevel level)
{
getLogLevelRef() = level;
}
static LogLevel getCurrentLogLevel()
{
return getLogLevelRef();
}
static void enableStatefulLogs()
{
getStatefulLogsEnableRef() = true;
}
static void disableStatefulLogs()
{
getStatefulLogsEnableRef() = false;
}
static bool isStatefulLogsEnabled()
{
return getStatefulLogsEnableRef();
}
private:
//
static LogLevel& getLogLevelRef()
{
static auto currentLevel = static_cast<LogLevel>(1);
return currentLevel;
}
static bool& getStatefulLogsEnableRef()
{
static auto isStatefulLogsEnabled = static_cast<bool>(false);
return isStatefulLogsEnabled;
}
//
std::ostringstream stringstream;
LogLevel level;
};
} // namespace crow
// The logging functions currently use macros. Now that we have c++20, ideally
// they'd use source_location with fixed functions, but for the moment, disable
// the check.
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define BMCWEB_LOG_CRITICAL \
if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Critical) \
crow::Logger("CRITICAL", __FILE__, __LINE__, crow::LogLevel::Critical)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define BMCWEB_LOG_ERROR \
if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Error) \
crow::Logger("ERROR", __FILE__, __LINE__, crow::LogLevel::Error)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define BMCWEB_LOG_WARNING \
if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Warning) \
crow::Logger("WARNING", __FILE__, __LINE__, crow::LogLevel::Warning)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define BMCWEB_LOG_INFO \
if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Info) \
crow::Logger("INFO", __FILE__, __LINE__, crow::LogLevel::Info)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define BMCWEB_LOG_DEBUG \
if (crow::Logger::getCurrentLogLevel() <= crow::LogLevel::Debug) \
crow::Logger("DEBUG", __FILE__, __LINE__, crow::LogLevel::Debug)
// Prints critical to triage and debug BMCWeb (always enabled - for now)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define BMCWEB_LOG_ALWAYS \
crow::Logger("ALWAYS", __FILE__, __LINE__, crow::LogLevel::Always)
// Stateful specific prints:
#define BMCWEB_LOG_STATEFUL_DEBUG \
if (crow::Logger::isStatefulLogsEnabled()) \
BMCWEB_LOG_DEBUG << "Stateful: "
#define BMCWEB_LOG_STATEFUL_INFO \
if (crow::Logger::isStatefulLogsEnabled()) \
BMCWEB_LOG_INFO << "Stateful: "
#define BMCWEB_LOG_STATEFUL_WARNING \
if (crow::Logger::isStatefulLogsEnabled()) \
BMCWEB_LOG_WARNING << "Stateful: "
#define BMCWEB_LOG_STATEFUL_ERROR \
if (crow::Logger::isStatefulLogsEnabled()) \
BMCWEB_LOG_ERROR << "Stateful: "
#define BMCWEB_LOG_STATEFUL_CRITICAL \
if (crow::Logger::isStatefulLogsEnabled()) \
BMCWEB_LOG_CRITICAL << "Stateful: "
#define BMCWEB_LOG_STATEFUL_ALWAYS BMCWEB_LOG_ALWAYS << "Stateful: "