25#include <ArmarXCore/interface/core/ManagedIceObjectDefinitions.h>
27#include <ArmarXGui/gui-plugins/LoggingPlugin/ui_FilterDialog.h>
39#include <boost/algorithm/string/regex.hpp>
41#include <QColorDialog>
43#include <QInputDialog>
55#define USERROLE_LOGTABLEID Qt::UserRole + 1
56#define USERROLE_LOGTABLEPTR Qt::UserRole + 2
57#define USERROLE_BASENAME Qt::UserRole + 3
58#define REGEX_COLORS "\033\\[(\\d|\\w?)[;]?(\\d+)m"
59#define ALL_MESSAGES_FILTER "All Messages"
64 logTable(NULL), loggingPaused(false), verbosityLevel(1), customToolbar(0)
67 qRegisterMetaType<Qt::Orientation>(
"Qt::Orientation");
68 qRegisterMetaType<std::string>(
"std::string");
71 for (
int i = 0; i < eLogLevelCount; i++)
76 ui.cbVerbosityLevel->setCurrentIndex(1);
79 verbosityLevel =
ui.cbVerbosityLevel->currentIndex();
80 connect(
ui.cbVerbosityLevel,
81 QOverload<int>::of(&QComboBox::currentIndexChanged),
83 [
this](
int index) { verbosityLevel = index; });
85 ui.lvFilters->setCurrentItem(
ui.lvFilters->invisibleRootItem()->child(0));
89 ui.lvFilters->setSortingEnabled(
false);
91 pendingEntriesTimer =
new QTimer(
getWidget());
92 pendingEntriesTimer->setInterval(50);
99 filterBadgeTimer =
new QTimer(
getWidget());
100 filterBadgeTimer->setInterval(250);
101 connect(filterBadgeTimer, SIGNAL(timeout()),
this, SLOT(
updateFilterList()));
107 sizes.push_back(400);
108 ui.splitter->setSizes(sizes);
121 qRegisterMetaType<LogMessage>(
"LogMessage");
128 connect(
ui.btnAddFilter, SIGNAL(clicked()),
this, SLOT(
addFilter()));
130 connect(
ui.btnPause, SIGNAL(toggled(
bool)),
this, SLOT(
pauseLogging(
bool)));
132 connect(
ui.btnClearAllLogs, SIGNAL(clicked()),
this, SLOT(
clearAllLogs()));
133 connect(
ui.lvFilters,
134 SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
137 connect(
ui.lvFilters,
138 SIGNAL(itemDoubleClicked(QTreeWidgetItem*,
int)),
151 &QWidget::customContextMenuRequested,
154 QShortcut* deleteLabelShortcut =
new QShortcut(QKeySequence::Delete,
ui.lvLabels);
155 deleteLabelShortcut->setContext(Qt::WidgetShortcut);
159 ui.edtLiveFilter->hide();
160 ui.edtLiveSearch->setFocus();
171 ui.cbVerbosityLevel->setCurrentIndex(settings->value(
"verbosityLevel", 2).toInt());
172 ui.cbAutoComponentFilters->setChecked(settings->value(
"autoFilterAdding",
true).toBool());
179 settings->setValue(
"verbosityLevel",
ui.cbVerbosityLevel->currentIndex());
181 settings->setValue(
"autoFilterAdding",
ui.cbAutoComponentFilters->isChecked());
231 LogViewer::loggingGroupNameToFilterName(
const QString& loggingGroupName)
const
233 return loggingGroupName.isEmpty() ?
"" : (
"#" + loggingGroupName);
237 LogViewer::sortFilterList()
239 ui.lvFilters->sortItems(0, Qt::AscendingOrder);
243 LogViewer::autoFilterId(
const QString& loggingGroupName,
const QString& componentName)
const
245 const QString filler =
246 (loggingGroupName.length() > 0 && componentName.length() > 0) ?
"_" :
"";
247 return loggingGroupNameToFilterName(loggingGroupName) + filler + componentName;
251 LogViewer::ensureAutoFilter(
const QString& filterId,
252 const QString& loggingGroupName,
253 const QString& componentName,
256 if (filterId.isEmpty())
261 const auto it = autoFilterMap.find(filterId);
262 if (it != autoFilterMap.end())
267 if (!mayCreate || !
ui.cbAutoComponentFilters->isChecked() || filterMap.count(filterId))
274 const QString filterName = componentName.length() > 0
276 : loggingGroupNameToFilterName(loggingGroupName);
280 filterId, filterName, loggingGroupName, componentName,
"", eDEBUG,
"",
"",
"");
285 generalFilters.erase(std::remove(generalFilters.begin(), generalFilters.end(), table),
286 generalFilters.end());
287 autoFilterMap.insert(filterId, table);
293 LogViewer::ingestBatch(
LogTable* table,
const std::vector<LogSeq>& seqs)
295 if (!table || seqs.empty())
300 const QString liveFilter = table->getCurrentLiveFilter();
301 MessageType batchMaxLevel = eUNDEFINED;
302 const int rowsAdded = table->getModel()->addEntries(seqs, &batchMaxLevel);
304 if (!table->getModel()->isMaterialised())
308 table->notifyNewMessages(rowsAdded, batchMaxLevel);
312 if (rowsAdded > 0 && !liveFilter.isEmpty())
317 const int count = table->getModel()->rowCount();
318 for (
int r = std::max(0, count - rowsAdded); r < count; r++)
320 table->liveFilterRow(liveFilter, r);
333 const std::string&
tag,
334 MessageType severity,
335 const std::string& message,
336 const std::string& file,
338 const std::string& function,
349 msg.function = function;
365 if (verbosityLevel.load() <= msg.type)
367 std::unique_lock lock(pendingEntriesMutex);
368 if (pendingEntries.size() >= maxPendingEntries)
376 pendingEntries.push_back(msg);
385 if (filterStr.length() == 0)
389 else if (filterStr.length() < 3)
396 logTable->liveFilter(filterStr, startRow);
397 lastLiveSearchEditChangeTime = IceUtil::Time::now();
403 if (searchStr.length() == 0)
406 ui.btnNextItem->setEnabled(
false);
407 ui.btnPreviousItem->setEnabled(
false);
413 if (!
logTable->liveSearch(searchStr))
416 "Could not find '" +
logTable->getModel()->getCurrentSearchStr() +
419 ui.btnNextItem->setEnabled(
false);
420 ui.btnPreviousItem->setEnabled(
false);
424 ui.btnNextItem->setEnabled(
true);
425 ui.btnPreviousItem->setEnabled(
true);
440 expireOrphanedMarkers();
451 std::map<QString, LogTable*>::iterator it = filterMap.begin();
453 for (; it != filterMap.end(); it++)
455 it->second->getModel()->clearData();
460 it->second->resetNewMessageCount();
464 markerRegistry.clear();
470 LogViewer::expireOrphanedMarkers()
481 loggingPaused = pause;
485 LogViewer::setupLogTable(
LogTable* logTable)
499 [
this](
LogSeq seq) { markerRegistry.
add(seq); });
507 markerRegistry.
remove(
id);
516 setupLogTable(newLogTable);
518 QTreeWidgetItem* item =
new QTreeWidgetItem(
ui.lvFilters);
520 item->setText(0, standardFilterStr);
525 filterMap[standardFilterStr] = newLogTable;
527 generalFilters.push_back(newLogTable);
528 ui.splitter->addWidget(newLogTable);
536 QString loggingGroup,
537 QString componentFilter,
539 MessageType minimumVerbosity,
540 QString messageFilter,
542 QString functionFilter)
545 if (filterMap.find(filterId) != filterMap.end())
547 QString msg =
"A filter with the id " + filterId +
" exists already";
553 setupLogTable(newLogTable);
560 if (loggingGroup.length())
567 if (componentFilter.length())
573 if (tagFilter.length())
578 if (messageFilter.length())
583 if (fileFilter.length())
588 if (functionFilter.length())
591 functionFilter.toStdString());
595 QString::number(minimumVerbosity).toStdString());
597 QTreeWidgetItem* item =
new QTreeWidgetItem();
598 item->setText(0, filterName);
602 filterMap[filterId] = newLogTable;
606 generalFilters.push_back(newLogTable);
607 Ice::StringSeq children;
608 for (
int i = 0; i <
ui.lvFilters->invisibleRootItem()->childCount(); i++)
610 children.push_back(
ui.lvFilters->invisibleRootItem()->child(i)->text(0).toStdString());
613 QTreeWidgetItem* grpItem = NULL;
614 auto grpFilterId = loggingGroupNameToFilterName(loggingGroup);
615 for (
int i = 0; i <
ui.lvFilters->invisibleRootItem()->childCount(); i++)
617 if (
ui.lvFilters->invisibleRootItem()
620 .toString() == grpFilterId)
622 grpItem =
ui.lvFilters->invisibleRootItem()->child(i);
628 grpItem->addChild(item);
634 ui.lvFilters->insertTopLevelItem(0, item);
639 ui.splitter->addWidget(newLogTable);
646 if (componentName.length() == 0 && loggingGroupName.length() == 0)
651 const QString filterId = autoFilterId(loggingGroupName, componentName);
652 const bool existedBefore = autoFilterMap.contains(filterId);
653 return ensureAutoFilter(filterId, loggingGroupName, componentName,
true) !=
nullptr &&
662 if (!filterDialog.exec())
667 QString filterName = filterDialog.
ui->edtFilterName->text();
669 if (filterMap.find(filterName) != filterMap.end())
671 QString msg =
"A filter with this name already exists";
677 setupLogTable(newLogTable);
681 if (filterDialog.
ui->editComponent->text().length())
687 if (filterDialog.
ui->edtTag->text().length())
690 filterDialog.
ui->edtTag->text().toStdString());
693 if (filterDialog.
ui->edtMessage->text().length())
696 filterDialog.
ui->edtMessage->text().toStdString());
699 if (filterDialog.
ui->edtFile->text().length())
702 filterDialog.
ui->edtFile->text().toStdString());
705 if (filterDialog.
ui->edtFunction->text().length())
708 filterDialog.
ui->edtFunction->text().toStdString());
711 if (filterDialog.
ui->cbVerbosity->currentIndex() != -1)
715 QString::number(filterDialog.
ui->cbVerbosity->currentIndex()).toStdString());
718 QTreeWidgetItem* item =
new QTreeWidgetItem();
719 item->setText(0, filterName);
723 filterMap[filterName] = newLogTable;
726 generalFilters.push_back(newLogTable);
727 ui.lvFilters->insertTopLevelItem(
ui.lvFilters->invisibleRootItem()->childCount(), item);
730 ui.splitter->addWidget(newLogTable);
740 if (filterMap.find(filterId) == filterMap.end())
756 const QString value = QString::fromStdString(activeFilter.value);
758 switch (activeFilter.column)
761 filterDialog.
ui->editComponent->setText(value);
764 filterDialog.
ui->edtTag->setText(value);
767 filterDialog.
ui->cbVerbosity->setCurrentIndex(value.toInt());
770 filterDialog.
ui->edtMessage->setText(value);
773 filterDialog.
ui->edtFile->setText(value);
776 filterDialog.
ui->edtFunction->setText(value);
784 if (!filterDialog.exec())
788 item->setText(0, filterDialog.
ui->edtFilterName->text());
790 logTable->getModel()->resetFilters();
792 if (filterDialog.
ui->editComponent->text().length())
795 filterDialog.
ui->editComponent->text().toStdString());
798 if (filterDialog.
ui->edtTag->text().length())
801 filterDialog.
ui->edtTag->text().toStdString());
804 if (filterDialog.
ui->edtMessage->text().length())
807 filterDialog.
ui->edtMessage->text().toStdString());
810 if (filterDialog.
ui->edtFile->text().length())
813 filterDialog.
ui->edtFile->text().toStdString());
816 if (filterDialog.
ui->edtFunction->text().length())
819 filterDialog.
ui->edtFunction->text().toStdString());
822 if (filterDialog.
ui->cbVerbosity->currentIndex() != -1)
826 QString::number(filterDialog.
ui->cbVerbosity->currentIndex()).toStdString());
833 if (autoFilterMap.remove(filterId) > 0)
838 logTable->getModel()->reapplyAllFilters();
845 if (
ui.lvFilters->invisibleRootItem()->childCount() == 1)
850 auto item =
ui.lvFilters->currentItem();
862 std::map<QString, LogTable*>::iterator it =
865 if (it == filterMap.end())
869 QList<QTreeWidgetItem*> itemsToDelete, iterationList({item});
870 while (!iterationList.isEmpty())
872 auto curItem = iterationList.front();
873 itemsToDelete << curItem;
874 iterationList.pop_front();
875 iterationList << curItem->takeChildren();
877 ui.lvFilters->setCurrentItem(
ui.lvFilters->invisibleRootItem()->child(0));
878 for (
auto& item : itemsToDelete)
880 auto parent = item->parent();
883 parent->removeChild(item);
887 ui.lvFilters->invisibleRootItem()->removeChild(item);
889 std::map<QString, LogTable*>::iterator it =
893 if (it == filterMap.end())
899 generalFilters.erase(
900 std::remove(generalFilters.begin(), generalFilters.end(),
logTable),
901 generalFilters.end());
902 autoFilterMap.remove(it->first);
904 filterBadgeCache.erase(it->first);
921 item->setFont(0, font);
923 if (filterMap.find(filterId) == filterMap.end())
944 ui.edtLiveFilter->setText(
logTable->getLiveFilterStr());
945 ui.edtLiveSearch->setText(
logTable->getModel()->getCurrentSearchStr());
952 QList<QTreeWidgetItem*> itemsToUpdate, iterationList({
ui.lvFilters->invisibleRootItem()});
953 while (!iterationList.isEmpty())
955 auto curItem = iterationList.front();
956 itemsToUpdate << curItem;
957 iterationList.pop_front();
958 for (
int i = 0; i < curItem->childCount(); ++i)
960 iterationList << curItem->child(i);
964 for (
auto item : itemsToUpdate)
967 auto filterIt = filterMap.find(filterId);
968 if (filterIt == filterMap.end())
973 LogTable* curLogtable = filterIt->second;
985 const auto cached = filterBadgeCache.find(filterId);
986 if (cached != filterBadgeCache.end() && cached->second.count == newCount &&
987 cached->second.level == newLevel)
991 filterBadgeCache[filterId] = FilterBadge{newCount, newLevel};
998 item->setFont(0, font);
1000 item->setBackgroundColor(0,
ui.lvFilters->palette().base().color());
1005 item->setFont(0, font);
1007 QString::number(newCount) +
")";
1009 if (newLevel == eWARN)
1011 item->setBackgroundColor(0, QColor(216, 120, 50));
1013 else if (newLevel == eERROR)
1015 item->setBackgroundColor(0, QColor(255, 90, 80));
1017 else if (newLevel == eFATAL)
1019 item->setBackgroundColor(0, QColor(255, 60, 50));
1023 item->setBackgroundColor(0,
ui.lvFilters->palette().base().color());
1027 item->setText(0, newContent);
1028 item->setToolTip(0, newContent);
1033 const unsigned long long dropped = droppedEntryCount.load();
1034 if (dropped != lastReportedDropCount)
1036 lastReportedDropCount = dropped;
1040 QString(
"LogViewer: dropped %1 log messages (ingest overloaded)")
1050 throw LocalException() <<
"Not yet implemented";
1056 ui.lvLabels->clear();
1057 for (
const LogMarker& marker : markerRegistry.markers())
1059 if (!store.contains(marker.seq))
1063 const LogMessage& snapshot = store.at(marker.seq).message;
1066 QPixmap swatch(12, 12);
1067 swatch.fill(marker.color);
1070 IceUtil::Time time = IceUtil::Time::microSeconds(snapshot.time);
1071 std::string timeStr = time.toDateTime();
1072 const auto spacePos = timeStr.find(
' ');
1073 if (spacePos != std::string::npos)
1075 timeStr = timeStr.substr(spacePos + 1);
1078 QString what = QString::fromStdString(snapshot.what);
1079 const int newlinePos = what.indexOf(
'\n');
1080 if (newlinePos >= 0)
1082 what.truncate(newlinePos);
1084 constexpr int maxWhatLength = 60;
1085 if (what.length() > maxWhatLength)
1087 what.truncate(maxWhatLength);
1091 const QString text = QString::fromStdString(timeStr) +
" " +
1092 QString::fromStdString(snapshot.who) +
" " + what;
1094 QListWidgetItem* item =
new QListWidgetItem(QIcon(swatch), text,
ui.lvLabels);
1095 item->setData(Qt::UserRole,
static_cast<qulonglong
>(marker.id));
1096 item->setToolTip(text);
1109 for (
const LogMarker& marker : markerRegistry.markers())
1111 if (marker.id !=
id)
1117 const int row =
logTable->getModel()->rowForSeq(marker.seq);
1120 const QModelIndex
index =
logTable->getModel()->index(row, 0);
1121 logTable->scrollTo(
index, QAbstractItemView::PositionAtCenter);
1132 QListWidgetItem* item =
ui.lvLabels->itemAt(pos);
1140 QAction* recolorAction = menu.addAction(tr(
"Change color..."));
1141 QAction* removeAction = menu.addAction(tr(
"Remove label"));
1142 QAction* chosen = menu.exec(
ui.lvLabels->viewport()->mapToGlobal(pos));
1144 if (chosen == removeAction)
1146 markerRegistry.remove(
id);
1148 else if (chosen == recolorAction)
1151 for (
const LogMarker& marker : markerRegistry.markers())
1153 if (marker.id ==
id)
1155 initial = marker.color;
1159 const QColor color =
1160 QColorDialog::getColor(initial,
getWidget(), tr(
"Choose label color"));
1161 if (color.isValid())
1163 markerRegistry.recolor(
id, color);
1171 QListWidgetItem* item =
ui.lvLabels->currentItem();
1177 markerRegistry.remove(
id);
1184 if (
getState() >= eManagedIceObjectExiting)
1189 std::vector<LogMessage> pendingEntriesTemp;
1191 std::unique_lock lock(pendingEntriesMutex);
1192 if (pendingEntries.size() <= maxEntriesPerTick)
1194 pendingEntriesTemp.swap(pendingEntries);
1200 const auto batchEnd = pendingEntries.begin() + maxEntriesPerTick;
1201 pendingEntriesTemp.assign(std::make_move_iterator(pendingEntries.begin()),
1202 std::make_move_iterator(batchEnd));
1203 pendingEntries.erase(pendingEntries.begin(), batchEnd);
1213 std::vector<LogSeq> wholeBatch;
1214 wholeBatch.reserve(pendingEntriesTemp.size());
1215 QHash<LogTable*, std::vector<LogSeq>> autoBuckets;
1219 for (LogMessage& msg : pendingEntriesTemp)
1222 if (msg.what.find(
'\033') != std::string::npos)
1224 msg.what = boost::regex_replace(msg.what, re,
"");
1229 const LogSeq seq = store.append(msg);
1230 wholeBatch.push_back(seq);
1237 const QString group = QString::fromStdString(msg.group);
1238 const QString
component = QString::fromStdString(msg.who);
1242 const bool mayCreate =
ui.cbVerbosityLevel->currentIndex() <= msg.type;
1244 const QString groupKey = autoFilterId(group, QString());
1245 const QString componentKey = autoFilterId(group,
component);
1247 if (
LogTable* groupTable = ensureAutoFilter(groupKey, group, QString(), mayCreate))
1249 autoBuckets[groupTable].push_back(seq);
1251 if (componentKey != groupKey)
1254 ensureAutoFilter(componentKey, group,
component, mayCreate))
1256 autoBuckets[componentTable].push_back(seq);
1263 const bool autoScroll =
1265 logTable->verticalScrollBar()->value() ==
logTable->verticalScrollBar()->maximum();
1267 for (
LogTable* log : generalFilters)
1269 ingestBatch(log, wholeBatch);
1271 for (
auto it = autoBuckets.begin(); it != autoBuckets.end(); ++it)
1273 ingestBatch(it.key(), it.value());
1288 const LogSeq firstSeq = store.firstSeq();
1289 for (
auto& filterEntry : filterMap)
1291 filterEntry.second->getModel()->dropRowsBefore(firstSeq);
1294 expireOrphanedMarkers();
1303 ui.edtLiveSearch->show();
1304 ui.btnPreviousItem->show();
1305 ui.btnNextItem->show();
1306 ui.edtLiveFilter->hide();
1310 ui.edtLiveSearch->hide();
1311 ui.btnPreviousItem->hide();
1312 ui.btnNextItem->hide();
1313 ui.edtLiveFilter->show();
1323 if (!
logTable->selectNextSearchResult(
false))
1326 "Could not find '" +
logTable->getModel()->getCurrentSearchStr() +
1337 if (!
logTable->selectNextSearchResult(
true))
1340 "Could not find '" +
logTable->getModel()->getCurrentSearchStr() +
1351 if (parent != customToolbar->parent())
1353 customToolbar->setParent(parent);
1356 return customToolbar;
1359 customToolbar =
new QToolBar(parent);
1360 customToolbar->setIconSize(QSize(16, 16));
1361 customToolbar->addAction(
1364 return customToolbar;
#define ARMARX_LOG_VERBOSITYSTR
#define ARMARX_LOG_COMPONENTSTR
#define ARMARX_LOG_FILESTR
#define ARMARX_LOG_TAGSTR
#define ARMARX_LOG_MESSAGESTR
#define ARMARX_LOG_LOGGINGGROUPSTR
#define ARMARX_LOG_FUNCTIONSTR
#define USERROLE_BASENAME
#define ALL_MESSAGES_FILTER
#define USERROLE_LOGTABLEID
bool expireBefore(LogSeq firstSeq)
Remove every marker whose line has been dropped from the store, i.e.
LogMarkerId markerIdForSeq(LogSeq seq) const
Id of the marker pinning seq, or 0 if it is not pinned.
void add(LogSeq seq)
Pin the store entry seq, assigning it the next Glasbey color.
void remove(LogMarkerId id)
Remove the marker with the given id (no-op if unknown).
static std::string levelToString(MessageTypeT type)
LogSeq firstSeq() const
Sequence number of the oldest retained entry.
void setMarkerRegistry(LogMarkerRegistry *registry)
Attach the shared pin registry.
void addFilter(const std::string &columnName, const std::string &filter, MatchMode mode=MatchMode::Contains)
void setStore(const LogStore *store)
Attach the shared backing store. Must be called before any ingestion.
MessageType getMaxNewLogLevelType()
LogTableModel * getModel()
void removeLabelRequested(LogSeq seq)
Emitted from the context menu to remove the pin on the given line.
void addLabelRequested(LogSeq seq)
Emitted from the context menu to pin the given line (assign a label).
void pauseLogging(bool pause=false)
void componentConnected()
void selectPreviousSearchResult()
void onInitComponent() override
Pure virtual hook for the subclass.
void editFilter(QTreeWidgetItem *item, int column)
void insertPendingEntries()
bool onClose() override
If you overwrite this method, make sure to call this implementation at the end of your implementation...
void removeSelectedLabel()
Remove the pin currently selected in the Labels panel.
void refreshLabelsPanel()
Rebuild the Labels panel from the pin registry.
QPointer< QWidget > getCustomTitlebarWidget(QWidget *parent) override
getTitleToolbar returns a pointer to the a toolbar widget of this controller.
void selectNextSearchResult()
void removeSelectedFilter()
LogTable * addEmptyFilter()
void removeFilter(QTreeWidgetItem *item)
void loadSettings(QSettings *settings) override
Implement to load the settings that are part of the GUI configuration.
void saveSettings(QSettings *settings) override
Implement to save the settings as part of the GUI configuration.
void updateFilterListSignal()
void performLiveSearch(QString searchStr)
void OpenConfigureDialog()
void onConnectComponent() override
Pure virtual hook for the subclass.
void write(const std::string &who, Ice::Long time, const std::string &tag, MessageType severity, const std::string &message, const std::string &file, Ice::Int line, const std::string &function, const Ice::Current &=Ice::emptyCurrent)
void filterSelectionChanged(QTreeWidgetItem *item, QTreeWidgetItem *previous)
bool checkAndAddNewFilter(const QString &loggingGroupName, const QString &componentName)
This function checks, if there are new components in the log and if so, it creates new filters for th...
void onExitComponent() override
Hook for subclass.
void writeLog(const LogMessage &msg, const Ice::Current &=Ice::emptyCurrent) override
void performLiveFilter(QString searchStr, int startRow=0)
void labelClicked(QListWidgetItem *item)
Focus the clicked label's line in the currently shown message view.
void showLabelsContextMenu(const QPoint &pos)
Recolor / remove menu for the Labels panel.
void searchTypeChanged(int index)
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
int getState() const
Retrieve current state of the ManagedIceObject.
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::uint64_t LogMarkerId
quint64 LogSeq
Identifies a stored log entry for as long as it is retained.
const LogSender::manipulator flush
A single pinned log line: the store entry it refers to plus the color assigned to it.