File indexing completed on 2024-05-19 05:49:12
0001 #include <QElapsedTimer> 0002 #include <QRegularExpression> 0003 0004 #include <KLocalizedString> 0005 0006 #include "ksystemlogConfig.h" 0007 #include "ksystemlog_debug.h" 0008 0009 #include "logViewModel.h" 0010 0011 #include "auditAnalyzer.h" 0012 #include "localLogFileReader.h" 0013 0014 AuditAnalyzer::AuditAnalyzer(LogMode *logMode) 0015 : FileAnalyzer(logMode) 0016 { 0017 } 0018 0019 LogViewColumns AuditAnalyzer::initColumns() 0020 { 0021 LogViewColumns columns; 0022 columns.addColumn(LogViewColumn(i18n("Date"), true, false)); 0023 columns.addColumn(LogViewColumn(i18n("Message"), true, false)); 0024 0025 return columns; 0026 } 0027 0028 void AuditAnalyzer::setLogFiles(const QVector<LogFile> &logFiles) 0029 { 0030 // Remove previous files 0031 deleteLogFiles(); 0032 0033 for (const LogFile &logFile : logFiles) { 0034 LogFileReader *logFileReader = createLogFileReader(logFile); 0035 mLogFileReaders.append(logFileReader); 0036 0037 connect(logFileReader, &LogFileReader::contentChanged, this, &AuditAnalyzer::logFileChanged); 0038 connect(logFileReader, &LogFileReader::statusBarChanged, this, &Analyzer::statusBarChanged); 0039 connect(logFileReader, &LogFileReader::errorOccured, this, &Analyzer::errorOccured); 0040 } 0041 } 0042 0043 LogFileReader *AuditAnalyzer::createLogFileReader(const LogFile &logFile) 0044 { 0045 return new LocalLogFileReader(logFile); 0046 } 0047 0048 Analyzer::LogFileSortMode AuditAnalyzer::logFileSortMode() 0049 { 0050 return Analyzer::AscendingSortedLogFile; 0051 } 0052 0053 LogLine *AuditAnalyzer::parseMessage(const QString &logLine, const LogFile &originalFile) 0054 { 0055 if (logLine.length() < 15) { 0056 return nullptr; 0057 } 0058 0059 static QRegularExpression re(QStringLiteral("^type=(.*)\\s.*msg=audit\\((\\d*\\.\\d*).*")); 0060 QRegularExpressionMatch match = re.match(logLine); 0061 0062 if (!match.hasMatch()) { 0063 return nullptr; 0064 } 0065 0066 const QString messageType = match.captured(1); 0067 0068 const qint64 msecs = qint64(match.captured(2).toDouble() * 1000.); 0069 0070 const QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(msecs); 0071 0072 QString message(logLine); 0073 re.setPattern(QStringLiteral("^type=.*\\):\\s")); 0074 message.remove(re); 0075 0076 QStringList list; 0077 list.append(messageType); 0078 list.append(message); 0079 0080 return new LogLine(mLogLineInternalIdGenerator++, dateTime, list, originalFile.url().path(), originalFile.defaultLogLevel(), mLogMode); 0081 } 0082 0083 void AuditAnalyzer::deleteLogFiles() 0084 { 0085 watchLogFiles(false); 0086 0087 // Remove the watching on the monitored files 0088 qDeleteAll(mLogFileReaders); 0089 mLogFileReaders.clear(); 0090 } 0091 0092 int AuditAnalyzer::insertLines(const QStringList &bufferedLines, const LogFile &logFile, ReadingMode readingMode) 0093 { 0094 qCDebug(KSYSTEMLOG) << "Inserting lines..."; 0095 0096 // If there is no line 0097 if (bufferedLines.isEmpty()) { 0098 qCWarning(KSYSTEMLOG) << "File is empty : " << logFile.url().path(); 0099 } 0100 0101 int stop = 0; 0102 int currentPosition = 0; 0103 0104 QList<QStringList> eventLines; 0105 QStringList event; 0106 QString msgField; 0107 QString curMsgField; 0108 0109 for (const auto &line : bufferedLines) { 0110 msgField = getMsgField(line); 0111 0112 if (msgField != curMsgField) { 0113 eventLines.append(event); 0114 curMsgField = msgField; 0115 event.clear(); 0116 } 0117 0118 event.push_front(line); 0119 } 0120 0121 eventLines.append(event); 0122 0123 QListIterator<QStringList> it(eventLines); 0124 /** 0125 * If the log file is sorted, then we can ignore the first lines 0126 * if there are more lines in the log file than the max lines 0127 * 0128 * TODO Read revertly the file and ignore last lines if we are in Descending mode 0129 */ 0130 qCDebug(KSYSTEMLOG) << "Log file Sort mode is " << logFileSortMode(); 0131 if (logFileSortMode() == Analyzer::AscendingSortedLogFile) { 0132 // Calculate how many lines we will ignore 0133 if (eventLines.size() > KSystemLogConfig::maxLines()) { 0134 stop = eventLines.size() - KSystemLogConfig::maxLines(); 0135 } 0136 0137 // Ignore those lines 0138 while (currentPosition < stop) { 0139 it.next(); 0140 ++currentPosition; 0141 } 0142 } 0143 0144 int insertedLogLineCount = 0; 0145 0146 while (currentPosition < eventLines.size()) { 0147 if (insertLine(it.next(), logFile, readingMode)) { 0148 insertedLogLineCount++; 0149 } 0150 0151 if (readingMode == Analyzer::FullRead) { 0152 informOpeningProgress(currentPosition, (eventLines.size() - 1) - stop); 0153 } 0154 0155 ++currentPosition; 0156 } 0157 0158 return insertedLogLineCount; 0159 } 0160 0161 bool AuditAnalyzer::insertLine(const QStringList &event, const LogFile &originalFile, ReadingMode readingMode) 0162 { 0163 LogLine *line = parseEvent(event, originalFile); 0164 0165 // Invalid log line 0166 if (!line) { 0167 return false; 0168 } 0169 0170 // On full reading, it is not needed to display the recent status 0171 if (readingMode == Analyzer::FullRead) { 0172 line->setRecent(false); 0173 } 0174 0175 return mLogViewModel->insertNewLogLine(line); 0176 } 0177 0178 void AuditAnalyzer::logFileChanged(LogFileReader *logFileReader, ReadingMode readingMode, const QStringList &content) 0179 { 0180 const QString filePath = logFileReader->logFile().url().path(); 0181 if (readingMode == Analyzer::FullRead) { 0182 qCDebug(KSYSTEMLOG) << "File " << filePath << " has been modified on full read."; 0183 } else { 0184 qCDebug(KSYSTEMLOG) << "File " << filePath << " has been modified on partial read"; 0185 } 0186 0187 if (mParsingPaused == true) { 0188 qCDebug(KSYSTEMLOG) << "Pause enabled. Nothing read."; 0189 return; 0190 } 0191 0192 qCDebug(KSYSTEMLOG) << "Locking file modifications of " << filePath; 0193 mInsertionLocking.lock(); 0194 qCDebug(KSYSTEMLOG) << "Unlocking file modifications of " << filePath; 0195 0196 QElapsedTimer benchmark; 0197 benchmark.start(); 0198 0199 int insertedLogLineCount; 0200 0201 mLogViewModel->startingMultipleInsertions(); 0202 0203 if (readingMode == Analyzer::UpdatingRead) { 0204 insertedLogLineCount = insertLines(content, logFileReader->logFile(), Analyzer::UpdatingRead); 0205 } else { 0206 qCDebug(KSYSTEMLOG) << "Reading file " << filePath; 0207 0208 Q_EMIT statusBarChanged(i18n("Opening '%1'...", filePath)); 0209 0210 // Inform that we are now reading the "index" file 0211 Q_EMIT readFileStarted(*mLogMode, logFileReader->logFile(), mLogFileReaders.count() - mLogFileReaders.indexOf(logFileReader), mLogFileReaders.count()); 0212 0213 insertedLogLineCount = insertLines(content, logFileReader->logFile(), Analyzer::FullRead); 0214 0215 Q_EMIT statusBarChanged(i18n("Log file '%1' loaded successfully.", filePath)); 0216 } 0217 0218 mLogViewModel->endingMultipleInsertions(readingMode, insertedLogLineCount); 0219 0220 // Inform connected LoadingBar that the reading is now finished 0221 Q_EMIT readEnded(); 0222 0223 // Inform LogManager that new lines have been added 0224 Q_EMIT logUpdated(insertedLogLineCount); 0225 0226 // Inform MainWindow status bar 0227 Q_EMIT statusBarChanged(i18n("Log file '%1' has changed.", filePath)); 0228 0229 qCDebug(KSYSTEMLOG) << "Updating log files in " << benchmark.elapsed() << " ms"; 0230 0231 mInsertionLocking.unlock(); 0232 } 0233 0234 QString AuditAnalyzer::getMsgField(const QString &logLine) 0235 { 0236 static const QRegularExpression re(QStringLiteral("^.*msg=audit\\((\\d*\\.\\d*:\\d*)\\)")); 0237 const QRegularExpressionMatch match = re.match(logLine); 0238 0239 if (!match.hasMatch()) { 0240 return QString(); 0241 } else { 0242 return match.captured(1); 0243 } 0244 } 0245 0246 LogLine *AuditAnalyzer::parseEvent(const QStringList &event, const LogFile &originalFile) 0247 { 0248 if (event.isEmpty()) { 0249 return nullptr; 0250 } 0251 0252 QRegularExpression re(QStringLiteral("^.*msg=audit\\((\\d*\\.\\d*).*")); 0253 QRegularExpressionMatch match = re.match(event.at(0)); 0254 0255 if (!match.hasMatch()) { 0256 return nullptr; 0257 } 0258 0259 const qint64 msecs = qint64(match.captured(1).toDouble() * 1000.); 0260 const QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(msecs); 0261 0262 QStringList messages; 0263 QString message; 0264 0265 for (const auto &msg : event) { 0266 message = m_conv.convertMessage(msg); 0267 re.setPattern(QStringLiteral("^type=")); 0268 message.remove(re); 0269 re.setPattern(QStringLiteral("\\smsg=audit\\(\\d*\\.\\d*:\\d*\\)")); 0270 message.remove(re); 0271 messages.append(message); 0272 } 0273 0274 QStringList list; 0275 list.append(messages.join(QStringLiteral(" \n"))); 0276 0277 return new LogLine(mLogLineInternalIdGenerator++, dateTime, list, originalFile.url().path(), originalFile.defaultLogLevel(), mLogMode); 0278 } 0279 0280 #include "moc_auditAnalyzer.cpp"