diff options
Diffstat (limited to 'ksystemlog/src/defaultReader.cpp')
-rw-r--r-- | ksystemlog/src/defaultReader.cpp | 498 |
1 files changed, 498 insertions, 0 deletions
diff --git a/ksystemlog/src/defaultReader.cpp b/ksystemlog/src/defaultReader.cpp new file mode 100644 index 0000000..e70f5e5 --- /dev/null +++ b/ksystemlog/src/defaultReader.cpp @@ -0,0 +1,498 @@ +/*************************************************************************** + * Copyright (C) 2005 by Nicolas Ternisien * + * nicolas.ternisien@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + + +#include <klocale.h> +#include <kmessagebox.h> + +#include "logListItem.h" +#include "ksystemlogConfig.h" +#include "logLine.h" +#include "view.h" +#include "parsingHelper.h" + +#include "defaultReader.h" + + +DefaultReader::DefaultReader(QObject *parent, const char *name) : + Reader(parent, name), + buffers(NULL) + { + + +} + + +DefaultReader::~DefaultReader() { + delete buffers; +} + +void DefaultReader::readLog() { + //Each file in the Log file list are watched with the following method + watchLogFiles(); + + if (buffers!=NULL) + delete buffers; + + if (logManager->getGroupBy()==NO_GROUP_BY) + buffers=new LogLineList(); + else { + buffers=new LogLineTree(logManager->getColumns(), logManager->getGroupBy(), logManager->getGroupByColumn()); + } + + + LogFiles& files=logManager->getLogFiles(); + + //Inform connected QObject that the reading has begun + emit readingBegin(); + + //Read each file of the list, and place their lines in the buffer + int i=files.count()-1; + LogFile* logFile; + while(i>=0) { + logFile=files[i]; + kdDebug() << "Reading file " << logFile->url.path() << endl; + this->readFile(logFile); + + i--; + } + + //Synchronize the buffer once we have fill it + logManager->synchronize(buffers); + + //Says to the buffer that we have read all files, and that + //the next adding will come from logChanged method + if (!buffers->isEmpty()) + buffers->setFirstReadPerformed(true); + + //Inform connected QObject that the reading is now finished + emit readingEnd(); + + //Emit a signal which informs connected slots that there are new lines + emit logUpdated(logManager->getView()->getLogList()->childCount()); +} + +void DefaultReader::readFile(LogFile* logFile) { + QString message=i18n("Opening file '%1'...").arg(logFile->url.path()); + emit statusbarChanged(message); + + //Inform connected QObject that we are now reading the "index" file + emit readingFile(logManager->getLogFiles().count() - logManager->getLogFiles().findIndex(logFile)); + + + //We initialize these values from configuration to be used by the insert methods + tmpDeleteDuplicate=KSystemLogConfig::deleteDuplicatedLines(); + tmpDeleteProcessId=KSystemLogConfig::deleteProcessIdentifier(); + tmpMaxLines=KSystemLogConfig::maxLines(); + tmpMaxCharacters=KSystemLogConfig::maxReadCharacters(); + + //Open the file + QFile* file=this->openFile(logFile->url.path()); + + //If an error occurs, end this method + if (file==NULL) { + return; + } + + QString buffer; + QString filePath=logFile->url.path(); + + + //Insert the content of the file in a string list + QStringList* rawBuffer=getRawBuffer(file); + + //If there is no line + if (rawBuffer->size()==0) { + QString message=i18n("No log line in '%1'.").arg(logFile->url.path()); + emit statusbarChanged(message); + + delete rawBuffer; + return; + } + + kdDebug() << "Testing each line..." << endl; + + QStringList::iterator it; + it=rawBuffer->end(); + it--; + + //Calculate how many lines we will read + int size=rawBuffer->size(); + int stop; + if (size>tmpMaxLines) + stop=size-tmpMaxLines; + else + stop=0; + + + //Test each line of the raw buffer + int i=size-1; + + int progress=0; + + int progressTotal=size-1 - stop; + int each=progressTotal / 100; + if (each==0) + each=progressTotal; + + + while(i>=stop) { + buffer=*it; + + if (insertOrReplaceLine(buffer, logFile)==false) + break; + + it--; + i--; + + if (i>=0 && i%each==0) { + emit openingProgressed(progress++); + } + } + + delete rawBuffer; + + logFile->lastFileSize=file->size(); + + // Close the file + this->closeFile(file); + + message=i18n("Log file '%1' loaded successfully.").arg(logFile->url.path()); + emit statusbarChanged(message); + +} + + + +void DefaultReader::logChanged(LogFile* logFile) { + kdDebug() << "SortedReader : File has been modified !" << endl; + + //We initialize these values from configuration to be used by the insert methods + tmpDeleteDuplicate=KSystemLogConfig::deleteDuplicatedLines(); + tmpDeleteProcessId=KSystemLogConfig::deleteProcessIdentifier(); + tmpMaxLines=KSystemLogConfig::maxLines(); + tmpMaxCharacters=KSystemLogConfig::maxReadCharacters(); + + QString buffer; + + QString filePath=logFile->url.path(); + QFile* file=this->openFile(filePath); + + if (file==NULL) + return; + + + //If there are new lines in the file, insert only them + if (logFile->lastFileSize <= (int) file->size()) { + //Place the cursor to the last line opened + file->at(logFile->lastFileSize); + + kdDebug() << "Retrieving a part of the file..." << endl; + + //Get the maximum number of line read from LogManager + int maxLines=KSystemLogConfig::maxLines(); + + QString buffer; + QStringList* rawBuffer=getRawBuffer(file); + + //If there is no line + if (rawBuffer->size()==0) { + delete rawBuffer; + return; + } + + kdDebug() << "Testing each line..." << endl; + + QStringList::iterator it; + it=rawBuffer->end(); + it--; + + //Calculate how many lines we will read + int size=rawBuffer->size(); + int stop=0; + if (size>maxLines) + stop=size-maxLines; + + //Test each line of the raw buffer + int i=size-1; + while(i>=stop) { + buffer=*it; + + if (insertOrReplaceLine(buffer, logFile)==false) + break; + + it--; + i--; + } + + kdDebug() << "Total read lines : " << (size-1-i) << endl; + + delete rawBuffer; + + + } + //Else reread all lines, clear log list + else { + buffers->clear(); + + file->close(); + + this->readFile(logFile); + } + + int newLineCount=buffers->getNewLineCount(); + + logManager->synchronize(buffers); + + //Get the size file for the next calculation + logFile->lastFileSize=file->size(); + + // Close the file + this->closeFile(file); + + QString message; + message=i18n("Log file '%1' has changed.").arg(logFile->url.path()); + emit statusbarChanged(message); + + //Emit a signal which informs connected slots that there are new lines + emit logUpdated(newLineCount); +} + + + + +bool DefaultReader::insertLine(QString& buffer, LogFile* originalFile) { + LogLine* line=this->parseMessage(buffer, originalFile); + + //Do not insert the line if it NULL + //TODO Maybe return true (because we don't want to stop the reading for one dirty line) + if (line==NULL) + return(false); + + + //If the Delete Duplicated Line is checked, we first test that the line is really new + if (tmpDeleteDuplicate==true) { + if (buffers->lineAlreadyExists(line)==true) + return(true); + } + + //If the line is newer, it can be inserted + if (buffers->isNewer(line)==true) { + + if (buffers->getItemCount()<tmpMaxLines) { + buffers->insert(line); + } + else { + return(false); + } + } + //If the line is older, then inserts it only if there is still space in the buffer + else if (buffers->getItemCount()<tmpMaxLines) { + buffers->insert(line); + } + + return(true); +} + + +bool DefaultReader::insertOrReplaceLine(QString& buffer, LogFile* originalFile) { + LogLine* line=this->parseMessage(buffer, originalFile); + + //Do not insert the line if it NULL + //TODO Maybe return true (because we don't want to stop the reading for one dirty line) + if (line==NULL) + return(false); + + //If the Delete Duplicated Line is checked, we first test that the line is really new + if (tmpDeleteDuplicate==true) { + if (buffers->lineAlreadyExists(line)==true) { + return(true); + } + } + + + //If the line is newer, it can be inserted + if (buffers->isNewer(line)==true) { + + if (buffers->getItemCount()<tmpMaxLines) { + buffers->insert(line); + return(true); + } + else { + buffers->removeOldestLine(); + buffers->insert(line); + return(true); + } + } + //If the line is older, then inserts it only if there is still space in the buffer + else if (buffers->getItemCount()<tmpMaxLines) { + buffers->insert(line); + return(true); + } + + return(false); +} + +/** + * TODO Improve speed of this method (with KRegExp class for example) + */ +LogLine* DefaultReader::parseMessage(QString& logLine, LogFile* originalFile) { + //kdDebug() << "Please don't use parseMessage() from SortedReader class" << endl; + + int year=QDate::currentDate().year(); + + //Month number + QString month; + month=logLine.left(3); + + logLine=logLine.remove(0, 4); + int monthNum=ParsingHelper::parseMonthNumber(month); + + //Day number + QString day; + + day=logLine.left(2); + int dayNum=day.toInt(); + + logLine=logLine.remove(0, 3); + + QDate date(year, monthNum, dayNum); + if (!date.isValid()) { + kdDebug() << "Malformed date" << endl; + date=QDate::currentDate(); + } + + //Time + QString stringTime; + stringTime=logLine.left(8); + int h=stringTime.left(2).toInt(); + stringTime.remove(0, 3); + int m=stringTime.left(2).toInt(); + stringTime.remove(0, 3); + int s=stringTime.left(2).toInt(); + stringTime.remove(0, 3); + + QTime time(h, m, s); + if (!time.isValid()) { + kdDebug() << "Malformed time" << endl; + time=QTime::currentTime(); + } + + //QStringList + logLine=logLine.remove(0, 9); + + int nextSpace; + nextSpace=logLine.find(' '); + + //Host name + QString hostname; + + hostname=logLine.left(nextSpace); + + logLine=logLine.remove(0, nextSpace+1); + + + QString process; + QString message; + + //Process name + nextSpace=logLine.find(':'); + if (nextSpace!=-1) { + process=logLine.left(nextSpace); + + //If the delete process identifier option is enabled + if (tmpDeleteProcessId==true) { + int squareBracket=process.find('['); + + //If we find a bracket, we remove the useless part + if (squareBracket!=-1) { + process=process.left(squareBracket); + } + + } + logLine=logLine.remove(0, nextSpace+1); + + message=logLine.remove(0, 1); + } + //If we can't find any ':' character, it means that this line is a + //internal message of syslogd + else { + process=i18n("none"); + + message=logLine; + } + + + + + + QStringList list; + list.append(hostname); + list.append(process); + list.append(message); + + /* + *TODO Try to avoid that 2 columns with the same timestamps (but not the + *same appearance order are not sorted correctly + */ + /* + LogLine* lastLine=buffers->lastLineInserted(); + if (lastLine!=NULL) { + if (lastLine->getTime().date()==date && lastLine->getTime().time()==time) + time=time.addMSecs(1); + } + */ + + QString filePath=originalFile->url.path(); + LogLine* logLineObject=new LogLine(date, time, list, filePath, originalFile->level, Globals::noMode->id); + + return(logLineObject); +} + + +QStringList* DefaultReader::getRawBuffer(QFile* file) { + kdDebug() << "Retrieving the raw buffer..." << endl; + + QString buffer; + QString tmpBuffer; + QStringList* rawBuffer=new QStringList(); + + int res; + + //Insert the content of the file in a string list + while(!file->atEnd()) { + + //Read the first MaxCharactersRead characters + res=file->readLine(buffer, tmpMaxCharacters); + + //Ignore the rest of the line + while(res==tmpMaxCharacters) + file->readLine(tmpBuffer, tmpMaxCharacters); + + //Push the new buffer to the list + rawBuffer->push_back(buffer); + } + + kdDebug() << "Raw buffer retrieved." << endl; + + return(rawBuffer); +} + +#include "defaultReader.moc" |