33 #include "../ControlTargets/ControlTargetBase.h"
34 #include "../Devices/ControlDevice.h"
35 #include "../Devices/SensorDevice.h"
36 #include "../SensorValues/SensorValueBase.h"
43 struct ControlThreadOutputBuffer;
66 virtual std::size_t
line()
const = 0;
67 virtual std::string
file()
const = 0;
68 virtual std::string
func()
const = 0;
69 virtual std::string
format()
const = 0;
78 float deactivateSpamSec{0};
80 std::uint64_t deactivateSpamTag_;
89 std::string
format() const final override;
90 std::
size_t line() const final override;
91 std::
string file() const final override;
92 std::
string func() const final override;
133 std::size_t numEntries,
134 std::size_t bufferMaxSize,
135 std::size_t bufferMaxNumberEntries);
143 void reset(std::size_t& bufferSize, std::size_t& numEntries, std::size_t iterationCount);
145 const std::vector<const RtMessageLogEntryBase*>& getEntries()
const;
147 std::size_t getMaximalBufferSize()
const;
148 std::size_t getMaximalNumberOfBufferEntries()
const;
154 friend struct ::armarx::ControlThreadOutputBuffer;
155 friend class ::armarx::RobotUnit;
156 friend class ::armarx::RobotUnitModule::Logging;
158 const std::size_t initialBufferSize;
159 const std::size_t initialBufferEntryNumbers;
160 const std::size_t bufferMaxSize;
161 const std::size_t bufferMaxNumberEntries;
163 std::vector<std::uint8_t> buffer;
164 std::size_t bufferSpace;
167 std::vector<const RtMessageLogEntryBase*> entries;
168 std::size_t entriesWritten{0};
170 std::size_t requiredAdditionalBufferSpace{0};
171 std::size_t requiredAdditionalEntries{0};
172 std::size_t messagesLost{0};
174 std::size_t maxAlign{1};
184 std::size_t messageBufferSize,
185 std::size_t messageBufferNumberEntries,
186 std::size_t messageBufferMaxSize,
187 std::size_t messageBufferMaxNumberEntries);
189 bool minimize =
false);
196 std::size_t getDataBufferSize()
const;
203 std::vector<PropagateConst<SensorValueBase*>>
sensors;
204 std::vector<std::vector<PropagateConst<ControlTargetBase*>>>
control;
205 std::size_t iteration{0};
210 std::vector<std::uint8_t> buffer;
221 std::size_t initialize(std::size_t numEntries,
224 std::size_t messageBufferSize,
225 std::size_t messageBufferNumberEntries,
226 std::size_t messageBufferMaxSize,
227 std::size_t messageBufferMaxNumberEntries);
234 return RtLoggingInstance;
238 Entry& getWriteBuffer();
242 const Entry& getReadBuffer()
const;
243 bool updateReadBuffer()
const;
246 void resetLoggingPosition()
const;
247 void forEachNewLoggingEntry(ConsumerFunctor consumer);
248 void forLatestLoggingEntry(ConsumerFunctor consumer,
size_t numberOfEntriesToLog);
250 std::size_t getNumberOfBytes()
const;
252 template <
class LoggingEntryT,
class... Ts>
253 RtMessageLogEntryBase* addMessageToLog(Ts&&... args);
260 std::size_t toBounds(std::size_t idx)
const;
263 bool isInitialized{
false};
264 std::size_t numEntries{0};
266 std::atomic_size_t writePosition{0};
267 mutable std::atomic_size_t onePastLoggingReadPosition{0};
268 mutable std::atomic_size_t onePastReadPosition{0};
270 std::vector<Entry> entries;
271 std::vector<std::uint8_t>
data;
273 std::size_t messageBufferSize{0};
274 std::size_t messageBufferEntries{0};
280 #define ARMARX_RT_LOGF(...) \
281 (*(_detail_ARMARX_RT_LOGF(__FILE__, ARMARX_FUNCTION, __LINE__, __VA_ARGS__, true)))
283 #define _detail_ARMARX_RT_LOGF(file_, func_, line_, FormatString, ...) \
287 using namespace ::armarx; \
288 using RtMessageLogEntryBase = ControlThreadOutputBuffer::RtMessageLogEntryBase; \
289 struct RtMessageLogEntry : RtMessageLogEntryBase \
291 using TupleT = decltype(std::make_tuple(__VA_ARGS__)); \
292 const TupleT tuple; \
293 ARMARX_MINIMAL_PLACEMENT_CONSTRUCTION_HELPER \
295 line() const final override \
300 file() const final override \
305 func() const final override \
310 format() const final override \
312 return TupleToStringF<0, std::tuple_size<TupleT>::value - 1>(FormatString, \
315 RtMessageLogEntry(TupleT tuple) : tuple{std::move(tuple)} \
318 RtMessageLogEntry(const RtMessageLogEntry&) = default; \
320 if (::armarx::ControlThreadOutputBuffer::GetRtLoggingInstance()) \
322 return ::armarx::ControlThreadOutputBuffer::GetRtLoggingInstance() \
323 ->addMessageToLog<RtMessageLogEntry>(__VA_ARGS__); \
327 *(loghelper(file_, line_, func_)) \
328 << "Redirected RT Logging:\n" \
329 << RtMessageLogEntry(std::make_tuple(__VA_ARGS__)).format(); \
330 return dynamic_cast<RtMessageLogEntryBase*>( \
331 &::armarx::detail::RtMessageLogEntryNull::Instance); \
335 #define ARMARX_RT_LOGF_DEBUG(...) \
336 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::DEBUG)
337 #define ARMARX_RT_LOGF_VERBOSE(...) \
338 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::VERBOSE)
339 #define ARMARX_RT_LOGF_INFO(...) \
340 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::INFO)
341 #define ARMARX_RT_LOGF_IMPORTANT(...) \
342 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::IMPORTANT)
343 #define ARMARX_RT_LOGF_WARNING(...) \
344 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::WARN)
345 #define ARMARX_RT_LOGF_WARN(...) \
346 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::WARN)
347 #define ARMARX_RT_LOGF_ERROR(...) \
348 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::ERROR)
349 #define ARMARX_RT_LOGF_FATAL(...) \
350 ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::FATAL)
364 throw std::logic_error{
"called 'format' of RtMessageLogEntryDummy"};
370 throw std::logic_error{
"called 'line' of RtMessageLogEntryDummy"};
376 throw std::logic_error{
"called 'file' of RtMessageLogEntryDummy"};
382 throw std::logic_error{
"called 'func' of RtMessageLogEntryDummy"};
386 std::size_t numEntries,
387 std::size_t bufferMaxSize,
388 std::size_t bufferMaxNumberEntries) :
389 initialBufferSize{bufferSize},
390 initialBufferEntryNumbers{numEntries},
391 bufferMaxSize{bufferMaxSize},
392 bufferMaxNumberEntries{bufferMaxNumberEntries},
393 buffer(bufferSize, 0),
394 bufferSpace{buffer.size()},
395 bufferPlace{buffer.data()},
396 entries(numEntries,
nullptr)
398 ARMARX_DEBUG <<
"RtMessageLogBuffer created with bufferSize=" << bufferSize
399 <<
" and numEntries=" << numEntries <<
" and bufferMaxSize=" << bufferMaxSize
400 <<
" and bufferMaxNumberEntries " << bufferMaxNumberEntries;
408 inline const std::vector<const RtMessageLogEntryBase*>&
417 return bufferMaxSize;
423 return bufferMaxNumberEntries;
429 return buffer.size();
436 ControlThreadOutputBuffer::toBounds(std::size_t idx)
const
438 return idx % numEntries;
447 template <
class LoggingEntryT,
class... Ts>
452 if (messages.entries.size() <= messages.entriesWritten)
454 ++messages.requiredAdditionalEntries;
455 ++messages.messagesLost;
458 messages.maxAlign =
std::max(messages.maxAlign,
alignof(LoggingEntryT));
459 void* place =
std::align(
alignof(LoggingEntryT),
460 sizeof(LoggingEntryT),
461 messages.bufferPlace,
462 messages.bufferSpace);
465 messages.requiredAdditionalBufferSpace +=
466 sizeof(LoggingEntryT) +
alignof(LoggingEntryT) - 1;
467 ++messages.messagesLost;
471 new (place) LoggingEntryT(std::make_tuple(std::forward<Ts>(args)...));
473 messages.bufferPlace =
static_cast<std::uint8_t*
>(place) +
sizeof(LoggingEntryT);
475 messages.bufferSpace -=
sizeof(LoggingEntryT);
478 messages.entries.at(messages.entriesWritten++) = entry;