blob: e2b9fefd272f1f42c5fa4ebd6c5f2e0bf8ca8bee [file] [log] [blame]
#pragma once
#include "bmcweb_config.h"
#include <bit>
#include <format>
#include <iostream>
#include <source_location>
#include <string_view>
#include <system_error>
// NOLINTBEGIN(readability-convert-member-functions-to-static, cert-dcl58-cpp)
template <>
struct std::formatter<void*>
{
constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}
auto format(const void*& ptr, auto& ctx) const
{
return std::format_to(ctx.out(), "{}",
std::to_string(std::bit_cast<size_t>(ptr)));
}
};
// NOLINTEND(readability-convert-member-functions-to-static, cert-dcl58-cpp)
namespace crow
{
enum class LogLevel
{
Disabled = 0,
Critical,
Error,
Warning,
Info,
Debug,
Enabled,
};
// Mapping of the external loglvl name to internal loglvl
constexpr std::array<std::string_view, 7> mapLogLevelFromName{
"DISABLED", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "ENABLED"};
constexpr crow::LogLevel getLogLevelFromName(std::string_view name)
{
const auto* iter = std::ranges::find(mapLogLevelFromName, name);
if (iter != mapLogLevelFromName.end())
{
return static_cast<LogLevel>(iter - mapLogLevelFromName.begin());
}
return crow::LogLevel::Disabled;
}
// configured bmcweb LogLevel
constexpr crow::LogLevel bmcwebCurrentLoggingLevel =
getLogLevelFromName(BMCWEB_LOGGING_LEVEL);
template <typename T>
const void* logPtr(T p)
{
static_assert(std::is_pointer<T>::value,
"Can't use logPtr without pointer");
return std::bit_cast<const void*>(p);
}
template <LogLevel level, typename... Args>
inline void vlog(std::format_string<Args...>&& format, Args&&... args,
const std::source_location& loc) noexcept
{
if constexpr (bmcwebCurrentLoggingLevel < level)
{
return;
}
constexpr size_t stringIndex = static_cast<size_t>(level);
static_assert(stringIndex < mapLogLevelFromName.size(),
"Missing string for level");
constexpr std::string_view levelString = mapLogLevelFromName[stringIndex];
std::string_view filename = loc.file_name();
filename = filename.substr(filename.rfind('/'));
if (!filename.empty())
{
filename.remove_prefix(1);
}
std::string logLocation;
try
{
// TODO, multiple static analysis tools flag that this could potentially
// throw Based on the documentation, it shouldn't throw, so long as none
// of the formatters throw, so unclear at this point why this try/catch
// is required, but add it to silence the static analysis tools.
logLocation =
std::format("[{} {}:{}] ", levelString, filename, loc.line());
logLocation +=
std::format(std::move(format), std::forward<Args>(args)...);
}
catch (const std::format_error& /*error*/)
{
logLocation += "Failed to format";
// Nothing more we can do here if logging is broken.
}
logLocation += '\n';
// Intentionally ignore error return.
fwrite(logLocation.data(), sizeof(std::string::value_type),
logLocation.size(), stdout);
fflush(stdout);
}
} // namespace crow
template <typename... Args>
struct BMCWEB_LOG_CRITICAL
{
// NOLINTNEXTLINE(google-explicit-constructor)
BMCWEB_LOG_CRITICAL(std::format_string<Args...> format, Args&&... args,
const std::source_location& loc =
std::source_location::current()) noexcept
{
crow::vlog<crow::LogLevel::Critical, Args...>(
std::move(format), std::forward<Args>(args)..., loc);
}
};
template <typename... Args>
struct BMCWEB_LOG_ERROR
{
// NOLINTNEXTLINE(google-explicit-constructor)
BMCWEB_LOG_ERROR(std::format_string<Args...> format, Args&&... args,
const std::source_location& loc =
std::source_location::current()) noexcept
{
crow::vlog<crow::LogLevel::Error, Args...>(
std::move(format), std::forward<Args>(args)..., loc);
}
};
template <typename... Args>
struct BMCWEB_LOG_WARNING
{
// NOLINTNEXTLINE(google-explicit-constructor)
BMCWEB_LOG_WARNING(std::format_string<Args...> format, Args&&... args,
const std::source_location& loc =
std::source_location::current()) noexcept
{
crow::vlog<crow::LogLevel::Warning, Args...>(
std::move(format), std::forward<Args>(args)..., loc);
}
};
template <typename... Args>
struct BMCWEB_LOG_INFO
{
// NOLINTNEXTLINE(google-explicit-constructor)
BMCWEB_LOG_INFO(std::format_string<Args...> format, Args&&... args,
const std::source_location& loc =
std::source_location::current()) noexcept
{
crow::vlog<crow::LogLevel::Info, Args...>(
std::move(format), std::forward<Args>(args)..., loc);
}
};
template <typename... Args>
struct BMCWEB_LOG_DEBUG
{
// NOLINTNEXTLINE(google-explicit-constructor)
BMCWEB_LOG_DEBUG(std::format_string<Args...> format, Args&&... args,
const std::source_location& loc =
std::source_location::current()) noexcept
{
crow::vlog<crow::LogLevel::Debug, Args...>(
std::move(format), std::forward<Args>(args)..., loc);
}
};
template <typename... Args>
BMCWEB_LOG_CRITICAL(std::format_string<Args...>,
Args&&...) -> BMCWEB_LOG_CRITICAL<Args...>;
template <typename... Args>
BMCWEB_LOG_ERROR(std::format_string<Args...>,
Args&&...) -> BMCWEB_LOG_ERROR<Args...>;
template <typename... Args>
BMCWEB_LOG_WARNING(std::format_string<Args...>,
Args&&...) -> BMCWEB_LOG_WARNING<Args...>;
template <typename... Args>
BMCWEB_LOG_INFO(std::format_string<Args...>,
Args&&...) -> BMCWEB_LOG_INFO<Args...>;
template <typename... Args>
BMCWEB_LOG_DEBUG(std::format_string<Args...>,
Args&&...) -> BMCWEB_LOG_DEBUG<Args...>;