38 #include "../ControlTargets/ControlTargetBase.h"
39 #include "../Devices/ControlDevice.h"
40 #include "../Devices/SensorDevice.h"
41 #include "../SensorValues/SensorValueBase.h"
48 struct ControlThreadOutputBuffer;
71 virtual std::size_t
line()
const = 0;
72 virtual std::string
file()
const = 0;
73 virtual std::string
func()
const = 0;
74 virtual std::string
format()
const = 0;
83 float deactivateSpamSec{0};
85 std::uint64_t deactivateSpamTag_;
94 std::string
format() const final override;
95 std::
size_t line() const final override;
96 std::
string file() const final override;
97 std::
string func() const final override;
138 std::size_t numEntries,
139 std::size_t bufferMaxSize,
140 std::size_t bufferMaxNumberEntries);
148 void reset(std::size_t& bufferSize, std::size_t& numEntries, std::size_t iterationCount);
150 const std::vector<const RtMessageLogEntryBase*>& getEntries()
const;
152 std::size_t getMaximalBufferSize()
const;
153 std::size_t getMaximalNumberOfBufferEntries()
const;
159 friend struct ::armarx::ControlThreadOutputBuffer;
160 friend class ::armarx::RobotUnit;
161 friend class ::armarx::RobotUnitModule::Logging;
163 const std::size_t initialBufferSize;
164 const std::size_t initialBufferEntryNumbers;
165 const std::size_t bufferMaxSize;
166 const std::size_t bufferMaxNumberEntries;
168 std::vector<std::uint8_t> buffer;
169 std::size_t bufferSpace;
172 std::vector<const RtMessageLogEntryBase*> entries;
173 std::size_t entriesWritten{0};
175 std::size_t requiredAdditionalBufferSpace{0};
176 std::size_t requiredAdditionalEntries{0};
177 std::size_t messagesLost{0};
179 std::size_t maxAlign{1};
189 std::size_t messageBufferSize,
190 std::size_t messageBufferNumberEntries,
191 std::size_t messageBufferMaxSize,
192 std::size_t messageBufferMaxNumberEntries);
194 bool minimize =
false);
201 std::size_t getDataBufferSize()
const;
208 std::vector<PropagateConst<SensorValueBase*>>
sensors;
209 std::vector<std::vector<PropagateConst<ControlTargetBase*>>>
control;
210 std::size_t iteration{0};
215 std::vector<std::uint8_t> buffer;
226 std::size_t initialize(std::size_t numEntries,
229 std::size_t messageBufferSize,
230 std::size_t messageBufferNumberEntries,
231 std::size_t messageBufferMaxSize,
232 std::size_t messageBufferMaxNumberEntries);
239 return RtLoggingInstance;
243 Entry& getWriteBuffer();
247 const Entry& getReadBuffer()
const;
248 bool updateReadBuffer()
const;
251 void resetLoggingPosition()
const;
252 void forEachNewLoggingEntry(ConsumerFunctor consumer);
253 void forLatestLoggingEntry(ConsumerFunctor consumer,
size_t numberOfEntriesToLog);
255 std::size_t getNumberOfBytes()
const;
257 template <
class LoggingEntryT,
class... Ts>
258 RtMessageLogEntryBase* addMessageToLog(Ts&&... args);
265 std::size_t toBounds(std::size_t idx)
const;
268 bool isInitialized{
false};
269 std::size_t numEntries{0};
271 std::atomic_size_t writePosition{0};
272 mutable std::atomic_size_t onePastLoggingReadPosition{0};
273 mutable std::atomic_size_t onePastReadPosition{0};
275 std::vector<Entry> entries;
276 std::vector<std::uint8_t>
data;
278 std::size_t messageBufferSize{0};
279 std::size_t messageBufferEntries{0};
285 #define ARMARX_RT_LOGF(...) \
286 (*(_detail_ARMARX_RT_LOGF(__FILE__, ARMARX_FUNCTION, __LINE__, __VA_ARGS__, true)))
288 #define _detail_ARMARX_RT_LOGF(file_, func_, line_, FormatString, ...) \
292 using namespace ::armarx; \
293 using RtMessageLogEntryBase = ControlThreadOutputBuffer::RtMessageLogEntryBase; \
294 struct RtMessageLogEntry : RtMessageLogEntryBase \
296 using TupleT = decltype(std::make_tuple(__VA_ARGS__)); \
297 const TupleT tuple; \
298 ARMARX_MINIMAL_PLACEMENT_CONSTRUCTION_HELPER \
300 line() const final override \
305 file() const final override \
310 func() const final override \
315 format() const final override \
317 return TupleToStringF<0, std::tuple_size<TupleT>::value - 1>(FormatString, \
320 RtMessageLogEntry(TupleT tuple) : tuple{std::move(tuple)} \
323 RtMessageLogEntry(const RtMessageLogEntry&) = default; \
325 if (::armarx::ControlThreadOutputBuffer::GetRtLoggingInstance()) \
327 return ::armarx::ControlThreadOutputBuffer::GetRtLoggingInstance() \
328 ->addMessageToLog<RtMessageLogEntry>(__VA_ARGS__); \
332 *(loghelper(file_, line_, func_)) \
333 << "Redirected RT Logging:\n" \
334 << RtMessageLogEntry(std::make_tuple(__VA_ARGS__)).format(); \
335 return dynamic_cast<RtMessageLogEntryBase*>( \
336 &::armarx::detail::RtMessageLogEntryNull::Instance); \
340 #define ARMARX_RT_LOGF_DEBUG(...) \
341 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::DEBUG)
342 #define ARMARX_RT_LOGF_VERBOSE(...) \
343 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::VERBOSE)
344 #define ARMARX_RT_LOGF_INFO(...) \
345 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::INFO)
346 #define ARMARX_RT_LOGF_IMPORTANT(...) \
347 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::IMPORTANT)
348 #define ARMARX_RT_LOGF_WARNING(...) \
349 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::WARN)
350 #define ARMARX_RT_LOGF_WARN(...) \
351 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::WARN)
352 #define ARMARX_RT_LOGF_ERROR(...) \
353 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::ERROR)
354 #define ARMARX_RT_LOGF_FATAL(...) \
355 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::FATAL)
369 throw std::logic_error{
"called 'format' of RtMessageLogEntryDummy"};
375 throw std::logic_error{
"called 'line' of RtMessageLogEntryDummy"};
381 throw std::logic_error{
"called 'file' of RtMessageLogEntryDummy"};
387 throw std::logic_error{
"called 'func' of RtMessageLogEntryDummy"};
391 std::size_t numEntries,
392 std::size_t bufferMaxSize,
393 std::size_t bufferMaxNumberEntries) :
394 initialBufferSize{bufferSize},
395 initialBufferEntryNumbers{numEntries},
396 bufferMaxSize{bufferMaxSize},
397 bufferMaxNumberEntries{bufferMaxNumberEntries},
398 buffer(bufferSize, 0),
399 bufferSpace{buffer.size()},
400 bufferPlace{buffer.data()},
401 entries(numEntries,
nullptr)
403 ARMARX_DEBUG <<
"RtMessageLogBuffer created with bufferSize=" << bufferSize
404 <<
" and numEntries=" << numEntries <<
" and bufferMaxSize=" << bufferMaxSize
405 <<
" and bufferMaxNumberEntries " << bufferMaxNumberEntries;
413 inline const std::vector<const RtMessageLogEntryBase*>&
422 return bufferMaxSize;
428 return bufferMaxNumberEntries;
434 return buffer.size();
441 ControlThreadOutputBuffer::toBounds(std::size_t idx)
const
443 return idx % numEntries;
452 template <
class LoggingEntryT,
class... Ts>
457 if (messages.entries.size() <= messages.entriesWritten)
459 ++messages.requiredAdditionalEntries;
460 ++messages.messagesLost;
463 messages.maxAlign =
std::max(messages.maxAlign,
alignof(LoggingEntryT));
464 void* place =
std::align(
alignof(LoggingEntryT),
465 sizeof(LoggingEntryT),
466 messages.bufferPlace,
467 messages.bufferSpace);
470 messages.requiredAdditionalBufferSpace +=
471 sizeof(LoggingEntryT) +
alignof(LoggingEntryT) - 1;
472 ++messages.messagesLost;
476 new (place) LoggingEntryT(std::make_tuple(std::forward<Ts>(args)...));
478 messages.bufferPlace =
static_cast<std::uint8_t*
>(place) +
sizeof(LoggingEntryT);
480 messages.bufferSpace -=
sizeof(LoggingEntryT);
483 messages.entries.at(messages.entriesWritten++) = entry;