Closed maordadush closed 1 year ago
Neither compile errors nor source code are provided, so we have no idea what we are dealing with.
oh sorry, I'm trying to set up JSON logging with spdlog, so I'm using the following custom formatter
#include <spdlog/spdlog.h>
#include <variant>
#include <iomanip>
#include <spdlog/fmt/ostr.h>
namespace {
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
}
struct SimpleJSON
{
using json_val = std::variant<std::int64_t, int, double, std::string, bool>;
std::unordered_map<std::string, json_val> members;
SimpleJSON(std::initializer_list<std::pair<const std::string, json_val>> il) : members{il} {}
template<typename OStream>
friend OStream &operator<<(OStream &os, const SimpleJSON &j)
{
for (const auto &kv : j.members) {
os << ", " << std::quoted(kv.first) << ":";
std::visit(overloaded {
[&](std::int64_t arg) { os << arg; },
[&](int arg) { os << arg; },
[&](double arg) { os << arg; },
[&](const std::string& arg) { os << std::quoted(arg); },
[&](bool arg) { os << (arg ? "true" : "false"); }
}, kv.second);
}
return os;
}
};
Then the usage looks like this:
using J = SimpleJSON;
spdlog::set_pattern(
"{\"timestamp\":\"%Y-%m-%dT%H:%M:%S.%e%z\",\"logger\":\"%n\",\"log_"
"level\":\"%l\",\"process_id\":%P,\"thread_id\":%t %v}");
spdlog::info("{}", J({{"key1","value1"},{"key2",true},{"key3",99}}));
but I got an fmt compilation error due to requiring a formatter
In file included from /usr/local/include/spdlog/fmt/bundled/format.h:48,
from /usr/local/include/spdlog/fmt/bundled/ranges.h:19,
from /home/user/test/src/common/log.h:3,
from /home/user/test/src/log.cpp:1:
/usr/local/include/spdlog/fmt/bundled/core.h: In instantiation of ‘constexpr fmt::v9::detail::value<Context> fmt::v9::detail::make_value(T&&) [with Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; T = logging::SimpleJSON&]’:
/usr/local/include/spdlog/fmt/bundled/core.h:1777:29: required from ‘constexpr fmt::v9::detail::value<Context> fmt::v9::detail::make_arg(T&&) [with bool IS_PACKED = true; Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; fmt::v9::detail::type <anonymous> = fmt::v9::detail::type::custom_type; T = logging::SimpleJSON&; typename std::enable_if<IS_PACKED, int>::type <anonymous> = 0]’
/usr/local/include/spdlog/fmt/bundled/core.h:1901:77: required from ‘constexpr fmt::v9::format_arg_store<Context, Args>::format_arg_store(T&& ...) [with T = {logging::SimpleJSON&}; Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; Args = {logging::SimpleJSON}]’
/usr/local/include/spdlog/fmt/bundled/core.h:1918:31: required from ‘constexpr fmt::v9::format_arg_store<Context, typename std::remove_cv<typename std::remove_reference<Args>::type>::type ...> fmt::v9::make_format_args(Args&& ...) [with Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; Args = {logging::SimpleJSON&}]’
/usr/local/include/spdlog/logger.h:374:75: required from ‘void spdlog::logger::log_(spdlog::source_loc, spdlog::level::level_enum, spdlog::string_view_t, Args&& ...) [with Args = {logging::SimpleJSON}; spdlog::string_view_t = fmt::v9::basic_string_view<char>]’
/usr/local/include/spdlog/logger.h:90:13: required from ‘void spdlog::logger::log(spdlog::source_loc, spdlog::level::level_enum, fmt::v9::format_string<T ...>, Args&& ...) [with Args = {logging::SimpleJSON}; fmt::v9::format_string<T ...> = fmt::v9::basic_format_string<char, logging::SimpleJSON>]’
/usr/local/include/spdlog/logger.h:96:12: required from ‘void spdlog::logger::log(spdlog::level::level_enum, fmt::v9::format_string<T ...>, Args&& ...) [with Args = {logging::SimpleJSON}; fmt::v9::format_string<T ...> = fmt::v9::basic_format_string<char, logging::SimpleJSON>]’
/usr/local/include/spdlog/logger.h:158:12: required from ‘void spdlog::logger::info(fmt::v9::format_string<T ...>, Args&& ...) [with Args = {logging::SimpleJSON}; fmt::v9::format_string<T ...> = fmt::v9::basic_format_string<char, logging::SimpleJSON>]’
/usr/local/include/spdlog/spdlog.h:170:31: required from ‘void spdlog::info(fmt::v9::format_string<T ...>, Args&& ...) [with Args = {logging::SimpleJSON}; fmt::v9::format_string<T ...> = fmt::v9::basic_format_string<char, logging::SimpleJSON>]’
/home/david/rdp-proxy/src/log.cpp:116:25: required from here
/usr/local/include/spdlog/fmt/bundled/core.h:1757:7: error: static assertion failed: Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt
1757 | formattable,
| ^~~~~~~~~~~
/usr/local/include/spdlog/fmt/bundled/core.h:1757:7: note: ‘formattable’ evaluates to false
Thanks!
You need to define a fmt::ostream<SimpleJSON>
specialization that extends fmt::ostream_formatter
.
https://github.com/fmtlib/fmt/blob/9.0.0/ChangeLog.rst#900---2022-07-04
Disabled automatic
std::ostream
insertion operator (operator<<
) discovery whenfmt/ostream.h
is included to prevent ODR violations. You can get the old behavior by definingFMT_DEPRECATED_OSTREAM
but this will be removed in the next major release. Usefmt::streamed
orfmt::ostream_formatter
to enable formatting viastd::ostream
instead.
See: https://fmt.dev/9.1.0/api.html#std-ostream-support
template <> struct fmt::ostream<SimpleJSON> : fmt::ostream_formatter {}
}
Another way: https://fmt.dev/9.1.0/api.html#formatting-user-defined-types
Thanks!
I'm still getting a fmt compilation errors due to requiring a formatter
Originally posted by @maordadush in https://github.com/gabime/spdlog/issues/1797#issuecomment-1686064127