RobotUnitModuleLogging.h
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package RobotAPI::ArmarXObjects::RobotUnit
17 * @author Raphael Grimm ( raphael dot grimm at kit dot edu )
18 * @date 2018
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#pragma once
24
25#include <atomic>
26#include <deque>
27#include <fstream>
28#include <map>
29#include <vector>
30
32
33#include <RobotAPI/interface/units/RobotUnit/RobotUnitInterface.h>
34
36#include "RobotUnitModuleBase.h"
37
39{
40 struct DoLoggingDurations;
41}
42
44{
46 {
47 public:
49 {
51 "RTLogging_PeriodMs",
52 10,
53 "Period of the rt-logging thread in milliseconds. "
54 "A high period can cause spikes in disk activity if data is logged to disk. "
55 "A low period causes more computation overhead and memory consumption. "
56 "Must not be 0.");
57
58 defineOptionalProperty<std::string>("RTLogging_DefaultLog",
59 "",
60 "If rt logging is active and a file path is given, "
61 "all data is logged to this file.");
62
64 "RTLogging_MessageNumber",
65 1000,
66 "Number of messages that can be logged in the control thread");
68 "RTLogging_MessageBufferSize",
69 1024 * 1024,
70 "Number of bytes that can be logged in the control thread");
72 "RTLogging_MaxMessageNumber",
73 16000,
74 "Max number of messages that can be logged in the control thread");
76 "RTLogging_MaxMessageBufferSize",
77 16 * 1024 * 1024,
78 "Max number of bytes that can be logged in the control thread");
79
81 "RTLogging_EnableBacklog",
82 true,
83 "Enable/Disable the backlog (SensorValues, ControlTargets, Messages) that is kept"
84 "and can be dumped in case of an error.");
85 defineOptionalProperty<std::size_t>("RTLogging_KeepIterationsForMs",
86 60 * 1000,
87 "All logging data (SensorValues, ControlTargets, "
88 "Messages) is kept for this duration "
89 "and can be dumped in case of an error.");
91 "RTLogging_MaxBacklogSize",
92 5000,
93 "Maximum size of the backlog (SensorValues, ControlTargets, Messages) that is kept"
94 "and can be dumped in case of an error.");
95
97 "RTLogging_StreamingDataMaxClientConnectionFailures",
98 10,
99 "If sending data to a client fails this often, the client is removed from the "
100 "list");
101
103 "RTLogging_LogLastNMessagesOnly",
104 -1,
105 "If greater than 0, logs/streams only the last n timesteps that are in the entry "
106 "cue of the ControlThreadOutputBuffer");
107 }
108 };
109
110 /**
111 * @ingroup Library-RobotUnit-Modules
112 * @brief This \ref ModuleBase "Module" manages logging of data.
113 *
114 * There are two types of data:
115 * - Messages: These are logged via \ref ARMARX_RT_LOGF macros and printed to the corresponding ArmarX streams
116 * - \ref SensorValueBase "SensorValues" / \ref ControlTargetBase "ControlTargets": These can be logged to CSV files
117 *
118 * @see ModuleBase
119 */
120 class Logging : virtual public ModuleBase, virtual public RobotUnitLoggingInterface
121 {
122 friend class ModuleBase;
123
124 public:
125 /**
126 * @brief Returns the singleton instance of this class
127 * @return The singleton instance of this class
128 */
129 static Logging&
131 {
133 }
134
135 // //////////////////////////////////////////////////////////////////////////////////////// //
136 // ///////////////////////////////// RobotUnitModule hooks //////////////////////////////// //
137 // //////////////////////////////////////////////////////////////////////////////////////// //
138 private:
139 /// @see ModuleBase::_postOnInitRobotUnit
140 void _postOnInitRobotUnit();
141 /// @see ModuleBase::_postFinishDeviceInitialization
142 void _postFinishDeviceInitialization();
143 /// @see ModuleBase::_preFinishControlThreadInitialization
144 void _preFinishControlThreadInitialization();
145 /// @see ModuleBase::_preFinishRunning
146 void _preFinishRunning();
147 // //////////////////////////////////////////////////////////////////////////////////////// //
148 // ///////////////////////////////////// ice interface //////////////////////////////////// //
149 // //////////////////////////////////////////////////////////////////////////////////////// //
150 public:
151 /**
152 * @brief Starts logging to a CSV file
153 * @param formatString The file to log to.
154 * @param loggingNames The data fields to log.
155 * @return A handle to the log. If it's last copy is deleted, logging is stopped.
156 */
157 SimpleRemoteReferenceCounterBasePtr
158 startRtLogging(const std::string& formatString,
159 const Ice::StringSeq& loggingNames,
160 const Ice::Current& = Ice::emptyCurrent) override;
161 /**
162 * @brief Starts logging to a CSV file
163 * @param formatString The file to log to.
164 * @param aliasNames Data fields to log. For an entry (key,value), the datafield key is logged and the table heading value is used.
165 * If value is empty, key is used as heading.
166 * @return A handle to the log. If it's last copy is deleted, logging is stopped.
167 */
168 SimpleRemoteReferenceCounterBasePtr
169 startRtLoggingWithAliasNames(const std::string& formatString,
170 const StringStringDictionary& aliasNames,
171 const Ice::Current& = Ice::emptyCurrent) override;
172
173 /**
174 * @brief Stops logging to the given log.
175 * @param token The log to close.
176 */
177 void stopRtLogging(const armarx::SimpleRemoteReferenceCounterBasePtr& token,
178 const Ice::Current& = Ice::emptyCurrent) override;
179 /**
180 * @brief Adds a string to the log (it is added in a special column).
181 * @param token The log.
182 * @param marker The string to add.
183 */
184 void addMarkerToRtLog(const SimpleRemoteReferenceCounterBasePtr& token,
185 const std::string& marker,
186 const Ice::Current& = Ice::emptyCurrent) override;
187
188 /**
189 * @brief Returns the names of all loggable data fields.
190 * @return The names of all loggable data fields.
191 */
192 Ice::StringSeq getLoggingNames(const Ice::Current& = Ice::emptyCurrent) const override;
193 /**
194 * @brief Dumps the backlog of all recent iterations to the given file.
195 * This helps debugging.
196 * @param formatString The file.
197 */
198 void writeRecentIterationsToFile(const std::string& formatString,
199 const Ice::Current& = Ice::emptyCurrent) const override;
200
201 RobotUnitDataStreaming::DataStreamingDescription
202 startDataStreaming(const RobotUnitDataStreaming::ReceiverPrx& receiver,
203 const RobotUnitDataStreaming::Config& config,
204 const Ice::Current& = Ice::emptyCurrent) override;
205
206 void stopDataStreaming(const RobotUnitDataStreaming::ReceiverPrx& receiver,
207 const Ice::Current& = Ice::emptyCurrent) override;
208 // //////////////////////////////////////////////////////////////////////////////////////// //
209 // //////////////////////////////////// implementation //////////////////////////////////// //
210 // //////////////////////////////////////////////////////////////////////////////////////// //
211 private:
212 /// @brief Executes the logging loop.
213 void doLogging();
214 void doLogging(details::DoLoggingDurations& durations,
215 const IceUtil::Time& now,
217 std::size_t i,
218 std::size_t num);
219 static bool MatchName(const std::string& pattern, const std::string& name);
220
221 // //////////////////////////////////////////////////////////////////////////////////////// //
222 // ///////////////////////////////////////// Data ///////////////////////////////////////// //
223 // //////////////////////////////////////////////////////////////////////////////////////// //
224 private:
225 /// @brief Data structure holding information about an logging entry.
226 struct CSVLoggingEntry
227 {
228 /// @brief Whether logging should be stopped.
229 std::atomic_bool stopLogging{false};
230 /// @brief Bools whether a control device field should be logged.
231 std::vector<std::vector<std::vector<char>>> loggedControlDeviceValues;
232 /// @brief Bools whether a sensor device field should be logged.
233 std::vector<std::vector<char>> loggedSensorDeviceValues;
234 /// @brief The file stream for the csv file
235 std::ofstream stream;
236 /// @brief The file name
237 std::string filename;
238 /// @brief The marker to add in the next logging iteration. (protected by \ref rtLoggingMutex)
239 std::string marker;
240 };
241
242 struct DataStreamingEntry
243 {
244 enum class ValueT
245 {
246 Bool,
247 Byte,
248 Short,
249 Int,
250 Long,
251 Float,
252 Double,
253 Skipped
254 };
255
256 struct OutVal
257 {
258 std::size_t idx;
259 ValueT value = ValueT::Skipped;
260 };
261
262 bool stopStreaming = false;
263
264 std::size_t numBools = 0;
265 std::size_t numBytes = 0;
266 std::size_t numShorts = 0;
267 std::size_t numInts = 0;
268 std::size_t numLongs = 0;
269 std::size_t numFloats = 0;
270 std::size_t numDoubles = 0;
271
272 bool onlyNewestFrame = false;
273 std::size_t connectionFailures = 0;
274 std::size_t rtStreamMaxClientErrors = 0;
275
276 std::vector<std::vector<OutVal>> sensDevs;
277 std::vector<std::vector<std::vector<OutVal>>> ctrlDevs;
278
279 RobotUnitDataStreaming::TimeStepSeq result;
280 std::deque<RobotUnitDataStreaming::TimeStep> entryBuffer;
281 std::deque<Ice::AsyncResultPtr> updateCalls;
282 void clearResult();
283 RobotUnitDataStreaming::TimeStep getResultElement();
284 RobotUnitDataStreaming::TimeStep allocateResultElement() const;
285
286
287 void processHeader(const ControlThreadOutputBuffer::Entry& e);
288 void processCtrl(const ControlTargetBase& val,
289 std::size_t didx,
290 std::size_t vidx,
291 std::size_t fidx);
292 void processSens(const SensorValueBase& val, std::size_t didx, std::size_t fidx);
293 void send(const RobotUnitDataStreaming::ReceiverPrx& r, uint64_t msgId);
294 };
295
296 std::map<RobotUnitDataStreaming::ReceiverPrx, DataStreamingEntry> rtDataStreamingEntry;
297 std::uint64_t rtDataStreamingMsgID = 0;
298
299 /// @brief The thread executing the logging functions.
300 std::thread rtLoggingTask;
301 std::atomic_bool stopRtLoggingTask{false};
302 /// @brief All entries for logging.
303 std::map<std::string, std::shared_ptr<CSVLoggingEntry>> rtLoggingEntries;
304 /// @brief Handle for the default log. (This log can be enabled via a property and logs everything)
305 SimpleRemoteReferenceCounterBasePtr defaultLogHandle;
306 /// @brief The stored backlog (it is dumped when \ref writeRecentIterationsToFile is called)
307 std::deque<::armarx::detail::ControlThreadOutputBufferEntry> backlog;
308 /// @brief The control threads unix thread id
309 Ice::Int controlThreadId{0};
310 /// @brief Mutex protecting the data structures of this class
311 mutable std::mutex rtLoggingMutex;
312
313 struct ValueMetaData
314 {
316 {
317 std::string name;
318 const std::type_info* type;
319 };
320
321 std::vector<FieldMetaData> fields;
322 };
323
324 /// @brief Data field info for all \ref ControlTargetBase "ControlTargets" (dex x jctrl)
325 std::vector<std::vector<ValueMetaData>> controlDeviceValueMetaData;
326 /// @brief Data field info for all \ref SensorValueBase "SensorValues" (dev)
327 std::vector<ValueMetaData> sensorDeviceValueMetaData;
328
329 /// @brief The initial size of the Message entry buffer
330 std::size_t messageBufferSize{0};
331 /// @brief The initial number of Message entries
332 std::size_t messageBufferNumberEntries{0};
333 /// @brief The maximal size of the Message entry buffer
334 std::size_t messageBufferMaxSize{0};
335 /// @brief The maximal number of Message entries
336 std::size_t messageBufferMaxNumberEntries{0};
337 /// @brief The logging thread's period
338 std::size_t rtLoggingTimestepMs{0};
339 /// @brief The time an entry should remain in the backlog.
340 IceUtil::Time rtLoggingBacklogRetentionTime;
341 /// @brief The maximum number of entries in the backlog.
342 std::size_t rtLoggingBacklogMaxSize;
343 /// @brief Enable/disable the backlog.
344 bool rtLoggingBacklogEnabled;
345
346 /// @brief
347 int numberOfEntriesToLog{-1};
348
349 friend void WriteTo(const auto& dentr,
350 const Logging::DataStreamingEntry::OutVal& out,
351 const auto& val,
352 std::size_t fidx,
353 auto& data);
354 };
355} // namespace armarx::RobotUnitModule
Brief description of class JointControlTargetBase.
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
PropertyDefinition< PropertyType > & defineOptionalProperty(const std::string &name, PropertyType defaultValue, const std::string &description="", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
This Module manages logging of data.
SimpleRemoteReferenceCounterBasePtr startRtLoggingWithAliasNames(const std::string &formatString, const StringStringDictionary &aliasNames, const Ice::Current &=Ice::emptyCurrent) override
Starts logging to a CSV file.
Ice::StringSeq getLoggingNames(const Ice::Current &=Ice::emptyCurrent) const override
Returns the names of all loggable data fields.
void writeRecentIterationsToFile(const std::string &formatString, const Ice::Current &=Ice::emptyCurrent) const override
Dumps the backlog of all recent iterations to the given file.
static Logging & Instance()
Returns the singleton instance of this class.
SimpleRemoteReferenceCounterBasePtr startRtLogging(const std::string &formatString, const Ice::StringSeq &loggingNames, const Ice::Current &=Ice::emptyCurrent) override
Starts logging to a CSV file.
void stopRtLogging(const armarx::SimpleRemoteReferenceCounterBasePtr &token, const Ice::Current &=Ice::emptyCurrent) override
Stops logging to the given log.
RobotUnitDataStreaming::DataStreamingDescription startDataStreaming(const RobotUnitDataStreaming::ReceiverPrx &receiver, const RobotUnitDataStreaming::Config &config, const Ice::Current &=Ice::emptyCurrent) override
friend void WriteTo(const auto &dentr, const Logging::DataStreamingEntry::OutVal &out, const auto &val, std::size_t fidx, auto &data)
void stopDataStreaming(const RobotUnitDataStreaming::ReceiverPrx &receiver, const Ice::Current &=Ice::emptyCurrent) override
void addMarkerToRtLog(const SimpleRemoteReferenceCounterBasePtr &token, const std::string &marker, const Ice::Current &=Ice::emptyCurrent) override
Adds a string to the log (it is added in a special column).
static ModuleBase & Instance()
Returns the singleton instance of this class.
The SensorValueBase class.
detail::ControlThreadOutputBufferEntry Entry