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"