WARNING: USE THIS SOFTWARE AT YOUR OWN RISK! THIS IS EXPERIMENTAL SOFTWARE NOT INTENDED FOR PRODUCTION USE! Zuble is currently an early stage prototype. As such Zuble is minimally tested and inherently unstable. It is provided for experimental, development, and demonstration purposes only. Zuble QML Types   |  Zuble C++ Classes   |  Zuble Overview
Zuble  0.1
Zuble Framework C++/QML extension API
ZblLogReader.cpp
Go to the documentation of this file.
1 /*
2  * Zuble - A run-time system for QML/Javascript applications
3  * Copyright (C) 2015 Bob Dinitto
4  *
5  * Filename: ZblLogReader.cpp
6  * Created on: 11/22/2015
7  * Author: Bob Dinitto
8  *
9  * Zuble is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 #include "ZblLogReader.h"
26 #include "ZLogViewport.h"
27 #include "ZApplication.h"
28 #include "ZLogReader.h"
29 #include "ZblLogLinkList.h"
30 #include "ZblLogManager.h"
31 #include "ZblLogScanner.h"
32 #include "ZblLogSearch.h"
33 #include <QThread>
34 #include <QtQml>
35 
36 
37 namespace Zbl {
38 
40 
41 QThread* ZblLogReader::m_readerThread = 0;
42 
43 QMutex ZblLogReader::m_lock(QMutex::Recursive);
44 
46 
47 qint64 ZblLogReader::m_defaultPageSize = 10000;
48 
50 
51 const int ZblLogReader::m_updateBatchSize = 10;
52 
53 const qint64 ZblLogReader::m_maxLineSize = 20000;
54 
55 
56 
57 
58 ZblLogReader::ZblLogReader(QObject *parent) :
59  QObject(parent),
60  //m_logModel(NULL),
61  m_fileActive(false),
62  m_firstRecordPos(-1),
63  m_timerID(0)
64 {
65 
66 
67 }
68 
70 {
71 
72 }
73 
74 
75 void ZblLogReader::zInit(int logRecordRoleCount)
76 {
78 
79  qmlRegisterUncreatableType<ZblLogReader>("org.zuble.qml", 1, 0,
80  "ZblLogReader", "ZblLogReader is an internal Zuble type. Use ZLogReader instead.");
81 
82  // TBD WE'RE CALLING THIS TWICE FOR ZLogViewport!
83 
84  qmlRegisterUncreatableType<ZLogViewport>("org.zuble.qml", 1, 0,
85  "ZLogViewport", "Use ZLogReader to create ZLogViewport objects.");
86 
87  m_recordRoleCount = logRecordRoleCount;
88 
89 }
90 
92 {
93  if(m_firstRecordPos != -1)
94  return;
95 
96  QByteArray metaRecord;
97 
98  zDebug() << "Loading log file metadata.";
99 
100  m_inputFile.seek(0);
101  metaRecord = m_inputFile.readLine(m_maxLineSize);
103 
104  if(metaRecord.size() == 0)
105  {
106  zWarning() << "Log file id and metadata not available.";
107  return;
108  }
109 
110  int uuidEndPos = metaRecord.indexOf('}');
111 
112  if(uuidEndPos == -1)
113  {
114  zWarning() << "Log file id not available.";
115  return;
116  }
117 
118  QUuid uuid(metaRecord.left(uuidEndPos+1));
119 
120  if(uuid.isNull())
121  {
122  zWarning() << "Log file id invalid format.";
123  return;
124  }
125  else
126  {
127  zDebug() << "Log file id: " << uuid.toByteArray();
128 
129  m_uuid = uuid;
130  }
131 
132  if(metaRecord.size() <= uuidEndPos+1)
133  {
134  zWarning() << "Log file metadata not available.";
135  return;
136  }
137 
138  QJsonParseError er;
139 
140  QByteArray metaBytes = metaRecord.right(metaRecord.size() - uuidEndPos - 1);
141 
142  zDebug() << "Log file metadata: " << metaBytes;
143 
144  QJsonDocument doc = QJsonDocument::fromJson(metaBytes, &er);
145 
146  if(er.error != QJsonParseError::NoError)
147  {
148  zWarning() << "Log file metadata parse error: "
149  << er.errorString();
150 
151  return;
152  }
153 
154  zDebug() << "Log file metadata parsed OK.";
155 
156  if(!doc.isObject())
157  {
158  zWarning() << "Log file metadata format error. Metadata must be a JSON object.";
159  return;
160  }
161 
162  QJsonObject jsonObj = doc.object();
163 
164  m_metadata = jsonObj.toVariantMap();
165 }
166 
167 
168 void ZblLogReader::timerEvent(QTimerEvent * event)
169 {
170  //zDebug() << "Got timerEvent function call";
171 
172  if(m_fileActive)
173  {
174  //zDebug() << "Emitting notifyFileSize signal";
175 
176  emit notifyFileSize(m_inputFile.size());
177  }
178 }
179 
181 {
182 
183  {
184  QMutexLocker lock(&m_lock);
185  if(!m_readerThread)
186  {
187  m_readerThread = new QThread();
188  m_readerThread->start();
189  }
190  m_readerCount++;
191  }
192 
193  ZblLogReader* newReader = new ZblLogReader();
194 
195  newReader->moveToThread(m_readerThread);
196 
197  return newReader;
198 
199 }
200 
201 void ZblLogReader::openFile(const QString& filePath, QVariantMap contextMap)
202 {
203  if(m_fileActive)
204  close();
205 
206  QString err;
207 
208  m_inputFile.setFileName(ZApplication::resolvePath(filePath, false));
209 
210  m_fileActive = m_inputFile.open(QFile::ReadOnly | QIODevice::Text);
211 
212  if(!m_fileActive)
213  {
214  err = m_inputFile.errorString();
215 
216  zCritical() << "OpenFile error: " << err
217  << ", error =" << m_inputFile.error();
218  }
219  else
220  {
222  }
223 
224 
225  emit openComplete(m_fileActive, err, contextMap);
226 
227  m_timerID = startTimer(5000);
228 
229 }
230 
232 {
233  if(m_fileActive)
234  {
235  if(m_timerID != 0)
236  {
237  killTimer(m_timerID);
238  m_timerID = 0;
239  }
240 
241  m_fileActive = false;
242  m_inputFile.close();
243  }
244 }
245 
246 void ZblLogReader::loadViewport(QObject *viewport,
247  qint64 seekPosition,
248  qint64 viewportSize,
249  ZblLogSearchParams searchParams,
250  bool loadMarkupColumn,
251  QVariantMap contextMap)
252 {
253 
254  QString errMsg;
255 
256  qint64 rowsFound = 0;
257  qint64 rowsStored = 0;
258  bool eof = false;
259 
260  ZLogViewport* zViewport = qobject_cast<ZLogViewport*>(viewport);
261 
262  if(!zViewport)
263  {
264  errMsg = "You must pass a ZLogViewport object as first argument.";
265 
266  emit loadComplete(viewport, searchParams, eof, errMsg, contextMap);
267 
268  return;
269  }
270 
271  ZTableModel* model = zViewport->getZModel();
272 
273  model->clearData();
274 
275  zViewport->m_optimalCount = viewportSize;
276 
277  if(seekPosition > m_inputFile.size())
278  {
279  // TBD: ENDING should not necessarily be an error.
280 
281  errMsg = "Log file doesn't contain requested rows.";
282 
283  emit loadComplete(viewport, searchParams, eof, errMsg, contextMap);
284  emit zViewport->loadComplete(eof, errMsg, contextMap);
285 
286  return;
287  }
288 
289 
290  errMsg = loadRowsAhead(
291  zViewport,
292  seekPosition,
293  viewportSize,
294  false,
295  &searchParams,
296  loadMarkupColumn,
297  rowsFound,
298  rowsStored,
299  eof
300  );
301 
302  //emit loadComplete(viewport, searchParams, eof, errMsg, contextMap);
303 
304  // TBD: ZblLogBkSearch will connect the loadComplete signal of it's background
305  // viewport to it's loadComplete processing function no need to pass searchparams anymore.
306 
307  emit zViewport->loadComplete(eof, errMsg, contextMap);
308 
309 }
310 
312  ZLogViewport* viewport,
313  qint64 seekPos,
314  qint64 rowCount,
315  bool truncate,
316  const ZblLogSearchParams* searchParams,
317  bool loadMarkupColumn,
318  qint64& foundCount,
319  qint64& storedCount,
320  bool& eof
321  )
322 {
323  foundCount = 0;
324  storedCount = 0;
325  eof = false;
326 
327  qint64 parsedLines = 0;
328 
329  qint64 currentIndex = 0;
330  const qint64 finalIndex = rowCount - 1;
331 
332  //qint64 nextRecordIdIndex = 0;
333  //QMap<qint64, QStringList> bookmarks;
334 
335  QByteArray ba;
336  QString errMsg;
337  ZDataRow cellBuffer;
338  ZblLogError logError;
339 
341 
342  if(loadMarkupColumn && searchParams->origin() != -1)
344 
345  ZblLogScanner scanner(searchParams, flags, loadMarkupColumn);
346 
347  if(seekPos == 0)
348  {
349  zDebug() << "Skipping log file metadata.";
350  m_inputFile.seek(0);
351  m_inputFile.readLine(m_maxLineSize);
352  }
353  else
354  {
355  m_inputFile.seek(seekPos);
356  }
357 
358  while(true)
359  {
360  ba = m_inputFile.readLine(m_maxLineSize);
361 
362  if(ba.isEmpty())
363  {
364  eof = m_inputFile.atEnd();
365 
366  if(!eof && (currentIndex < finalIndex))
367  {
368  errMsg = "Log file doesn't contain requested rows.";
369  }
370 
371  if(!cellBuffer.isEmpty())
372  {
373  storeViewportData(cellBuffer, viewport, truncate);
374  storedCount += parsedLines;
375  parsedLines = 0;
376  }
377 
378  break;
379  }
380 
381  foundCount++;
382 
383  parseNextFileRecord(viewport, ba, seekPos, scanner, cellBuffer, logError);
384 
385  // TBD: add a method to input cellBuffer and search text list (role, index, length)
386  // and output a second cell buffer containing rich text; load rich text cell buffer
387  // into col 1 of data model. do this only if search mode = true.
388 
389  if(logError.errorType == ZblLogError::PARSE_ERROR)
390  {
391  errMsg = "JSON parse error at seek position: %1, %2";
392 
393  errMsg = errMsg.arg(seekPos);
394  errMsg = errMsg.arg(logError.parseError.errorString());
395 
396  zWarning() << errMsg;
397  }
398  else if(logError.errorType == ZblLogError::NOTARRAY_ERROR)
399  {
400  errMsg = "Log file format error at seek position: %1, "
401  "Each Zuble log record must be a JSON array.";
402 
403  errMsg.arg(seekPos);
404 
405  zWarning() << errMsg;
406  }
407  else if(logError.errorType == ZblLogError::FIELDCOUNT_ERROR)
408  {
409  errMsg = "Log file format error at seek position: %1, "
410  "Each Zuble log record must be a JSON array.";
411 
412  errMsg.arg(seekPos);
413 
414  zWarning() << errMsg;
415  }
416  else
417  {
418  parsedLines++;
419 
420  //zDebug() << "READING RECORD: " << recordID;
421 
422  }
423 
424  if((rowCount != -1) && (currentIndex == finalIndex))
425  {
426  storeViewportData(cellBuffer, viewport, truncate);
427  storedCount += parsedLines;
428  parsedLines = 0;
429  break;
430  }
431 
432  if(currentIndex % m_updateBatchSize == 0)
433  {
434  storeViewportData(cellBuffer, viewport, truncate);
435  storedCount += parsedLines;
436  parsedLines = 0;
437  }
438 
439  seekPos = m_inputFile.pos();
440  currentIndex++;
441  }
442 
443  return errMsg;
444 }
445 
447  ZLogViewport* viewport,
448  const QByteArray& ba,
449  qint64 seekPos,
450  ZblLogScanner& logScanner,
451  ZDataRow& cellBuffer,
452  ZblLogError& logError
453  )
454 {
455  logError.errorType = logError.NO_ERROR;
456  logError.formatErrorString.clear();
457 
458  if(ba.isEmpty())
459  return;
460 
461  QJsonDocument doc = QJsonDocument::fromJson(ba, &logError.parseError);
462 
463  if(logError.parseError.error != QJsonParseError::NoError)
464  {
465  logError.errorType = logError.PARSE_ERROR;
466  return;
467  }
468 
469  if(!doc.isArray())
470  {
471  logError.errorType = logError.NOTARRAY_ERROR;
472  logError.formatErrorString =
473  "Each Zuble log record must be a JSON array "
474  "containing %1 cells per row.";
475  logError.formatErrorString.arg(m_recordRoleCount);
476  return;
477  }
478 
479  QJsonArray ja = doc.array();
480 
481  const int arraySize = ja.size();
482 
483  if(arraySize != m_recordRoleCount)
484  {
485  logError.errorType = logError.FIELDCOUNT_ERROR;
486  logError.formatErrorString =
487  "Can't load log record: Record size mismatch! Expecting %1 "
488  "cells per row but file has %2.";
489  logError.formatErrorString.arg(m_recordRoleCount, arraySize);
490  return;
491  }
492 
493  QVariantList va(ja.toVariantList());
494 
495  // insert additional model roles for log viewer use only
496 
497  qint64 recordID = va.at(0).toLongLong();
498 
499  //va.append(recordID);
500 
501  va.append(QVariant(seekPos));
502  va.append(QVariant(ba.size()));
503 
504  // TDB: we must move this call to ZLogReader to foreground thread!!!
505  //va.append(QVariant(viewport->getZReader()->getBookmarkNames(recordID))); // TBD: SLOW!!!!!
506 
507  va.append(QVariant("")); // dummy placeholder for bookmark names data
508 
509  cellBuffer.append(va);
510 
511  if(logScanner.outputMarkupColumn())
512  {
513  if(logScanner.outputHighlightedText())
514  {
515  va = logScanner.markupOrdinalRoleList(va);
516 
517  }
518  cellBuffer.append(va);
519  }
520 
521  return;
522 }
523 
525  ZDataRow& cellData,
526  ZLogViewport* viewport,
527  bool truncate)
528 {
529  ZTableModel* model = viewport->getZModel();
530  model->appendCells(cellData, truncate);
531  cellData.clear();
532 }
533 
535  zRowBuffer& logRecords,
536  zSeekBuffer& seekPositions,
537  qint64 rowCount,
538  ZLogViewport* viewport,
539  ZblLogScanner& logScanner)
540 {
541 
542  const qint64 recordCount = logRecords.size();
543 
544  zDebug() << "Record count = " << recordCount;
545  zDebug() << "Rows needed = " << rowCount;
546 
547  if(recordCount == 0 || rowCount == 0)
548  {
549  zDebug() << "rows stored = " << 0;
550  return 0;
551  }
552 
553  int rowsStored = -1;
554 
555  ZDataRow cellBuffer;
556  ZblLogError logError;
557 
558  qint64 index = recordCount - rowCount;
559 
560  if(index < 0)
561  index = 0;
562 
563  zDebug() << "index = " << index;
564 
565  //const int lastIndex = recordCount - 1;
566 
567  rowsStored = recordCount - index;
568 
569  int lostRecords;
570 
571  for(lostRecords = 0; index < recordCount; index++)
572  {
573  //zDebug() << "Saving record at index: " << index;
574 
575  qint64 seekPos = seekPositions.at(index);
576 
578  viewport,
579  logRecords.at(index),
580  seekPos,
581  logScanner,
582  cellBuffer,
583  logError
584  );
585 
586  if(logError.errorType == ZblLogError::PARSE_ERROR)
587  {
588  lostRecords++;
589 
590  QString errMsg = "JSON parse error at seek position: %1, %2";
591 
592  errMsg.arg(seekPos).arg(logError.parseError.errorString());
593 
594  zWarning() << errMsg;
595  }
596  else if(logError.errorType != ZblLogError::NO_ERROR)
597  {
598  lostRecords++;
599 
600  QString errMsg = "Log file format error at seek position: %1, %2";
601 
602  errMsg.arg(seekPos).arg(logError.formatErrorString);
603 
604  zWarning() << errMsg;
605  }
606  //TBD: ARE WE MISSING SOME ERROR CONDITIONS HERE?
607  }
608 
609  rowsStored -= lostRecords;
610 
611  zDebug() << "rows stored = " << rowsStored;
612 
613  ZTableModel* model = viewport->getZModel();
614 
615  zDebug() << "Saving log records to data model, cell count: " << cellBuffer.size();
616 
617  model->prependCells(cellBuffer, true);
618 
619  return rowsStored;
620 }
621 
622 
624  ZLogViewport* viewport,
625  qint64 seekPos,
626  qint64 rowCount,
627  const ZblLogSearchParams* searchParams,
628  bool loadMarkupColumn,
629  qint64& foundCount,
630  qint64& storedCount,
631  bool& bof
632  )
633 {
634  //qint64 currentIndex = 0;
635  //const qint64 finalIndex = rowCount - 1;
636 
637  foundCount = 0;
638  storedCount = 0;
639  bof = false;
640 
641  //int startSeek = seekPos;
642  qint64 chunkSize = 1024; // number of bytes to fetch
643  zRowBuffer rowBuffer; // raw (JSON array) data row buffer
644  zSeekBuffer seekBuffer; // seek positions for rowBuffer
645  bool moreData = true; // becomes false when first row in file has been read
646 
647  QByteArray ba; // temporary row storage
648  QString errMsg; // holds error message
649  //ZDataRow cellBuffer; // multi-row list of data model cells
650 
651  qint64 rowsNeeded = rowCount; // rows left to find
652 
654 
655  if(loadMarkupColumn && searchParams->origin() != -1)
657 
658  ZblLogScanner scanner(searchParams, flags, loadMarkupColumn);
659 
660 
661  //static qint64 firstRecordPos = -1;
662 
663  //initializeMetadata();
664 
665  while(true)
666  {
667  // seek back from current pos by x bytes
668 
669  bool discard = true;
670 
671  qint64 startSeek = seekPos;
672 
673  seekPos = seekPos - chunkSize;
674 
675  zDebug() << "Seeking back - startSeek = " << startSeek
676  << ", chunkSize = " << chunkSize;
677 
678  if(seekPos <= 0)
679  {
680  zDebug() << "Seek at or past beginning of file: " << seekPos;
681  seekPos = 0;
682  moreData = false;
683  discard = false;
684  bof = true;
685  }
686 
687  m_inputFile.seek(seekPos);
688 
689  // readline forward - discard potentially incomplete lines, accumulate remainder
690 
691  while(seekPos < startSeek)
692  {
693  zDebug() << "Reading next line at seekPos:" << seekPos;
694 
695  ba = m_inputFile.readLine(m_maxLineSize);
696 
697  if(!ba.isEmpty() && !discard)
698  {
699  zDebug() << "Saving line at seekPos: " << seekPos;
700 
701  rowBuffer.push_back(ba);
702  seekBuffer.push_back(seekPos);
703  }
704  else
705  {
706  zDebug() << "Discarding line at seekPos: " << seekPos;
707  discard = false;
708  }
709 
710  seekPos = m_inputFile.pos();
711  }
712 
713  const int rowsFound = rowBuffer.size();
714 
715  zDebug() << "Rows found = " << rowsFound;
716  zDebug() << "Rows needed = " << rowsNeeded;
717 
718  const int rowsStored = parseAndStoreViewportData(
719  rowBuffer, seekBuffer, rowsNeeded, viewport, scanner);
720 
721  // here
722 
723  foundCount += rowsFound;
724  storedCount += rowsStored;
725 
726  if(rowsStored >= rowsNeeded)
727  break;
728  else if(!moreData)
729  break;
730 
731  rowsNeeded -= rowsFound;
732 
733  zDebug() << "Rows left to fetch: " << rowsNeeded;
734 
735  chunkSize *= 2;
736 
737  if(rowsFound)
738  {
739  seekPos = seekBuffer.at(0);
740  zDebug() << "Setting new seekPos: " << seekPos;
741  }
742  else
743  {
744  zDebug() << "Not setting new seekPos: " << seekPos;
745  }
746 
747  rowBuffer.clear();
748  seekBuffer.clear();
749 
750  }
751 
752  return errMsg;
753 }
754 
756  QObject *viewport,
757  qint64 recordCount,
758  qint64 seekIndex,
759  bool forward,
760  ZblLogSearchParams searchParams,
761  bool loadMarkupColumn
762  )
763 {
764  ZLogViewport* zViewport = qobject_cast<ZLogViewport*>(viewport);
765 
766  QString errMsg;
767 
768  qint64 rowsFound = 0;
769  qint64 rowsStored = 0;
770  bool eod = false;
771 
772  if(!zViewport)
773  {
774  errMsg = "You must pass a ZLogViewport object as first argument.";
775  emit zViewport->moveComplete(rowsFound, rowsStored, eod, errMsg);
776  return;
777  }
778 
779  if(forward)
780  {
781  //m_inputFile.seek(seekIndex);
782 
783  errMsg = loadRowsAhead(
784  zViewport,
785  seekIndex,
786  recordCount,
787  true,
788  &searchParams,
789  loadMarkupColumn,
790  rowsFound,
791  rowsStored,
792  eod
793  );
794  }
795  else
796  {
797  errMsg = loadRowsBehind(
798  zViewport,
799  seekIndex,
800  recordCount,
801  &searchParams,
802  loadMarkupColumn,
803  rowsFound,
804  rowsStored,
805  eod
806  );
807  //zDebug() << errMsg;
808  }
809 
810  // force blocking call to ensure model update complete
811  zViewport->getZModel()->sync();
812 
813  emit zViewport->moveComplete(rowsFound, rowsStored, eod, errMsg);
814 }
815 
817  QObject* searchmark,
818  QVariant links)
819 {
820  ZblLogSearch* search = qobject_cast<ZblLogSearch*>(searchmark);
821 
822  if(!search)
823  {
824  zWarning() << "Programming error: searchmark parameter must be "
825  "a ZLogSearch object.";
826  return;
827  }
828 
829  ZblLogLinkList logLinks = links.value<Zbl::ZblLogLinkList>();
830  ZblLogLinkList results;
831 
832  QByteArray ba;
833  QString errMsg;
834  ZDataRow cellBuffer;
835  ZblLogError logError;
836  bool eof;
837 
838  for(int i=0; i < logLinks.m_links.count(); i++)
839  {
840  logError.errorType = ZblLogError::NO_ERROR;
841 
842  const ZblLogLinkList::LinkNode& nextNode = logLinks.m_links.at(i);
843 
844  zDebug() << "link message id = " << nextNode.m_index << ", seek = " << nextNode.m_value;
845 
846  qint64 seekPos = nextNode.m_value.toLongLong();
847 
848 
849  if(seekPos == 0)
850  {
851  zDebug() << "Skipping log file metadata.";
852  m_inputFile.seek(0);
853  m_inputFile.readLine(m_maxLineSize);
854  }
855  else
856  {
857  m_inputFile.seek(seekPos);
858  }
859 
860  ba = m_inputFile.readLine(m_maxLineSize);
861 
862  if(ba.isEmpty())
863  {
864  eof = m_inputFile.atEnd();
865  break;
866  }
867 
868  QJsonDocument doc = QJsonDocument::fromJson(ba, &logError.parseError);
869 
870  if(logError.parseError.error != QJsonParseError::NoError)
871  {
872  logError.errorType = logError.PARSE_ERROR;
873  zWarning() << "JSON parse error reading log file at seekposition "
874  << seekPos << ": " << logError.parseError.errorString();
875  continue;
876  }
877  else if(!doc.isArray())
878  {
879  logError.errorType = logError.NOTARRAY_ERROR;
880  logError.formatErrorString =
881  "Each Zuble log record must be a JSON array "
882  "containing %1 cells per row.";
883  logError.formatErrorString = logError.formatErrorString.arg(m_recordRoleCount);
884 
885  zWarning() << "JSON format error reading log file at seekposition "
886  << seekPos << ": " << logError.formatErrorString;
887  continue;
888  }
889 
890  QJsonArray ja = doc.array();
891 
892  const int arraySize = ja.size();
893 
894  if(arraySize != m_recordRoleCount)
895  {
896  logError.errorType = logError.FIELDCOUNT_ERROR;
897  logError.formatErrorString =
898  "Can't load log record: Record size mismatch! Expecting %1 "
899  "cells per row but file has %2.";
900  logError.formatErrorString.arg(m_recordRoleCount, arraySize);
901  return;
902  }
903 
904  QJsonValue messageValue = ja.at(ZblLogManager::LogFieldMessage);
905 
906  zDebug() << "link message text = " << messageValue.toString();
907 
908  results.addMessageText(nextNode.m_index, messageValue.toString());
909 
910  }
911 
912  QVariant vResults(QVariant::fromValue<ZblLogLinkList>(results));
913 
914  zDebug() << "Sending linkMessageText signal...";
915 
916 
917  QMetaObject::invokeMethod(search, "onLinkTextComplete", Qt::QueuedConnection, Q_ARG(QVariant, vResults));
918 
919 }
920 
921 
922 } // Zbl
void initializeMetadata()
Reads the log file metadata contained in the first record of the log file.
Q_INVOKABLE void prependCells(QVariant data, bool truncateModel=false)
Asynchronously converts an array of cell data into one or more rows of model data and prepends it to ...
void timerEvent(QTimerEvent *event)
Periodically sends notifyFileSize signal.
static QThread * m_readerThread
A single background thread services all ZblLogReader objects.
Definition: ZblLogReader.h:491
Q_INVOKABLE void appendCells(QVariant data, bool truncateModel=false)
Asynchronously converts an array of cell data into one or more rows of model data and appends it to t...
static QMutex m_lock
Histogram buffer caches bytes of file data for subsequent parsing into log records.
Definition: ZblLogReader.h:486
This class performs log file I/O operations and JSON parsing in a background thread on behalf of a ZL...
Definition: ZblLogReader.h:91
Q_INVOKABLE void clearData()
Removes all data from the model. Roles and role names remain intact.
void move(QObject *viewport, qint64 recordCount, qint64 seekIndex, bool forward, ZblLogSearchParams searchParams, bool loadMarkupColumn)
Moves the viewport forward or backward a specific number of records.
This class allows Zuble log file viewer text search operations to pass parameters between threads...
#define ZBL_REGISTER_LOGGED_OBJECT
Definition: zglobal.h:104
bool outputHighlightedText()
Determine if scanner is enabled.
QList< qint64 > zSeekBuffer
Definition: ZblLogReader.h:96
QString loadRowsBehind(ZLogViewport *viewport, qint64 seekPos, qint64 rowCount, const ZblLogSearchParams *searchParams, bool loadMarkupColumn, qint64 &foundCount, qint64 &storedCount, bool &bof)
Prepends log data records to the data model scanning backward in the file from the specified seek pos...
QString loadRowsAhead(ZLogViewport *viewport, qint64 seekPos, qint64 rowCount, bool truncate, const ZblLogSearchParams *searchParams, bool loadMarkupColumn, qint64 &foundCount, qint64 &storedCount, bool &eof)
Appends log records to the data model scanning foreward in the file from the specified seek position...
bool outputMarkupColumn()
Determine if scanner will output markup column when scanning log record data models.
ZTableModel * getZModel()
Returns the data model containing the viewport&#39;s log records.
bool m_fileActive
true if input file is open and ready for reading, false otherwise.
Definition: ZblLogReader.h:467
void openFile(const QString &filePath, QVariantMap contextMap=QVariantMap())
Opens the log file in a concurrent background thread. Sends the openComplete signal when open is comp...
QVariantMap m_metadata
A QVariantMap containing meta information about the log file.
Definition: ZblLogReader.h:536
A log viewport encapsulates a ZTableModel containing a contiguous subset of log records from a Zuble ...
Definition: ZLogViewport.h:95
Definition: ZAndGate.cpp:6
static void zInit(int logRecordRoleCount)
Must be called only once before calling newLogReader();.
void storeViewportData(ZDataRow &cellData, ZLogViewport *viewport, bool truncate=false)
Appends data to the back of the viewport&#39;s data model.
void parseNextFileRecord(ZLogViewport *viewport, const QByteArray &ba, qint64 seekPos, ZblLogScanner &logScanner, ZDataRow &cellBuffer, ZblLogError &logError)
Picks the next file record off the input stream buffer, parses it and contatenates results to the dat...
void loadViewport(QObject *viewport, qint64 seekPosition, qint64 viewportSize, ZblLogSearchParams searchParams, bool loadMarkupColumn=false, QVariantMap contextMap=QVariantMap())
Loads a viewport&#39;s log record data model with the a set of records located by a file seek index...
static ZblLogReader * newLogReader()
creates a new ZblLogReader object and moves it to the shared background log reader thread...
#define ZBL_DEFINE_LOGGED_OBJECT(class_name)
Definition: zglobal.h:99
#define zWarning()
Definition: zglobal.h:111
This two dimensional table model is used to store and manipulate data.
Definition: ZTableModel.h:96
void loadRecordLinkMessageText(QObject *searchmark, QVariant links)
Loads the message text from the log file for the specified ZLogSearch object.
int m_timerID
Timer ID for file size timer. Zero == timer inactive.
Definition: ZblLogReader.h:559
static int m_readerCount
Counts instances of ZblLogReader objects.
Definition: ZblLogReader.h:497
#define zDebug()
Definition: zglobal.h:113
void loadComplete(bool endOfData, QString errorMsg, QVariantMap context)
Signals that loading of the viewport requested by a call to loadRecordByIndex() has completed...
static qint64 m_defaultPageSize
number of rows in a default page.
Definition: ZblLogReader.h:502
void moveComplete(qint64 rowsFound, qint64 rowsStored, bool endOfData, QString errorMsg)
Signals that moving of the viewport requested by a call to move() has completed.
void openComplete(bool success, QString errorMsg, QVariantMap contextMap)
Sent when the file open operation started by calling openFile() has completed.
static int m_recordRoleCount
Number of roles in a log record.
Definition: ZblLogReader.h:508
Log record scanner/highlighter object encapsulates logic for locating and marking up search text...
Definition: ZblLogScanner.h:34
QQueue< QByteArray > zRowBuffer
Definition: ZblLogReader.h:95
static QString resolvePath(const QString &path, bool includeUrlScheme=true)
Converts relative file paths into canonical file paths. Paths prefixed with prefix are mapped relativ...
static const int m_updateBatchSize
The number of rows to accumulate before sending a row update to the data model. Batching rows reduces...
Definition: ZblLogReader.h:514
A class for passing log file input error information.
Definition: ZblLogReader.h:294
void loadComplete(QObject *viewport, ZblLogSearchParams searchParams, bool endOfData, QString errorMsg, QVariantMap context)
Sent when loading log records into a viewport by calling ZblLogReader::loadViewport() has completed...
qint64 m_optimalCount
Identifies the first record in the viewport.
Definition: ZLogViewport.h:722
Q_INVOKABLE void sync()
Blocks thread until model&#39;s event queue has been processed.
ZblLogReader(QObject *parent=0)
static const qint64 m_maxLineSize
The maximum number of bytes a log record can contain.
Definition: ZblLogReader.h:520
QVariantList markupOrdinalRoleList(QVariantList data)
Returns a highlighted text string for the specified QVariant objects.
ZBL_DECLARE_LOGGED_OBJECT QFile m_inputFile
Input file object from which log records will be read.
Definition: ZblLogReader.h:461
QUuid m_uuid
A UUID that uniquely identifies this log file.
Definition: ZblLogReader.h:547
int parseAndStoreViewportData(zRowBuffer &logRecords, zSeekBuffer &seekPositions, qint64 rowCount, ZLogViewport *viewport, ZblLogScanner &logScanner)
Parses rows from a row buffer and prepends them to the front of the viewport&#39;s data model...
#define zCritical()
Definition: zglobal.h:112
This object encapsulates search operation parameters, results, and steady state.
Definition: ZblLogSearch.h:35
QList< QVariant > ZDataRow
Represents a single row (or column for column headers) of data cell values for a single role...
Definition: ZTableModel.h:57
virtual ~ZblLogReader()
qint64 m_firstRecordPos
File position of the first log record of the search operation.
Definition: ZblLogReader.h:553
void notifyFileSize(qint64 fileSize)
Periodically signals the current log file size.