File indexing completed on 2024-05-05 05:48:56
0001 /* 0002 SPDX-FileCopyrightText: 2007 Nicolas Ternisien <nicolas.ternisien@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "fileAnalyzer.h" 0008 0009 #include <KLocalizedString> 0010 #include <QElapsedTimer> 0011 0012 #include "ksystemlogConfig.h" 0013 #include "ksystemlog_debug.h" 0014 0015 #include "logViewModel.h" 0016 0017 #include "logFileReader.h" 0018 #include "logMode.h" 0019 0020 FileAnalyzer::FileAnalyzer(LogMode *logMode) 0021 : Analyzer(logMode) 0022 { 0023 } 0024 0025 FileAnalyzer::~FileAnalyzer() 0026 { 0027 deleteLogFiles(); 0028 0029 // logMode is managed by Globals 0030 // logViewModel is managed by LogViewWidget 0031 } 0032 0033 void FileAnalyzer::watchLogFiles(bool enabled) 0034 { 0035 // Enable the log file watching, by revert order to read the most top file at last, and be sure its line 0036 // will be kept 0037 0038 QListIterator<LogFileReader *> it(mLogFileReaders); 0039 it.toBack(); 0040 while (it.hasPrevious()) { 0041 LogFileReader *logFileReader = it.previous(); 0042 logFileReader->watchFile(enabled); 0043 } 0044 } 0045 0046 void FileAnalyzer::deleteLogFiles() 0047 { 0048 watchLogFiles(false); 0049 0050 // Remove the watching on the monitored files 0051 qDeleteAll(mLogFileReaders); 0052 mLogFileReaders.clear(); 0053 } 0054 0055 void FileAnalyzer::setLogFiles(const QVector<LogFile> &logFiles) 0056 { 0057 // Remove previous files 0058 deleteLogFiles(); 0059 0060 for (const LogFile &logFile : logFiles) { 0061 LogFileReader *logFileReader = createLogFileReader(logFile); 0062 mLogFileReaders.append(logFileReader); 0063 0064 connect(logFileReader, &LogFileReader::contentChanged, this, &FileAnalyzer::logFileChanged); 0065 connect(logFileReader, &LogFileReader::statusBarChanged, this, &Analyzer::statusBarChanged); 0066 connect(logFileReader, &LogFileReader::errorOccured, this, &Analyzer::errorOccured); 0067 } 0068 } 0069 0070 void FileAnalyzer::logFileChanged(LogFileReader *logFileReader, ReadingMode readingMode, const QStringList &content) 0071 { 0072 const QString filePath = logFileReader->logFile().url().toLocalFile(); 0073 if (readingMode == Analyzer::FullRead) { 0074 qCDebug(KSYSTEMLOG) << "File " << filePath << " has been modified on full read."; 0075 } else { 0076 qCDebug(KSYSTEMLOG) << "File " << filePath << " has been modified on partial read"; 0077 } 0078 0079 if (mParsingPaused) { 0080 qCDebug(KSYSTEMLOG) << "Pause enabled. Nothing read."; 0081 return; 0082 } 0083 0084 qCDebug(KSYSTEMLOG) << "Locking file modifications of " << filePath; 0085 mInsertionLocking.lock(); 0086 qCDebug(KSYSTEMLOG) << "Unlocking file modifications of " << filePath; 0087 0088 QElapsedTimer benchmark; 0089 benchmark.start(); 0090 0091 int insertedLogLineCount; 0092 0093 mLogViewModel->startingMultipleInsertions(); 0094 0095 if (readingMode == Analyzer::UpdatingRead) { 0096 insertedLogLineCount = insertLines(content, logFileReader->logFile(), Analyzer::UpdatingRead); 0097 } else { 0098 qCDebug(KSYSTEMLOG) << "Reading file " << filePath; 0099 0100 Q_EMIT statusBarChanged(i18n("Opening '%1'...", filePath)); 0101 0102 // Inform that we are now reading the "index" file 0103 Q_EMIT readFileStarted(*mLogMode, logFileReader->logFile(), mLogFileReaders.count() - mLogFileReaders.indexOf(logFileReader), mLogFileReaders.count()); 0104 0105 insertedLogLineCount = insertLines(content, logFileReader->logFile(), Analyzer::FullRead); 0106 0107 Q_EMIT statusBarChanged(i18n("Log file '%1' loaded successfully.", filePath)); 0108 } 0109 0110 mLogViewModel->endingMultipleInsertions(readingMode, insertedLogLineCount); 0111 0112 // Inform connected LoadingBar that the reading is now finished 0113 Q_EMIT readEnded(); 0114 0115 // Inform LogManager that new lines have been added 0116 Q_EMIT logUpdated(insertedLogLineCount); 0117 0118 // Inform MainWindow status bar 0119 Q_EMIT statusBarChanged(i18n("Log file '%1' has changed.", filePath)); 0120 0121 qCDebug(KSYSTEMLOG) << "Updating log files in " << benchmark.elapsed() << " ms"; 0122 0123 mInsertionLocking.unlock(); 0124 } 0125 0126 int FileAnalyzer::insertLines(const QStringList &bufferedLines, const LogFile &logFile, ReadingMode readingMode) 0127 { 0128 qCDebug(KSYSTEMLOG) << "Inserting lines..."; 0129 0130 // If there is no line 0131 if (bufferedLines.isEmpty()) { 0132 qCWarning(KSYSTEMLOG) << "File is empty : " << logFile.url().toLocalFile(); 0133 } 0134 0135 int stop = 0; 0136 int currentPosition = 0; 0137 0138 QListIterator<QString> it(bufferedLines); 0139 /** 0140 * If the log file is sorted, then we can ignore the first lines 0141 * if there are more lines in the log file than the max lines 0142 * 0143 * TODO Read revertly the file and ignore last lines if we are in Descending mode 0144 */ 0145 qCDebug(KSYSTEMLOG) << "Log file Sort mode is " << logFileSortMode(); 0146 if (logFileSortMode() == Analyzer::AscendingSortedLogFile) { 0147 // Calculate how many lines we will ignore 0148 if (bufferedLines.size() > KSystemLogConfig::maxLines()) { 0149 stop = bufferedLines.size() - KSystemLogConfig::maxLines(); 0150 } 0151 0152 // Ignore those lines 0153 while (currentPosition < stop) { 0154 it.next(); 0155 ++currentPosition; 0156 } 0157 } 0158 0159 int insertedLogLineCount = 0; 0160 while (currentPosition < bufferedLines.size()) { 0161 const QString buffer(it.next()); 0162 0163 const bool inserted = insertLine(buffer, logFile, readingMode); 0164 if (inserted) { 0165 insertedLogLineCount++; 0166 } 0167 0168 if (readingMode == Analyzer::FullRead) { 0169 informOpeningProgress(currentPosition, (bufferedLines.size() - 1) - stop); 0170 } 0171 0172 ++currentPosition; 0173 } 0174 0175 qCDebug(KSYSTEMLOG) << "Total read lines :" << (bufferedLines.size() - stop) << "(" << logFile.url().toLocalFile() << ")"; 0176 0177 return insertedLogLineCount; 0178 } 0179 0180 bool FileAnalyzer::insertLine(const QString &buffer, const LogFile &originalFile, ReadingMode readingMode) 0181 { 0182 LogLine *line = parseMessage(buffer, originalFile); 0183 0184 // Invalid log line 0185 if (!line) { 0186 return false; 0187 } 0188 0189 // On full reading, it is not needed to display the recent status 0190 if (readingMode == Analyzer::FullRead) { 0191 line->setRecent(false); 0192 } 0193 0194 return mLogViewModel->insertNewLogLine(line); 0195 } 0196 0197 #include "moc_fileAnalyzer.cpp"