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();
84 static Reporting _instance;
105 bool result = pimpl->queue.push(error);
110 m_errorProcessingCondition.notify_all();
116 m_maxErrorHistorySize = maxErrorHistorySize;
119 std::optional<std::filesystem::path>
123 IceUtil::Time startTime =
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));
232 switch (e.m_severity)
235 *logpointer->setBacktrace(
false)
241 *logpointer->setBacktrace(
false)
247 *logpointer->setBacktrace(
false)
253 *logpointer->setBacktrace(
false)
267 while (m_errorProcessingRunning.load() ==
true)
269 std::unique_lock<std::mutex> lock{m_errorProcessingConditionMutex};
270 m_errorProcessingCondition.wait(
271 lock, [&]() {
return !pimpl->queue.empty() || !m_errorProcessingRunning.load(); });
279 Reporter::ReportWrapper
283 return Reporter::ReportWrapper{info,
this};
286 Reporter::ReportWrapper
290 return Reporter::ReportWrapper{info,
this};
293 Reporter::ReportWrapper
298 return Reporter::ReportWrapper{error,
this};
301 Reporter::ReportWrapper
306 return Reporter::ReportWrapper{error,
this};
314 m_errorReporting->report(std::move(error));
315 throw std::runtime_error(error.
toString());
321 return m_errorCount > 0;
324 Reporter::Reporter(
Reporting* errorReporting) : m_errorReporting(errorReporting)
345 snprintf(m_metaInfo.file,
sizeof(m_metaInfo.file),
"%s", file);
346 m_metaInfo.line = line;
347 snprintf(m_metaInfo.function,
sizeof(m_metaInfo.function),
"%s", function);
354 snprintf(m_device_name,
sizeof(m_device_name),
"%s",
deviceName);
361 std::stringstream ss;
362 ss <<
"[" << m_type <<
"] ";
363 ss << std::string(m_message, m_message_size) <<
"\n";
364 if (m_sid.slaveIndex != -1)
366 ss << m_sid.toString(
" ");
368 if (m_device_name[0] !=
'\0')
370 ss <<
" " << std::left << std::setw(16) <<
"Name: " << std::string(m_device_name);
372 if (m_bus_iteration_number != 0)
374 ss <<
" " << std::left << std::setw(16)
375 <<
"Bus Iteration: " << std::to_string(m_bus_iteration_number);
384 if (m_identifier_size > 0)
390 return std::string{m_metaInfo.file} +
"/" + std::string{m_metaInfo.function} +
"/" +
391 std::to_string(m_metaInfo.line);
398 m_bus_iteration_number = iteration;
402 Reporter::ReportWrapper::ReportWrapper(
Entry& error,
Reporter* reporter) :
403 m_error(error), m_reporter(reporter)
407 Reporter::ReportWrapper::~ReportWrapper()
409 m_reporter->m_errorReporting->
report(std::move(m_error));
412 Reporter::ReportWrapper&
413 Reporter::ReportWrapper::deactivateSpam(
float seconds)
415 m_error.m_deactivate_spam_seconds = std::fmax(0.f, seconds);
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Brief description of class Entry.
Entry & slaveIdentifier(SlaveIdentifier sid)
std::string toString() const
Entry & busIterationNumber(std::uint64_t iteration)
Entry & deviceName(const char *deviceName)
Entry & metaInfo(const char *file, int line, const char *function)
Entry & errorType(Type type)
std::string getIdentifier() const