5 #include <boost/lockfree/policies.hpp>
6 #include <boost/lockfree/queue.hpp>
62 boost::lockfree::queue<Entry, boost::lockfree::capacity<queueSize>>
queue;
65 Reporting::Reporting(std::size_t maxErrorHistorySize) :
66 pimpl(
std::make_unique<
QueueImpl>()), m_maxErrorHistorySize(maxErrorHistorySize)
68 setTag(
"ethercat::Reporting");
71 m_errorProcessingThread = std::thread(&Reporting::errorProcessingLoop,
this);
74 Reporting::~Reporting()
76 m_errorProcessingRunning.store(
false);
77 m_errorProcessingCondition.notify_all();
78 m_errorProcessingThread.join();
105 bool result = pimpl->queue.push(error);
110 m_errorProcessingCondition.notify_all();
116 m_maxErrorHistorySize = maxErrorHistorySize;
119 std::optional<std::filesystem::path>
124 endTime - IceUtil::Time::seconds(
static_cast<std::int64_t
>(lastNSeconds));
125 if (startTime < m_timestampReportingStart)
127 startTime = m_timestampReportingStart;
129 const std::string yearString = startTime.toString(
"%y-%m-%d");
130 const std::string startTimeString = startTime.toString(
"%H-%M-%S");
131 const std::string endTimeString = endTime.toString(
"%H-%M-%S");
133 file.replace_filename(std::string(file.stem().c_str()) +
"_" + yearString +
"__" +
134 startTimeString +
"_" + endTimeString);
135 file.replace_extension(
".errors");
137 if (std::filesystem::exists(file))
139 file.replace_filename(file.filename().string() +
".new");
142 auto history = m_errorHistory;
143 auto it = history.begin();
144 for (
const auto& [key,
value] : history)
146 if (key.timestamp < startTime.toMicroSeconds())
151 history.erase(history.begin(), it);
153 if (history.size() > 0)
155 ARMARX_INFO << history.size() <<
" errors from " << startTimeString <<
" to "
156 << endTimeString <<
" will be saved to file " << file.string();
160 ARMARX_VERBOSE <<
"No errors happend from " << startTimeString <<
" to "
166 if (!std::filesystem::exists(file.parent_path()) &&
167 !std::filesystem::create_directories(file.parent_path()))
169 throw std::runtime_error{
"Could not create directories for '" + file.string() +
"'"};
172 std::ofstream outFile{file.string(), std::ofstream::out};
175 throw std::runtime_error{
"dumpToFile could not open filestream for '" + file.string() +
179 for (
const auto& [key,
value] : history)
182 std::string timeStr =
value.m_timestamp.toDateTime();
183 timeStr = timeStr.substr(timeStr.find(
' ') + 1);
185 outFile <<
"[" << timeStr <<
"]";
186 outFile <<
"[" <<
value.m_type <<
"]";
187 outFile <<
"[" <<
value.m_severity <<
"] ";
188 outFile << std::string(
value.m_message,
value.m_message_size) <<
"\n";
189 if (
value.m_sid.slaveIndex != -1)
191 outFile <<
value.m_sid.toString(
" ") <<
"\n";
195 return std::move(file);
199 Reporting::errorProcessingLoop()
202 auto handleEntries = [&,
this]()
204 while (pimpl->queue.pop(e))
206 const std::int64_t timestamp = e.m_timestamp.toMicroSeconds();
210 while (m_errorHistory.size() >= m_maxErrorHistorySize)
212 m_errorHistory.erase(m_errorHistory.begin());
216 if (m_errorHistory.begin()->first.timestamp == timestamp)
218 i = m_errorHistory.begin()->first.subid + 1;
220 while (m_errorHistory.count({timestamp, i}))
225 m_errorHistory.insert({{timestamp, i}, e});
228 (
loghelper(e.m_metaInfo.file, e.m_metaInfo.line, e.m_metaInfo.function));
229 switch (e.m_severity)
232 *logpointer->setBacktrace(
false)
237 *logpointer->setBacktrace(
false)
238 << ::armarx::MessageTypeT::DEBUG
243 *logpointer->setBacktrace(
false)
244 << ::armarx::MessageTypeT::WARN
249 *logpointer->setBacktrace(
false)
250 << ::armarx::MessageTypeT::ERROR
255 *logpointer << ::armarx::MessageTypeT::FATAL
263 while (m_errorProcessingRunning.load() ==
true)
265 std::unique_lock<std::mutex> lock{m_errorProcessingConditionMutex};
266 m_errorProcessingCondition.wait(
267 lock, [&]() {
return !pimpl->queue.empty() || !m_errorProcessingRunning.load(); });
275 Reporter::ReportWrapper
279 return Reporter::ReportWrapper{info,
this};
282 Reporter::ReportWrapper
286 return Reporter::ReportWrapper{info,
this};
289 Reporter::ReportWrapper
294 return Reporter::ReportWrapper{error,
this};
297 Reporter::ReportWrapper
302 return Reporter::ReportWrapper{error,
this};
310 m_errorReporting->report(std::move(error));
311 throw std::runtime_error(error.
toString());
317 return m_errorCount > 0;
320 Reporter::Reporter(
Reporting* errorReporting) : m_errorReporting(errorReporting)
341 snprintf(m_metaInfo.file,
sizeof(m_metaInfo.file),
"%s", file);
342 m_metaInfo.line = line;
343 snprintf(m_metaInfo.function,
sizeof(m_metaInfo.function),
"%s",
function);
350 snprintf(m_device_name,
sizeof(m_device_name),
"%s",
deviceName);
357 std::stringstream ss;
358 ss <<
"[" << m_type <<
"] ";
359 ss << std::string(m_message, m_message_size) <<
"\n";
364 if (m_device_name[0] !=
'\0')
366 ss <<
" " << std::left << std::setw(16) <<
"Name: " << std::string(m_device_name);
368 if (m_bus_iteration_number != 0)
370 ss <<
" " << std::left << std::setw(16)
380 m_bus_iteration_number = iteration;
384 Reporter::ReportWrapper::ReportWrapper(
Entry& error,
Reporter* reporter) :
385 m_error(error), m_reporter(reporter)
389 Reporter::ReportWrapper::~ReportWrapper()
391 m_reporter->m_errorReporting->report(std::move(m_error));
394 Reporter::ReportWrapper&
397 m_error.m_deactivate_spam_seconds = std::fmax(0.f, seconds);