-
Notifications
You must be signed in to change notification settings - Fork 244
Description
Is your feature request related to a problem? Please describe.
I use this library extensively and I wonder if there's some more convenient way to log UDT with this library.
For a relatively large/not trivially copyable UDT, typically we only need to log several essential fields.
eg.
struct SuperBigStruct {
std::map<std::string, int> superBigMap;
}
template<>
struct fmt::formatter<SuperBigStruct> {
template <typename FCtx>
auto format(const SuperBigStruct &obj, FCtx &ctx) const {
return fmt::format(ctx.out(), "SuperBigStruct(size={})", obj.superBigMap.size());
}
};So logically if we want to log this UDT we only need to encode & decode one size_t (which is obj.superBigMap.size()), but this is impossible under the current design structure(which always requires you to encode and decode the entire struct).
It is possible to do this though:
struct SuperBigStruct {
std::map<std::string, int> superBigMap;
}
struct SuperBigStructFormatProxy {
int size;
};
auto format_as(const SuperBigStruct &obj) { return SuperBigStructFormatProxy{obj.size()}; }
template<>
struct fmt::formatter<SuperBigStructFormatProxy> {
template <typename FCtx>
auto format(const SuperBigStructFormatProxy&obj, FCtx &ctx) const {
return fmt::format(ctx.out(), "SuperBigStruct(size={})", obj.size);
}
};but this is too verbose.
Describe the solution you'd like
I think a way to automatically extract necessary fields from the format string to do encode/decode would be very nice.
I was browsing through the documentation of fmt the other day and I came across this std::make_format_args. Maybe we can support codec for the returned fmt::basic_format_args (which is essentially a list of references to the arguments).
So maybe something like this(but I don't know how to exactly implement it yet):
struct SuperBigStruct {
std::map<std::string, int> superBigMap;
int size;
// here we define the format string and pack of args for the format string
auto GetFormatArgs() const { return std::make_format_args(size); }
static inline constexpr std::string_view kFmtStr{"SuperBigStruct(size={})"};
}
using ArgsType = std::invoke_result_t<&SuperBigStruct::GetFormatArgs, SuperBigStruct>;
auto format_as(const SuperBigStruct &obj) { return obj.GetFormatArgs(); }
// implement codec for the pack of args
// we get the list of args and encode those basic members one by one
// since basic_format_args is list of references, maybe we need to allocate & make the list of args point to
// the decoded value in backend thread.
template<>
quill::Codec<SuperBigStruct> : quill::FormatArgsCodec<ArgsType> {};
// formatter for ArgsType
template<>
fmtquill::formatter<ArgsType> {
template <typename FCtx>
auto format(const ArgsType &args, FCtx &ctx) const {
return fmt::vformat(ctx.out(), "SuperBigStruct(size={})", args);
}
}Additional context
This is just my immature two cents, I'm open to discussion.