LogViewer.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 ArmarX::
17* @author Mirko Waechter ( mirko.waechter at kit dot edu)
18* @date 2012
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 <mutex>
27
28#include <QHash>
29#include <QPointer>
30#include <QToolBar>
31
33
34#include <ArmarXGui/gui-plugins/LoggingPlugin/ui_LogViewer.h>
36
37#include "LogMarkerRegistry.h"
38#include "LogStore.h"
39#include "LogTable.h"
40
41class QTimer;
42
43namespace armarx
44{
45
46 class LogTableModel;
47
48 /*!
49 \page ArmarXGui-GuiPlugins-LogViewer LogViewer
50 \brief The log viewer allows you to filter and view log messages from
51 all running ArmarX applications.
52 \image html LogViewer.png
53 ArmarXGui Documentation \ref LogViewer
54 \see LoggingPlugin
55 */
56 /*!
57 \class LogViewer
58 \see LoggingPlugin
59 */
62 public Log
63 {
64 Q_OBJECT
65 public:
66 LogViewer();
67 ~LogViewer() override;
68 //inherited from ArmarXMdiWidget
69
70 void loadSettings(QSettings* settings) override;
71 void saveSettings(QSettings* settings) override;
72
73 static QString
75 {
76 return "Meta.LogViewer";
77 }
78
79 static QIcon
81 {
82 return QIcon("://icons/papyrus.svg");
83 }
84
85 static QIcon
87 {
88 return QIcon("://icons/papyrus.svg");
89 }
90
91 QPointer<QWidget> getCustomTitlebarWidget(QWidget* parent) override;
92
93 // inherited from Component
94 void onInitComponent() override;
95 void onConnectComponent() override;
96 void onExitComponent() override;
97
98 // inherited from Log
99 void write(const std::string& who,
100 Ice::Long time,
101 const std::string& tag,
102 MessageType severity,
103 const std::string& message,
104 const std::string& file,
105 Ice::Int line,
106 const std::string& function,
107 const Ice::Current& = Ice::emptyCurrent);
108 void writeLog(const LogMessage& msg, const Ice::Current& = Ice::emptyCurrent) override;
109
110
111 LogTable* addEmptyFilter();
112 LogTable* addFilter(QString filterId,
113 QString filterName,
114 QString loggingGroup,
115 QString componentFilter,
116 QString tagFilter,
117 MessageType minimumVerbosity,
118 QString messageFilter,
119 QString fileFilter,
120 QString functionFilter);
121 //! This function checks, if there are new components in the log and if so, it creates new filters for these components
122 bool checkAndAddNewFilter(const QString& loggingGroupName, const QString& componentName);
123
124
125 public slots:
126 void performLiveFilter(QString searchStr, int startRow = 0);
127 void performLiveSearch(QString searchStr);
128 void clearSelectedLog();
129 void clearAllLogs();
130 void pauseLogging(bool pause = false);
131 void addFilter();
132 void editFilter(QTreeWidgetItem* item, int column);
133 void removeSelectedFilter();
134 void removeFilter(QTreeWidgetItem* item);
135 void filterSelectionChanged(QTreeWidgetItem* item, QTreeWidgetItem* previous);
136 void insertPendingEntries();
137 void searchTypeChanged(int index);
138 void selectNextSearchResult();
139 void selectPreviousSearchResult();
140 void updateFilterList();
141 void OpenConfigureDialog();
142 //! Rebuild the Labels panel from the pin registry.
143 void refreshLabelsPanel();
144 //! Focus the clicked label's line in the currently shown message view.
145 void labelClicked(QListWidgetItem* item);
146 //! Recolor / remove menu for the Labels panel.
147 void showLabelsContextMenu(const QPoint& pos);
148 //! Remove the pin currently selected in the Labels panel.
149 void removeSelectedLabel();
150 signals:
153
154 protected:
155 bool onClose() override;
156
157 Ui_LogViewer ui;
159
160 private:
161 QString loggingGroupNameToFilterName(const QString& loggingGroupName) const;
162
163 //! Sort the filter tree by name. Called when the filter set changes; the tree's own
164 //! sorting stays disabled so that badge updates do not re-sort it.
165 void sortFilterList();
166
167 //! Id of the auto-generated filter for this group/component pair. This doubles as
168 //! the routing key, because the id is a pure function of (group, component).
169 QString autoFilterId(const QString& loggingGroupName, const QString& componentName) const;
170
171 //! Look up the auto-generated filter with this id, creating it if it does not exist
172 //! yet and \p mayCreate allows it. Returns nullptr when there is no such filter.
173 LogTable* ensureAutoFilter(const QString& filterId,
174 const QString& loggingGroupName,
175 const QString& componentName,
176 bool mayCreate);
177
178 //! Hand a batch to one table and re-apply that table's live filter to the new rows.
179 void ingestBatch(LogTable* table, const std::vector<LogSeq>& seqs);
180
181 //! Common wiring for every freshly created LogTable: share the pin registry with its
182 //! model (so pins created anywhere show up in this filter too).
183 void setupLogTable(LogTable* logTable);
184
185 //! Drop pins whose source line is no longer a native row in any filter (i.e. it has
186 //! been cleared or trimmed everywhere), so pins stay bound to the live log.
187 void expireOrphanedMarkers();
188
189 //! Upper bound on retained log lines. The store is shared by every filter, so this
190 //! is the viewer's total history rather than a per-filter budget. It is larger than
191 //! a single table's display window so that a quiet filter can still fill its own
192 //! window from history a busy one has long scrolled past.
193 static constexpr std::size_t maxStoredEntries = 10000000;
194
195 //! The single backing buffer for every retained log line. Filters hold sequence
196 //! numbers into this, so a message accepted by several filters is stored once.
197 LogStore store{maxStoredEntries};
198
199 //! Session-only registry of pinned ("labeled") log lines, shared with every model.
200 LogMarkerRegistry markerRegistry;
201
202 // Accessed from Ice dispatch threads (writeLog) as well as the GUI thread.
203 std::atomic<bool> loggingPaused;
204 // Mirror of ui.cbVerbosityLevel->currentIndex(), kept in sync from the GUI thread
205 // so the Ice-thread writeLog does not have to touch the (GUI-only) QComboBox.
206 std::atomic<int> verbosityLevel;
207 LogPrx logProxy;
208 IceUtil::Time lastLiveSearchEditChangeTime;
209 std::map<QString, LogTable*> filterMap;
210
211 //! The auto-generated per-group / per-(group, component) filters, keyed by their
212 //! filter id. Because that id is exactly autoFilterId(group, component), a message
213 //! can be routed to the (at most two) filters that can accept it with two hash
214 //! lookups, instead of being tested against every filter in filterMap.
215 QHash<QString, LogTable*> autoFilterMap;
216 //! Filters that cannot be routed on -- "All Messages", "Warning+" and user-created
217 //! filters. Every message is offered to each of these. Routing only narrows the
218 //! candidate set; each model still applies its own filters, so a stale routing
219 //! entry can never let a message into a table that does not accept it.
220 std::vector<LogTable*> generalFilters;
221
222 std::vector<LogMessage> pendingEntries;
223
224 //! Hard bound on the staging queue. Beyond this, writeLog drops messages instead
225 //! of letting an overloaded GUI thread grow the backlog without limit. At the
226 //! drain rate below this is well over a second of backlog.
227 static constexpr std::size_t maxPendingEntries = 50000;
228 //! Upper bound on how many messages a single timer tick ingests; the remainder is
229 //! carried over, so one burst cannot stall the GUI thread arbitrarily long.
230 static constexpr std::size_t maxEntriesPerTick = 2000;
231
232 //! Incremented from the Ice dispatch thread whenever a message is dropped because
233 //! pendingEntries is saturated.
234 std::atomic<unsigned long long> droppedEntryCount{0};
235 //! Last value of droppedEntryCount reported to the status bar.
236 unsigned long long lastReportedDropCount = 0;
237
238 //! What refreshFilterBadges() last rendered for a filter, so untouched items can be
239 //! skipped (every setText() on the tree costs a relayout and repaint).
240 struct FilterBadge
241 {
242 int count = -1;
243 MessageType level = eUNDEFINED;
244 };
245
246 std::map<QString, FilterBadge> filterBadgeCache;
247
248 mutable std::mutex pendingEntriesMutex;
249 QTimer* pendingEntriesTimer;
250 QTimer* filterBadgeTimer;
251 QToolBar* customToolbar;
252 };
253} // namespace armarx
uint8_t index
#define ARMARXCOMPONENT_IMPORT_EXPORT
Shared, session-only store of pinned ("labeled") log lines.
The single bounded buffer holding every log line the viewer retains.
Definition LogStore.h:63
A filtered view onto the shared LogStore.
LogTable * logTable
Definition LogViewer.h:158
void componentConnected()
bool onClose() override
If you overwrite this method, make sure to call this implementation at the end of your implementation...
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()
Ui_LogViewer ui
Definition LogViewer.h:157
static QIcon GetWidgetCategoryIcon()
Definition LogViewer.h:86
static QString GetWidgetName()
Definition LogViewer.h:74
static QIcon GetWidgetIcon()
Definition LogViewer.h:80
This file offers overloads of toIce() and fromIce() functions for STL container types.
::IceInternal::ProxyHandle<::IceProxy::armarx::Log > LogPrx
Definition LogSender.h:58