source: src-qt4/life-preserver/LPWatcher.cpp @ 8516ff2

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since 8516ff2 was 8516ff2, checked in by Ken Moore <ken@…>, 16 months ago

Setup the LPTray to use the new LPWatcher class (untested yet)

  • Property mode set to 100644
File size: 10.3 KB
Line 
1#include "LPWatcher.h"
2
3/* ------ HASH NUMBERING NOTE -----
4  Each set of 10 is a different type of status
5    "message" status: 10-19
6    "replication" status: 20-29
7    "critical" status: 30-39
8  Within each set:
9    *0 = ID Code (for internal identification as necessary)
10    *1 = dataset (example: tank1)
11    *2 = summary (shortened version of the message - good for titles)
12    *3 = message (full message)
13    *4 = timestamp (full date/time timestamp in readable format)
14    *5 = short timestamp (just time in readable format)
15
16  Valid Internal ID's:
17    SNAPCREATED -> new snapshot created
18    REPSTARTED    -> Replication task started
19    REPFINISHED  -> Replication task finished
20    REPERROR       -> Replication task failed
21   
22*/
23
24LPWatcher::LPWatcher() : QObject(){
25  //Initialize the path variables
26  FILE_LOG = "/var/log/lpreserver/lpreserver.log";
27  FILE_ERROR="/var/log/lpreserver/error.log";
28  FILE_REPLICATION=""; //this is set automatically based on the log file outputs
29
30  //initialize the watcher and timer
31  watcher = new QFileSystemWatcher(this);
32    connect(watcher, SIGNAL(fileChanged(QString)),this,SLOT(fileChanged(QString)) );
33  timer = new QTimer();
34    timer->setInterval( 600000 ); //10 minute check time
35    connect(timer, SIGNAL(timeout()), this, SLOT(checkErrorFile()) );
36  //initialize the log file reader
37  logfile = new QFile(FILE_LOG, this);
38  LFSTREAM = new QTextStream(logfile);
39  //initialize the replication file reader
40  repfile = new QFile(this);
41}
42
43LPWatcher::~LPWatcher(){
44  //clean up the internal objects
45  delete watcher;
46  delete timer;
47  delete logfile;
48  delete LFSTREAM;
49}
50
51// -----------------------------------
52//    PUBLIC FUNCTIONS
53// -----------------------------------
54void LPWatcher::start(){
55  if(!logfile->exists()){
56    QString dir = FILE_LOG;
57          dir.chop( dir.section("/",-1).count()+1 );
58    if(!QFile::exists(dir)){ system( QString("mkdir -p "+dir).toUtf8() ); }
59    system( QString("touch "+FILE_LOG).toUtf8() );
60  }
61  //Read the current state of the log file
62  logfile->open(QIODevice::ReadOnly | QIODevice::Text);
63  readLogFile(true); //do this quietly the first time through
64  //Now start up the log file watcher
65  watcher->addPath(FILE_LOG);
66  //Now check for any current errors in the LPbackend
67  checkErrorFile();
68  //And start up the error file watcher
69  timer->start();
70}
71
72void LPWatcher::stop(){
73  watcher->removePaths(watcher->files());
74  logfile->close();
75  timer->stop();
76}
77
78QStringList LPWatcher::getMessages(QString type, QStringList msgList){
79  QStringList output;
80  type = type.toLower();
81  //Valid types - "critical"/"running"/"message"
82  //Valid messages - "dataset","message","summary","id", "timestamp", "time"
83  unsigned int base;
84  if(type=="message"){base=10;}
85  else if(type=="running"){base=20;}
86  else if(type=="critical"){base=30;}
87  else{ return output; } //invalid input type
88  //Now fill the output array based upon requested outputs
89  for(int i=0; i<msgList.length(); i++){
90    msgList[i] = msgList[i].toLower();
91    if(msgList[i]=="id" && LOGS.contains(base)){ output << LOGS[base]; }
92    else if(msgList[i]=="dataset" && LOGS.contains(base+1)){ output << LOGS[base+1]; }
93    else if(msgList[i]=="summary" && LOGS.contains(base+2)){ output << LOGS[base+2]; }
94    else if(msgList[i]=="message" && LOGS.contains(base+3)){ output << LOGS[base+3]; }
95    else if(msgList[i]=="timestamp" && LOGS.contains(base+4)){ output << LOGS[base+4]; }
96    else if(msgList[i]=="time" && LOGS.contains(base+5)){ output << LOGS[base+5]; }
97    else{ output << ""; }
98  }
99  //Return the output list
100  return output;
101}
102
103// -------------------------------------
104//    PRIVATE FUNCTIONS
105// -------------------------------------
106void LPWatcher::readLogFile(bool quiet){
107  QTextStream in(logfile);
108  while(!LFSTREAM->atEnd()){
109    QString log = LFSTREAM->readLine();
110    //Divide up the log into it's sections
111    QString timestamp = log.section(":",0,2).simplified();
112    QString time = timestamp.section(" ",3,3).simplified();
113    QString message = log.section(":",3,3).toLower().simplified();
114    QString dev = log.section(":",4,4).simplified(); //dataset/snapshot/nothing
115    //Now decide what to do/show because of the log message
116    qDebug() << "New Log Message:" << log;
117    if(message.contains("creating snapshot")){
118      dev = message.section(" ",-1).simplified();
119      //Setup the status of the message
120      LOGS.insert(10,"SNAPCREATED");
121      LOGS.insert(11,dev); //dataset
122      LOGS.insert(12, tr("New Snapshot") ); //summary
123      LOGS.insert(13, QString(tr("Creating snapshot for %1")).arg(dev) );
124      LOGS.insert(14, timestamp); //full timestamp
125      LOGS.insert(15, time); // time only
126      if(!quiet){ emit MessageAvailable("message"); }
127    }else if(message.contains("starting replication")){
128      //Setup the file watcher for this new log file
129      FILE_REPLICATION = dev;
130      startRepFileWatcher();
131      //Set the appropriate status variables
132      LOGS.insert(20,"REPSTARTED");
133      // 21 - dataset set on update ping
134      LOGS.insert(22, tr("Replication Started") ); //summary
135      // 23 - Full message set on update ping
136      LOGS.insert(24, timestamp); //full timestamp
137      LOGS.insert(25, time); // time only     
138      //let the first ping of the replication file watcher emit the signal - don't do it now
139    }else if(message.contains("finished replication")){
140      stopRepFileWatcher();
141      dev = message.section(" ",-1).simplified();
142      //Now set the status of the process
143      LOGS.insert(20,"REPFINISHED");
144      LOGS.insert(21,dev); //dataset
145      LOGS.insert(22, tr("Finished Replication") ); //summary
146      LOGS.insert(23, QString(tr("Finished replication for %1")).arg(dev) );
147      LOGS.insert(24, timestamp); //full timestamp
148      LOGS.insert(25, time); // time only     
149      if(!quiet){ emit MessageAvailable("replication"); }
150    }else if( message.contains("FAILED replication") ){
151      stopRepFileWatcher();
152      //Now set the status of the process
153      dev = message.section(" ",-1).simplified();
154      QString file = log.section("LOGFILE:",1,1).simplified();
155      QString tt = QString(tr("Replication Failed for %1")).arg(dev) +"\n"+ QString(tr("Logfile available at: %1")).arg(file);
156      LOGS.insert(20,"REPERROR");
157      LOGS.insert(21,dev); //dataset
158      LOGS.insert(22, tr("Replication Failed") ); //summary
159      LOGS.insert(23, tt );
160      LOGS.insert(24, timestamp); //full timestamp
161      LOGS.insert(25, time); // time only     
162      if(!quiet){ emit MessageAvailable("replication"); }
163    }
164         
165  }
166}
167
168void LPWatcher::readReplicationFile(bool quiet){
169  QString stat;
170  while( !RFSTREAM->atEnd() ){ 
171    QString line = RFSTREAM->readLine(); 
172    if(line.contains("total estimated size")){ repTotK = line.section(" ",-1).simplified(); } //save the total size to replicate
173    else if(line.startsWith("send from ")){}
174    else if(line.startsWith("TIME ")){}
175    else{ stat = line; } //only save the relevant/latest status line
176  }
177  if(stat.isEmpty()){
178    qDebug() << "New Status Message:" << stat;
179    //Divide up the status message into sections
180    stat.replace("\t"," ");
181    QString dataset = stat.section(" ",2,2,QString::SectionSkipEmpty).section("/",0,0).simplified();
182    QString cSize = stat.section(" ",1,1,QString::SectionSkipEmpty);
183    //Now Setup the tooltip
184    if(cSize != lastSize){ //don't update the info if the same size info
185      QString percent;
186      if(!repTotK.isEmpty()){
187        //calculate the percentage
188        double tot = displayToDoubleK(repTotK);
189        double c = displayToDoubleK(cSize);
190        if( tot!=-1 & c!=-1){
191          double p = (c*100)/tot;
192          p = int(p*10)/10.0; //round to 1 decimel places
193          percent = QString::number(p) + "%";
194        }
195      }
196      if(repTotK.isEmpty()){ repTotK = "??"; }
197      //Format the info string
198      QString status = cSize+"/"+repTotK;
199      if(!percent.isEmpty()){ status.append(" ("+percent+")"); }
200      QString txt = QString(tr("Replicating %1: %2")).arg(dataset, status);
201      lastSize = cSize; //save the current size for later
202      //Now set the current process status
203      LOGS.insert(21,dataset);
204      LOGS.insert(23,txt);
205      if(!quiet){ emit MessageAvailable("replication"); }
206    }
207  }
208}
209
210void LPWatcher::startRepFileWatcher(){
211  if(FILE_REPLICATION.isEmpty()){ return; }
212  if(!QFile::exists(FILE_REPLICATION)){ system( QString("touch "+FILE_REPLICATION).toUtf8() ); }
213  repfile->setFileName(FILE_REPLICATION);
214  repfile->open(QIODevice::ReadOnly | QIODevice::Text);
215  RFSTREAM = new QTextStream(repfile);
216  watcher->addPath(FILE_REPLICATION);
217}
218
219void LPWatcher::stopRepFileWatcher(){
220  if(FILE_REPLICATION.isEmpty()){ return; }
221  watcher->removePath(FILE_REPLICATION);
222  repfile->close();
223  delete RFSTREAM;
224  FILE_REPLICATION.clear();
225  repTotK.clear();
226  lastSize.clear();
227}
228
229double LPWatcher::displayToDoubleK(QString displayNumber){
230  QStringList labels; 
231    labels << "K" << "M" << "G" << "T" << "P" << "E";
232  QString clab = displayNumber.right(1); //last character is the size label
233        displayNumber.chop(1); //remove the label from the number
234  double num = displayNumber.toDouble();
235  //Now format the number properly
236  bool ok = false;
237  for(int i=0; i<labels.length(); i++){
238    if(labels[i] == clab){ ok = true; break; }
239    else{ num = num*1024; } //get ready for the next size
240  }
241  if(!ok){ num = -1; } //could not determine the size
242  return num;
243}
244
245// ------------------------------
246//    PRIVATE SLOTS
247// ------------------------------
248void LPWatcher::fileChanged(QString file){
249  if(file == FILE_LOG){ readLogFile(); }
250  else  if(file == FILE_REPLICATION){ readReplicationFile(); }
251}
252
253void LPWatcher::checkErrorFile(){
254  return;
255  if(QFile::exists(FILE_ERROR)){
256    //Read the file to determine the cause of the error
257    QString msg, id, summary, timestamp, time, dataset;
258    QFile file(FILE_ERROR);
259      file.open(QIODevice::ReadOnly | QIODevice::Text);
260      QTextStream in(&file);
261      qDebug() << "Error File Parsing not implemented yet. \n - File Contents:";
262      while(!in.atEnd()){
263        QString line = in.readLine();
264        //Now look for key information on this line
265        qDebug() << line;
266      }
267    //Now set the status and emit the signal
268    LOGS.insert(30, id);
269    LOGS.insert(31, dataset); //dataset
270    LOGS.insert(32, summary ); //summary
271    LOGS.insert(33, msg ); //message
272    LOGS.insert(34, timestamp); //full timestamp
273    LOGS.insert(35, time); // time only   
274    emit MessageAvailable("critical");
275  }
276}
Note: See TracBrowser for help on using the repository browser.