QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
LogManager.h
Go to the documentation of this file.
1#pragma once
2
3#include <QtCore/QFuture>
4#include <QtCore/QHash>
5#include <QtCore/QList>
6#include <QtCore/QObject>
7#include <QtCore/QSet>
8#include <QtCore/QString>
9#include <QtCore/QTimer>
10#include <QtQmlIntegration/QtQmlIntegration>
11
12#include "LogEntry.h"
13#include "LogFormatter.h"
14
15class QJSEngine;
16class QQmlEngine;
17class LogModel;
18class LogRemoteSink;
19class LogStore;
21class QGCFileWriter;
22
23class LogManager : public QObject
24{
25 Q_OBJECT
26 QML_ELEMENT
27 QML_SINGLETON
28 Q_MOC_INCLUDE("LogModel.h")
29 Q_MOC_INCLUDE("LogRemoteSink.h")
30 Q_MOC_INCLUDE("LogStore.h")
31 Q_MOC_INCLUDE("LogStoreQueryModel.h")
32 Q_PROPERTY(LogModel* model READ model CONSTANT)
33 Q_PROPERTY(LogRemoteSink* remoteSink READ remoteSink CONSTANT)
34 Q_PROPERTY(LogStore* logStore READ logStore CONSTANT)
35 Q_PROPERTY(LogStoreQueryModel* historyModel READ historyModel CONSTANT)
36 Q_PROPERTY(bool hasError READ hasError NOTIFY hasErrorChanged)
37 Q_PROPERTY(QString lastError READ lastError NOTIFY lastErrorChanged)
38 Q_PROPERTY(
39 bool diskLoggingEnabled READ isDiskLoggingEnabled WRITE setDiskLoggingEnabled NOTIFY diskLoggingEnabledChanged)
40 Q_PROPERTY(bool diskCompressionEnabled READ isDiskCompressionEnabled WRITE setDiskCompressionEnabled NOTIFY
42 Q_PROPERTY(int flushOnLevel READ flushOnLevel WRITE setFlushOnLevel NOTIFY flushOnLevelChanged)
43
44public:
45 enum ExportFormat
46 {
47 PlainText = LogFormatter::PlainText,
48 JSON = LogFormatter::JSON,
50 JSONLines = LogFormatter::JSONLines,
51 };
52 Q_ENUM(ExportFormat)
53
55
56 static LogManager* instance();
57 static LogManager* create(QQmlEngine* qmlEngine, QJSEngine* jsEngine);
58 static void installHandler();
59 static void applyEnvironmentLogLevel();
60
61 [[nodiscard]] LogModel* model() { return _model; }
62
63 [[nodiscard]] LogRemoteSink* remoteSink() { return _remoteSink; }
64
65 [[nodiscard]] LogStore* logStore() { return _logStore; }
66
67 [[nodiscard]] LogStoreQueryModel* historyModel() { return _historyModel; }
68
69 [[nodiscard]] bool hasError() const { return _ioError; }
70
71 [[nodiscard]] QString lastError() const { return _lastError; }
72
73 void setLogDirectory(const QString& path);
74
75 [[nodiscard]] QString logDirectory() const { return _logDirectory; }
76
77 [[nodiscard]] bool isDiskLoggingEnabled() const { return _diskLoggingEnabled; }
78
79 void setDiskLoggingEnabled(bool enabled);
80
81 [[nodiscard]] bool isDiskCompressionEnabled() const { return _diskCompressionEnabled; }
82
83 void setDiskCompressionEnabled(bool enabled);
84
85 [[nodiscard]] int flushOnLevel() const { return _flushOnLevel; }
86
87 void setFlushOnLevel(int level);
88
89 Q_INVOKABLE void writeMessages(const QString& destFile, ExportFormat format = PlainText);
90 Q_INVOKABLE void writeFilteredMessages(const QString& destFile, ExportFormat format = PlainText);
91 Q_INVOKABLE void clearError();
92 Q_INVOKABLE void flush();
93
94 Q_INVOKABLE static QStringList categoryLogLevelNames();
95 Q_INVOKABLE static QVariantList categoryLogLevelValues();
96
97 static void setCaptureEnabled(bool enabled);
98 static void clearCapturedMessages();
99 [[nodiscard]] static QList<LogEntry> capturedMessages(const QString& category = {});
100 [[nodiscard]] static bool hasCapturedMessage(const QString& category, LogEntry::Level level);
101 [[nodiscard]] static bool hasCapturedWarning(const QString& category);
102 [[nodiscard]] static bool hasCapturedCritical(const QString& category);
103 [[nodiscard]] static bool hasCapturedUncategorizedMessage();
104 static void captureIfEnabled(QtMsgType type, const QMessageLogContext& context, const QString& msg);
105
106signals:
113 void writeFinished(bool success);
114
115private slots:
116 void _handleEntry(const LogEntry& entry);
117 void _flushToDisk();
118
119private:
120 explicit LogManager(QObject* parent = nullptr);
121
122 static void msgHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
123 void log(QtMsgType type, const QMessageLogContext& context, const QString& message);
124 static LogEntry buildEntry(QtMsgType type, const QMessageLogContext& context, const QString& message);
125
126 void _dispatchToSinks(const LogEntry& entry);
127 void _rotateLogs();
128 void _setIoError(const QString& message);
129 void _exportEntries(QList<LogEntry> entries, const QString& destFile, ExportFormat format);
130 const QString& _internCategory(const QString& category);
131
132 LogModel* _model = nullptr;
133 LogRemoteSink* _remoteSink = nullptr;
134 LogStore* _logStore = nullptr;
135 LogStoreQueryModel* _historyModel = nullptr;
136 QGCFileWriter* _fileWriter = nullptr;
137
138 struct RateBucket
139 {
140 qint64 lastRefillMs = 0;
141 int tokens = 0;
142 int suppressed = 0;
143 };
144
145 bool _rateLimitCheck(const LogEntry& entry);
146 void _emitSuppressedSummary(const QString& category, int count);
147
148 QFuture<void> _exportFuture;
149 QTimer _flushTimer;
150 QList<LogEntry> _pendingDiskWrites;
151 QSet<QString> _internedCategories;
152 QHash<QString, RateBucket> _rateBuckets;
153 QString _logDirectory;
154 bool _ioError = false;
155 QString _lastError;
156 bool _diskLoggingEnabled = false;
157 bool _diskCompressionEnabled = false;
158 int _flushOnLevel = LogEntry::Warning;
159
160 static constexpr int kMaxLogFileSize = 10 * 1024 * 1024;
161 static constexpr int kMaxBackupFiles = 5;
162 static constexpr int kFlushIntervalMSecs = 1000;
163 static constexpr int kRateTokensPerSecond = 100;
164 static constexpr int kRateMaxTokens = 200;
165};
void writeStarted()
void lastErrorChanged()
void writeFinished(bool success)
void flushOnLevelChanged()
void hasErrorChanged()
void diskLoggingEnabledChanged()
void diskCompressionEnabledChanged()