Skip to content

Instantly share code, notes, and snippets.

@jwpleow
Last active January 19, 2023 12:18
Show Gist options
  • Select an option

  • Save jwpleow/88dac73d7e841ab7eb26f1364828e006 to your computer and use it in GitHub Desktop.

Select an option

Save jwpleow/88dac73d7e841ab7eb26f1364828e006 to your computer and use it in GitHub Desktop.
test ipc logging using iceoryx and spdlog
cmake_minimum_required(VERSION 3.15)
include_guard(GLOBAL)
project(ipc_logging)
find_package(spdlog CONFIG REQUIRED)
find_package(iceoryx_posh CONFIG REQUIRED)
find_package(iceoryx_hoofs CONFIG REQUIRED)
include(GNUInstallDirs)
add_library(ipc_logging INTERFACE)
add_library(waffle::ipc_logging ALIAS ipc_logging)
target_include_directories(ipc_logging
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(ipc_logging
INTERFACE
spdlog::spdlog
iceoryx_posh::iceoryx_posh
iceoryx_hoofs::iceoryx_hoofs
)
target_compile_features(ipc_logging PUBLIC cxx_std_11)
install(FILES subscriber.hpp spdlog_ipc_sink.hpp
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
#pragma once
#include <iceoryx_posh/popo/untyped_publisher.hpp>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/spdlog.h>
namespace waffle
{
// The iceoryx runtime MUST be initialised before instantiating this.
template<typename Mutex>
class iceoryx_sink : public spdlog::sinks::base_sink<Mutex>
{
public:
// Make sure the ID's are <100 characters!
iceoryx_sink(const std::string& serviceID,
const std::string& instanceID,
const std::string& eventID)
: m_publisher(iox::capro::ServiceDescription(iox::capro::IdString_t(iox::cxx::TruncateToCapacity, serviceID),
iox::capro::IdString_t(iox::cxx::TruncateToCapacity, instanceID),
iox::capro::IdString_t(iox::cxx::TruncateToCapacity, eventID)),
iox::popo::PublisherOptions{16U, "", true, iox::popo::ConsumerTooSlowPolicy::WAIT_FOR_CONSUMER}
)
{
}
protected:
void sink_it_(const spdlog::details::log_msg& msg) override
{
spdlog::memory_buf_t formatted;
spdlog::sinks::base_sink<Mutex>::formatter_->format(msg, formatted);
const auto logString = fmt::to_string(formatted);
m_publisher.loan(logString.size() + 1)
.and_then([&](auto& payload) {
std::memcpy(reinterpret_cast<char*>(payload), logString.c_str(), logString.size() + 1);
m_publisher.publish(payload);
})
.or_else([&](auto& error) {
std::cerr << "waffle::iceoryx_sink - Unable to loan memory for publish call. Error code " << static_cast<uint64_t>(error) << "\n";
});
}
void flush_() override
{
}
protected:
iox::popo::UntypedPublisher m_publisher;
};
}
#pragma once
#include <string>
#include <iceoryx_posh/popo/untyped_subscriber.hpp>
#include <iceoryx_posh/popo/listener.hpp>
#include <spdlog/spdlog.h>
namespace waffle
{
// The iceoryx runtime MUST be initialised before instantiating this.
template <class Queue> // e.g. https://github.com/cameron314/readerwriterqueue
class LogSubscriber
{
public:
LogSubscriber(const std::string& serviceID,
const std::string& instanceID,
const std::string& eventID,
);
Queue& GetQueue() { return m_logQueue; }
private:
static void OnDataReceivedCallbackImpl(iox::popo::UntypedSubscriber* subscriber, LogSubscriber* self);
private:
iox::popo::Listener m_ioxListener;
iox::popo::UntypedSubscriber m_subscriber;
Queue m_logQueue{1024};
};
inline LogSubscriber::LogSubscriber(const std::string& serviceID,
const std::string& instanceID,
const std::string& eventID,
LogCallbackFn callback
)
: m_subscriber(iox::capro::ServiceDescription(iox::capro::IdString_t(iox::cxx::TruncateToCapacity, serviceID),
iox::capro::IdString_t(iox::cxx::TruncateToCapacity, instanceID),
iox::capro::IdString_t(iox::cxx::TruncateToCapacity, eventID)),
iox::popo::SubscriberOptions{256U, 0, "", true, iox::popo::QueueFullPolicy::BLOCK_PRODUCER})
{
m_ioxListener
.attachEvent(m_subscriber,
iox::popo::SubscriberEvent::DATA_RECEIVED,
iox::popo::createNotificationCallback(OnDataReceivedCallbackImpl, *this))
.or_else([&](auto) {
spdlog::error("LogSubscriber - Unable to attach the subscriber.");
});
}
inline void LogSubscriber::OnDataReceivedCallbackImpl(iox::popo::UntypedSubscriber* subscriber, LogSubscriber* self)
{
// Use a lock-free queue so we don't block the publisher as much as possible
while(subscriber->take().and_then([subscriber, self](auto& payload) {
std::string logString(reinterpret_cast<const char*>(payload)); // Rely on null-terminator
self->m_logQueue.enqueue(std::move(logString));
subscriber->release(payload);
})) {}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment