Replies: 3 comments
-
Thank you for your kind words. I understand your concerns about upgrading to post- The current design aims to serialize class members individually using Given the complexity of your class, particularly with members like
This method should allow you to still benefiting from off-hot-path serialization. It's a compromise between the efficiency goals post- Please try this approach and let me know if it helps with your use case. I have tried it locally and it worked #include <quill/Backend.h>
#include <quill/Frontend.h>
#include <quill/sinks/ConsoleSink.h>
#include <quill/LogMacros.h>
#include <quill/Logger.h>
#include <nlohmann/json.hpp>
#include <chrono>
#include <string>
#include <exception>
#include <iostream>
#include <utility>
class BigLog {
public:
BigLog() = default;
void add_some_data()
{
// example
m_fields["name"] = "John Doe";
m_fields["age"] = 30;
m_fields["city"] = "London";
m_exception = std::make_exception_ptr(std::runtime_error("Example"));
m_start = std::chrono::steady_clock::now();
m_walltime = std::chrono::seconds {1};
m_timestamp = "test";
}
std::string dump() const
{
// example
std::string s;
for (auto& [key, value] : m_fields.items())
{
s += "[" + key + ", " + value.dump() + "] ";
}
s += std::to_string(m_start.time_since_epoch().count()) + " ";
s += m_exception ? std::string { "m_exception" } : std::string {"nullptr"};
return s;
}
private:
nlohmann::json m_fields;
std::exception_ptr m_exception;
std::chrono::time_point<std::chrono::steady_clock> m_start;
std::chrono::steady_clock::duration m_walltime{};
std::string m_timestamp;
};
/**
* Helper
*/
static std::byte* align_pointer(void* pointer, size_t alignment) noexcept
{
return reinterpret_cast<std::byte*>((reinterpret_cast<uintptr_t>(pointer) + (alignment - 1ul)) &
~(alignment - 1ul));
}
/**
* fmt formatter
* Runs on backend - slow path
*/
template <>
struct fmtquill::formatter<BigLog>
{
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
auto format(::BigLog const& bl, format_context& ctx) const
{
return fmtquill::format_to(ctx.out(), "{}", bl.dump());
}
};
/**
* Define a custom codec
*/
template <>
struct quill::Codec<BigLog>
{
static size_t compute_encoded_size(detail::SizeCacheVector& conditional_arg_size_cache, ::BigLog const& bl) noexcept
{
// hot path
return sizeof(::BigLog) + alignof(::BigLog);
}
static void encode(std::byte*& buffer, detail::SizeCacheVector const& conditional_arg_size_cache,
uint32_t& conditional_arg_size_cache_index, ::BigLog const& bl) noexcept
{
// hot path
auto aligned_ptr = align_pointer(buffer, alignof(::BigLog));
new (aligned_ptr) ::BigLog { bl };
buffer += sizeof(::BigLog) + alignof(::BigLog);
}
static ::BigLog decode_arg(std::byte*& buffer)
{
// Runs on backend - slow path
auto aligned_ptr = align_pointer(buffer, alignof(::BigLog));
auto* tmp = reinterpret_cast<::BigLog*>(aligned_ptr);
// Take a copy
BigLog bl { *tmp };
// Explicitly call the destructor
tmp->~BigLog();
buffer += sizeof(::BigLog) + alignof(::BigLog);
return bl;
}
static void decode_and_store_arg(std::byte*& buffer, DynamicFormatArgStore* args_store)
{
// Runs on backend - slow path
args_store->push_back(decode_arg(buffer));
}
};
int main() {
quill::Backend::start();
auto console_sink = quill::Frontend::create_or_get_sink<quill::ConsoleSink>("console");
quill::Logger *logger = quill::Frontend::create_or_get_logger("root", std::move(console_sink));
BigLog bl;
bl.add_some_data();
LOG_INFO(logger, "BigLog: {}", bl);
LOG_INFO(logger, "BigLog: {}", bl);
return 0;
} |
Beta Was this translation helpful? Give feedback.
-
The above has been added to master, you should be able to use it for easy migration to v8. I am not sure when the next release will be. Please see the example: https://github.com/odygrd/quill/blob/master/examples/user_defined_types_logging_deferred_format.cpp |
Beta Was this translation helpful? Give feedback.
-
Thank you so much, really appreciate you addressing my use case! |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I've been using quill 3.x for awhile and I've been thinking about how to upgrade to version 8, but I'm stumped on a class I need to serialize outside of the hot path. I've looked at the example for the codec, but that appears to be geared to towards simpler structs and not heavyweight encapsulated classes. For instance, this is more or less the class I need to serialize
nlohmann json is a complex object so I'm not sure how that would go, and in addition the members of my class are private and I would prefer to keep them that way. I use this to write stacktraces (very slow) and to dump out json (not that bad, but would prefer off the hot path). What are my options here?
I know you hated copying between the threads in previous versions, but what if you only allowed moves and returned the ability to format a custom object outside of the hot path. Anyways, just a suggestion. Really love the library even if I'm stuck on v3 at the moment
Beta Was this translation helpful? Give feedback.
All reactions