File indexing completed on 2024-05-05 05:48:58
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 "processOutputLogFileReader.h" 0008 0009 #include <QStringList> 0010 #include <QTimer> 0011 0012 #include <KLocalizedString> 0013 0014 #include "logFileReaderPrivate.h" 0015 0016 #include "ksystemlog_debug.h" 0017 0018 class ProcessOutputLogFileReaderPrivate : public LogFileReaderPrivate 0019 { 0020 public: 0021 long mPreviousLinesCount; 0022 0023 QTimer mProcessUpdater; 0024 0025 QProcess *mProcess = nullptr; 0026 0027 QString mBuffer; 0028 QStringList mAvailableStandardOutput; 0029 }; 0030 0031 ProcessOutputLogFileReader::ProcessOutputLogFileReader(const LogFile &logFile) 0032 : LogFileReader(*new ProcessOutputLogFileReaderPrivate(), logFile) 0033 { 0034 init(); 0035 } 0036 0037 ProcessOutputLogFileReader::ProcessOutputLogFileReader(ProcessOutputLogFileReaderPrivate &dd, const LogFile &logFile) 0038 : LogFileReader(dd, logFile) 0039 { 0040 init(); 0041 } 0042 0043 ProcessOutputLogFileReader::~ProcessOutputLogFileReader() 0044 { 0045 // d pointer is deleted by the parent class 0046 } 0047 0048 void ProcessOutputLogFileReader::init() 0049 { 0050 Q_D(ProcessOutputLogFileReader); 0051 0052 // Init current file position 0053 d->mPreviousLinesCount = 0; 0054 d->mAvailableStandardOutput.clear(); 0055 d->mProcess = nullptr; 0056 0057 d->mProcessUpdater.setInterval(PROCESS_OUTPUT_UPDATER_INTERVAL); 0058 connect(&(d->mProcessUpdater), &QTimer::timeout, this, &ProcessOutputLogFileReader::startProcess); 0059 0060 qCDebug(KSYSTEMLOG) << "Using process name " << d->logFile.url().toLocalFile(); 0061 } 0062 0063 void ProcessOutputLogFileReader::watchFile(bool enable) 0064 { 0065 Q_D(ProcessOutputLogFileReader); 0066 0067 if (enable) { 0068 qCDebug(KSYSTEMLOG) << "Monitoring process : " << d->logFile.url().toLocalFile(); 0069 0070 // Reinit current file position 0071 d->mPreviousLinesCount = 0; 0072 0073 // Launch the timer 0074 d->mProcessUpdater.start(); 0075 0076 // Launch immediately the process updater 0077 startProcess(); 0078 } else { 0079 // Stop regularly start process 0080 d->mProcessUpdater.stop(); 0081 } 0082 } 0083 0084 void ProcessOutputLogFileReader::startProcess() 0085 { 0086 qCDebug(KSYSTEMLOG) << "Starting process..."; 0087 0088 Q_D(ProcessOutputLogFileReader); 0089 0090 if (!d->logFile.url().isValid()) { 0091 const QString message(i18n("This file is not valid. Please adjust it in the settings of KSystemLog.")); 0092 Q_EMIT errorOccured(i18n("File Does Not Exist"), message); 0093 Q_EMIT statusBarChanged(message); 0094 } 0095 0096 qCDebug(KSYSTEMLOG) << "Starting process..."; 0097 0098 d->mProcess = new QProcess(); 0099 connect(d->mProcess, &QProcess::readyReadStandardOutput, this, &ProcessOutputLogFileReader::logFileModified); 0100 connect(d->mProcess, &QProcess::finished, this, &ProcessOutputLogFileReader::emitProcessOutput); 0101 0102 d->mProcess->start(d->logFile.url().toLocalFile(), QStringList(), QIODevice::ReadOnly | QIODevice::Text); 0103 0104 d->mProcess->waitForStarted(); 0105 0106 qCDebug(KSYSTEMLOG) << "Process started"; 0107 } 0108 0109 void ProcessOutputLogFileReader::closeProcess() 0110 { 0111 qCDebug(KSYSTEMLOG) << "Closing process..."; 0112 0113 Q_D(ProcessOutputLogFileReader); 0114 0115 // Get the size file for the next calculation 0116 d->mPreviousLinesCount = d->mAvailableStandardOutput.count(); 0117 qCDebug(KSYSTEMLOG) << "New lines count : " << d->mPreviousLinesCount << " (" << d->logFile.url().toLocalFile() << ")"; 0118 0119 d->mAvailableStandardOutput.clear(); 0120 0121 if (d->mProcess) { 0122 d->mProcess->close(); 0123 delete d->mProcess; 0124 d->mProcess = nullptr; 0125 } 0126 0127 qCDebug(KSYSTEMLOG) << "Process closed"; 0128 } 0129 0130 void ProcessOutputLogFileReader::emitProcessOutput(int /*exitCode*/, QProcess::ExitStatus exitStatus) 0131 { 0132 Q_D(ProcessOutputLogFileReader); 0133 0134 // First commit last lines of the buffer to the line list 0135 emptyBuffer(); 0136 0137 qCDebug(KSYSTEMLOG) << "Process terminated" << d->mPreviousLinesCount << "previously /" << d->mAvailableStandardOutput.count() << "currently"; 0138 0139 if (exitStatus == QProcess::CrashExit) { 0140 QString const message(i18n("The process '%1' crashed.", d->logFile.url().toLocalFile())); 0141 Q_EMIT errorOccured(i18n("Process Crashed"), message); 0142 Q_EMIT statusBarChanged(message); 0143 } 0144 0145 // If there is no new lines 0146 if (d->mPreviousLinesCount == d->mAvailableStandardOutput.count()) { 0147 /* 0148 //Q_EMIT an empty log lines list 0149 Q_EMIT contentChanged(this, false, QStringList()); 0150 */ 0151 } 0152 // If there are new lines in the file, insert only them or this is the first time we read this file 0153 else if (d->mPreviousLinesCount != 0 && d->mPreviousLinesCount <= d->mAvailableStandardOutput.count()) { 0154 qCDebug(KSYSTEMLOG) << "Reading from line " << d->mPreviousLinesCount << " (" << d->logFile.url().toLocalFile() << ")"; 0155 0156 QStringList newOutputs; 0157 0158 int index = d->mPreviousLinesCount - 1; 0159 while (index < d->mAvailableStandardOutput.count()) { 0160 newOutputs.append(d->mAvailableStandardOutput.at(index)); 0161 0162 ++index; 0163 } 0164 0165 qCDebug(KSYSTEMLOG) << "Retrieving a part of the file..."; 0166 0167 Q_EMIT contentChanged(this, Analyzer::UpdatingRead, newOutputs); 0168 } 0169 // Else reread all lines, clear log list 0170 else { 0171 qCDebug(KSYSTEMLOG) << "New process or process already read. Reading entire content"; 0172 0173 Q_EMIT contentChanged(this, Analyzer::FullRead, d->mAvailableStandardOutput); 0174 } 0175 0176 closeProcess(); 0177 } 0178 0179 void ProcessOutputLogFileReader::logFileModified() 0180 { 0181 Q_D(ProcessOutputLogFileReader); 0182 0183 qCDebug(KSYSTEMLOG) << "Content available on process output..."; 0184 0185 // New added lines 0186 QByteArray const bytesOutput = d->mProcess->readAllStandardOutput(); 0187 d->mBuffer.append(QLatin1String(bytesOutput)); 0188 0189 // Parse buffer 0190 int endLinePos = d->mBuffer.indexOf(QLatin1String("\n")); 0191 while (true) { 0192 if (endLinePos == -1) { 0193 break; 0194 } 0195 0196 // Add the new found lines and 0197 d->mAvailableStandardOutput.append(d->mBuffer.left(endLinePos)); 0198 d->mBuffer.remove(0, endLinePos + 1); 0199 0200 endLinePos = d->mBuffer.indexOf(QLatin1String("\n")); 0201 } 0202 0203 qCDebug(KSYSTEMLOG) << "Received a total of" << d->mAvailableStandardOutput.count() << "new lines"; 0204 } 0205 0206 /** 0207 * The buffer could contains some last characters that are added at last 0208 * (Normally useless) 0209 */ 0210 void ProcessOutputLogFileReader::emptyBuffer() 0211 { 0212 Q_D(ProcessOutputLogFileReader); 0213 0214 if (!d->mBuffer.isEmpty()) { 0215 qCWarning(KSYSTEMLOG) << "Buffer was not empty !!"; 0216 d->mAvailableStandardOutput.append(d->mBuffer); 0217 d->mBuffer.clear(); 0218 } 0219 } 0220 0221 #include "moc_processOutputLogFileReader.cpp"