34 #include <QMutexLocker> 36 #include <QJsonDocument> 37 #include <QJsonObject> 39 #include <QCoreApplication> 43 #include <QTemporaryFile> 44 #include <QStringBuilder> 69 "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" 71 "xmlns=\"http://zuble.org/schema/zuble/settings\"\n" 72 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" 74 "xsi:schemaLocation=\"http://zuble.org/schema/zuble/settings zublesettings01.xsd\">\n" 75 " <organization>zuble.org</organization> \n" 76 " <name>Zuble</name> \n" 78 " <setgroup xml:id=\"log-histogram\"> \n" 79 " <name>Log Histogram</name> \n" 81 " <setgroup xml:id=\"log-output\"> \n" 82 " <name>Log Output</name> \n" 84 " <setgroup xml:id=\"log-input\"> \n" 85 " <name>Log Input</name> \n" 89 " <setting xml:id=\"histogram-enabled\" group=\"log-histogram\"> \n" 90 " <name>Enabled</name> \n" 91 " <type>bool</type> \n" 92 " <default>false</default> \n" 94 " <state value=\"false\">Disabled</state> \n" 95 " <state value=\"true\">Enabled</state> \n" 97 " <desc>Enable the log histogram buffer.</desc> \n" 99 " <setting xml:id=\"histogram-buffer-size\" group=\"log-histogram\"> \n" 100 " <name>Buffer Size</name> \n" 101 " <type>string</type> \n" 102 " <default>1000</default> \n" 103 " <desc>Set the number of log records the histogram will hold.</desc> \n" 105 " <setting xml:id=\"log-file-enabled\" group=\"log-output\"> \n" 106 " <name>Log To File</name> \n" 107 " <type>bool</type> \n" 108 " <default>false</default> \n" 110 " <state value=\"false\">Disabled</state> \n" 111 " <state value=\"true\">Enabled</state> \n" 113 " <desc>Send log output to a file.</desc> \n" 115 " <setting xml:id=\"log-stdout-enabled\" group=\"log-output\"> \n" 116 " <name>Log To stdout</name> \n" 117 " <type>bool</type> \n" 118 " <default>true</default> \n" 120 " <state value=\"false\">Disabled</state> \n" 121 " <state value=\"true\">Enabled</state> \n" 123 " <desc>Send log output to stdout.</desc> \n" 125 " <setting xml:id=\"log-file-format\" group=\"log-output\"> \n" 126 " <name>Log File Format</name> \n" 127 " <type>choice</type> \n" 128 " <default>text</default> \n" 131 " <name>Plain Text</name> \n" 132 " <desc>Output simple utf8 text strings.</desc> \n" 133 " <value>text</value> \n" 136 " <name>XML</name> \n" 137 " <desc>Output XML-encoded log records.</desc> \n" 138 " <value>xml</value> \n" 141 " <name>JSON</name> \n" 142 " <desc>Output JSON-encoded log records.</desc> \n" 143 " <value>json</value> \n" 146 " <desc>Select the log record output format.</desc> \n" 148 " <setting xml:id=\"show-record-details\" group=\"log-input\"> \n" 149 " <name>Show Details</name> \n" 150 " <type>bool</type> \n" 151 " <default>false</default> \n" 153 " <state value=\"false\">Disabled</state> \n" 154 " <state value=\"true\">Enabled</state> \n" 156 " <desc>Include file name, line number and function with each log record.</desc> \n" 158 " <setting xml:id=\"timestamps-enabled\" group=\"log-input\"> \n" 159 " <name>Enable Timestamps</name> \n" 160 " <type>bool</type> \n" 161 " <default>false</default> \n" 163 " <state value=\"false\">Disabled</state> \n" 164 " <state value=\"true\">Enabled</state> \n" 166 " <desc>Include a timestamp with each log record.</desc> \n" 168 " <setting xml:id=\"thread-id-enabled\" group=\"log-input\"> \n" 169 " <name>Enable Thread Identifiers</name> \n" 170 " <type>bool</type> \n" 171 " <default>false</default> \n" 173 " <state value=\"false\">Disabled</state> \n" 174 " <state value=\"true\">Enabled</state> \n" 176 " <desc>Include a thread identifier with each log record.</desc> \n" 179 " </appsettings> \n";
191 m_logBuffer(nullptr),
192 m_logWorker(nullptr),
194 m_logSettings(nullptr),
195 m_profileSettings(nullptr),
196 m_syncProfiles(true),
197 m_loadingProfile(false),
198 m_LogSource(
"Zuble"),
199 m_originalMsgHandler(nullptr)
216 "Zbl::ZblLogManager::zInstance programming error: " 217 "Singleton ZblLogManager object already initialized!");
235 qDebug() <<
"Log worker object initial thread: " 238 QVariant vModules = qApp->property(
"org_zuble_logModules");
244 foreach(module,modules)
246 if(qobject_cast<ZblLogOutput*>(module))
247 qDebug() <<
"WE GOT SOMETHING!!!!";
249 if(qobject_cast<ZblLogTextFormatterIF*>(module))
250 qDebug() <<
"WE GOT A WINNER!!!!!";
259 qDebug() <<
"Log worker object background thread: " 264 Qt::BlockingQueuedConnection);
283 QLoggingCategory::setFilterRules(QStringLiteral(
"qml.debug=true"));
284 QLoggingCategory::setFilterRules(QStringLiteral(
"qml.info=true"));
285 QLoggingCategory::setFilterRules(QStringLiteral(
"qml.warning=true"));
286 QLoggingCategory::setFilterRules(QStringLiteral(
"qml.critical=true"));
293 static bool alreadyCalled =
false;
297 zDebug() <<
"Programming error - setApplicationObject must only be called once.";
301 alreadyCalled =
true;
316 zDebug() <<
"SETTINGS BUNDLE AVAILABLE: " << bundleId;
326 zDebug() <<
"Current log settings bundle available for id: " 336 zDebug() <<
"Updating application settings bundle";
354 zDebug() <<
"Updating log profile settings bundle";
378 QVariant vModules = qApp->property(
"org_zuble_logModules");
384 foreach(module,modules)
386 if(qobject_cast<ZblLogOutput*>(module))
387 qDebug() <<
"CREATING SETTINGS METADATA FOR LOG OUTPUT MODULE!!!!";
389 if(qobject_cast<ZblLogTextFormatterIF*>(module))
390 qDebug() <<
"OUTPUT FORMATTER!!!!!";
392 qDebug() <<
"OUTPUT TARGET!!!!!";
411 QString actualPath = logProfilePath;
413 if(logProfilePath.isEmpty())
415 qWarning() <<
"Zuble log manager can't locate applicaiton setting: " 416 "zuble/log-profile-path";
421 QVariant(
true)).toBool();
428 QFile logProfile(logProfilePath);
430 if(logProfile.exists())
432 if(!logProfile.copy(actualPath))
434 qWarning() <<
"Zuble log manager can't decouple log profile";
435 actualPath = logProfilePath;
448 if(filterRules.isNull())
464 const QString& nameTemplate,
468 QString logProfilePath;
472 if(!qDir.mkpath(logProfileDir))
474 qCritical() <<
"Zuble can't create log profile directory: " << logProfileDir;
476 logProfilePath = QDir::tempPath();
477 logProfilePath +=
'/';
481 logProfilePath = logProfileDir;
484 logProfilePath += nameTemplate;
487 qDebug() <<
"log profile path = " << logProfilePath;
489 QTemporaryFile temp(logProfilePath);
493 qWarning() <<
"Zuble can't open temporary log profile.";
497 logProfilePath = temp.fileName();
498 qDebug() <<
"temporary log profile = " << logProfilePath;
500 temp.setAutoRemove(
remove);
504 return logProfilePath;
509 bool logging =
false;
513 QStringList args(QCoreApplication::arguments());
514 const int argCount = args.length();
516 for(
int i=0; i<argCount; i++)
518 if(args.at(i) ==
"-zl")
529 bool ZblLogManager::updateMessageHandlerStatus()
531 bool captureLogMessages =
false;
535 QStringList args(QCoreApplication::arguments());
536 const int argCount = args.length();
538 for(
int i=0; i<argCount; i++)
540 if(args.at(i) ==
"-zl")
542 captureLogMessages =
true;
549 if(!captureLogMessages)
554 settings->value(
"zuble/enable-zuble-logging", captureLogMessages).toBool();
563 if(captureLogMessages)
566 return captureLogMessages;
574 "Zbl::ZblLogManager::zInstance programming error: " 575 "Singleton ZblLogManager object not initialized! " 576 "Call ZblLogManager::zInit before calling this method.");
582 const QMessageLogContext& logCtx,
585 bool fatal = msgType == QtFatalMsg ? true :
false;
594 QThread* thisThread = QThread::currentThread();
596 if(workerThread != thisThread)
610 QVariant zMsg = QVariant::fromValue<Zbl::ZblLogMessage>(msg);
614 Qt::ConnectionType conType = fatal ? Qt::BlockingQueuedConnection : Qt::QueuedConnection;
618 Q_ARG(QVariant, zMsg));
663 void ZblLogManager::appendModelColumn(
665 const QByteArray& columnName,
669 roles.insert(columnNumber, columnName);
678 QString actualName(logCategory);
682 if(logCategory.indexOf(
'.') != -1)
685 actualName.replace(
'.', QLatin1Char(
'$'));
687 zWarning() <<
"Logging category name: " << logCategory
688 <<
"can't contain the period character (dot \".\"), " 689 "converting name to: " << actualName;
692 zDebug() <<
"Registering log category: " << actualName;
706 QObject* p = parent ? parent :
m_zLog;
729 zCritical() <<
"Zuble programing error: log buffer role count mismatch!";
776 zDebug() <<
"LOGGER GOT CURRENT LOG PROFILE MODIFIED SIGNAL!";
788 value(
"zuble/enable-zuble-logging").toBool();
790 value(
"zuble/log-output-dir").toString();
795 value(
"log-output/log-file-enabled").toBool();
797 value(
"log-output/log-stdout-enabled").toBool();
799 value(
"log-histogram/histogram-enabled").toBool();
801 value(
"log-input/show-record-details").toBool();
803 value(
"log-output/log-file-format").toString().toLower());
812 qInstallMessageHandler(
nullptr);
814 QVariant vParams(QVariant::fromValue<ZblLogParams>(logParams));
816 QMetaObject::invokeMethod(
m_logWorker,
"setOutputParameters",
817 Qt::QueuedConnection,
818 Q_ARG(QVariant, vParams));
851 zDebug() <<
"LOGGER GOT ZUBLE SETTINGS MODIFIED SIGNAL!";
858 QVariant(
false)).toBool();
871 QString ZblLogManager::getLogRuleBooleanString(
int dataRole,
int rowNumber)
881 zCritical() <<
"Sorry, populateMetaRules method not yet implemented.";
894 qWarning() <<
"Log Manager can't load log profile: " << logProfileBundleID;
900 if(vFilterRules.isEmpty())
902 qWarning() <<
"Log Manager can't load current filter rules.";
908 QJsonObject filterRules = QJsonObject::fromVariantMap(vFilterRules);
910 if(filterRules.isEmpty())
912 qWarning() <<
"Log Manager can't locate previous filter rules.";
922 qWarning() <<
"Error loading current filter fules: " << ex.
message();
949 return QString(category +
'.' + level +
"=" 959 for(
int i = 0; i < categoryCount; i++)
964 QLoggingCategory::setFilterRules(rules);
971 qWarning() <<
"logging rule model already exists";
977 QQmlEngine::setObjectOwnership(ruleModel, QQmlEngine::CppOwnership);
989 const int roleCount = 7;
998 QList<int> roles = ruleModel->
roles();
1000 for(
int i=0; i<roleCount; i++)
1002 const int nextRole = roles.at(i);
1012 Qt::QueuedConnection);
1035 categoryRow.replace(0, QVariant(logCategory));
1072 QVariant rulesmap = ruleData.toVariantMap();
1085 const int categoryCount = zLogCategories.count();
1087 for(
int j=0; j<categoryCount; j++)
1094 qDebug() <<
"Begin dumping logging rule model.";
1099 qDebug() <<
"end dumping logging rule model.";
1107 if(logFileFormat ==
"json")
1111 else if(logFileFormat ==
"xml")
1113 zWarning() <<
"Sorry, XML log format not yet implemented. " 1114 "Using text format instead.";
1116 else if(logFileFormat !=
"text")
1118 zWarning() <<
"Invalid log format: " << logFileFormat <<
1119 "Should be one of: \"text\", \"json\". Using text format.";
void onSettingsBundleAvailable(QString bundleId)
Responds to newly loaded settings bundles.
The Zuble Log Manager is a singleton object that controls logging in Zuble applications.
static const QString m_profileMetadata
Log profile metadata defines logger settings that are stored in a log profile.
void tableModified(int dataRole, int rowNumber)
Sent when a table cell has been modified.
QString getFileName() const
Q_INVOKABLE void appendMissingRow(ZRoleRow roleRow, const QString &keyText, int keyColumn=0)
Appends the specified row if no rows contain the specified text in the specified column. Otherwise does nothing.
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
QAbstractTableModel override.
ZblLogWorker * m_logWorker
A background thread worker object to handle logging rules and log record output.
void populateRegisteredRules()
Appends all log categories that have so far been registered with a call to ZblLogManager::registerLog...
void updateApplicationSettings()
void setQtLogRulesFromModel()
Sets Qt's internal logging rules from data contained in log manager's logging rules model...
Q_INVOKABLE QObject * getLogBuffer()
Obtain the log buffer data model.
void onLogWorkerOutputParametersUpdated(QVariant logParams)
Synchronizes log manager and log worker output parameters.
static LogFileFormat fileFormatFromString(const QString &logFileFormat)
static ZblLogManager & zInit(QObject *parent)
Construct, initialize and obtain a reference to Zuble's log manager object.
QString toLiterallyTrue(bool value)
bool populateMetaRules()
Appends all log categories defined in the Zuble application's zblconfig.xml configuration file to the...
bool loadCurrentLogProfile()
Replaces the current log settings with those from the specified file.
Q_INVOKABLE QJsonObject getJsonData() const
Copies data from the table model into a newly created JSON object and returns it. ...
bool registerLogCategory(const QString logCategory)
Adds the specified log category to the registered log category list.
bool appendRuleModelCategory(const QString &logCategory)
Adds a new category to the rule model. If the category already exists in the rule model the request t...
int getRoleCount() const
Returns the number of roles defined for this model.
enum Zbl::logFileFormat LogFileFormat
Specifies the output format for Zuble log files.
Q_INVOKABLE void truncate(int rowCount, bool removeFromFront=false)
void setApplicationObject(ZApplication *appObject)
Connects the log manager to appropriate Zuble core plugin signals and attempts to load the current lo...
#define ZBL_REGISTER_LOGGED_OBJECT
Q_INVOKABLE void dumpModelData() const
dumps diagnostic information about the model to the debug output.
static int m_maxBufferSize
The number of logging records the circular log buffer will attempt to hold.
bool m_loadingProfile
true when log manager is currently loading a log profile, false otherwise
LogFileFormat m_fileFormat
The current logger output file format.
bool loadFilterRules(const QString &logProfileBundleID)
Loades the log filter rules from the specified log profile into the log rule model.
void outputParametersUpdated(QVariant logParams)
const QString & message() const
void onRuleModelModified(int dataRole, int rowNumber)
Responds to changes in the rule model by updating Qt's internal rule model and the current log settin...
Q_INVOKABLE bool setFileWatcher(bool enabled)
Enables or disables the file system watcher. This method must be called to enable this object to emit...
ZDataRow m_modelBooleanRow
A data row to use as a template for constructing role rows.
ZDataRow m_modelCategoryRow
A data row to use as a template for constructing role rows.
void updateLogProfileSettings()
Loads a new copy of the log profile settings from the settings file.
Q_INVOKABLE QList< int > roles() const
Determines which roles are in the data set. This method may block the current thread.
ZblLogParams m_logParam
Current Zuble logging parameters.
Q_INVOKABLE QVariant getValue(int role, int row)
Obtains the value of the specified data cell.
static bool containsBundle(const QString &id)
bool m_enableModelOutput
Enables log output to log histogram buffer.
logFileFormat
Specifies the output format for Zuble log files.
ZBL_DECLARE_LOGGED_OBJECT QString getQtLogRule(const QString &category, const QString &level, bool enabled)
Returns a Qt logging rule string for the given log category and level.
static ZblLogManager & zInstance()
Obtain a reference to Zuble's log manager object.
ZTableModel * createLogBufferModel(QObject *parent=NULL)
Creates a new log record data model by appending the appropriate data rules. The caller assumes owner...
QMap< int, QList< QVariant > > ZRoleRow
Represents a single row (or column for column headers) of data cell values for multiple roles...
#define ZBL_SLOT_BEGIN_TRY
Abstract base class for Zuble log output modules.
static const QString m_defaultOutputFilePath
TBD: currently unused!
#define ZBL_DEFINE_LOGGED_OBJECT(class_name)
void settingsModified(const QString &path)
Sent whenever the settings file is modified by this or other programs.
ZTableModel * m_logBuffer
Zuble's log buffer provides a viewable record of recent log activity.
This two dimensional table model is used to store and manipulate data.
Q_INVOKABLE QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
ZTableModel * m_logRules
A data model containing the current logging rules in effect for each known log category.
QString m_logOutputDir
Directory in which log files are created.
void saveFilterRules()
Saves the current state of the logging rules data model to the current log profile.
QString getQtLogRulesForRow(int rowNumber)
Returns a Qt logging rule string for all logging levels for the specified row (log category) in the l...
virtual void timerEvent(QTimerEvent *event)
Timer is used to flush excess log records from the log record buffer.
Q_INVOKABLE int getLogBufferRoleCount()
Obtain the number of roles in the log buffer data model.
This class contains the Zuble logging parameters that control log output.
bool m_syncProfiles
true if all application instances update the same log profile, false if each instance updates a separ...
static const QString m_zubleSettingsBundleId
The bundle ID for the zuble application settings = "default".
Q_INVOKABLE void putJsonData(QJsonObject data)
Writes data from the specified JSON object into the data table. Previous contents of the data table a...
void settingsBundleAvailable(QString bundleId)
This signal is sent by the settings bundle manager when an application settings bundle is added to th...
static QString getObjectThreadAddress(QObject *object)
Returns the human-readable memory address of the specified object's thread.
bool startLogThread()
Starts log manager's background thread.
void onLogProfileModified(const QString &path)
Responds to changes to the current log settings by replacing the log profile with the current log set...
static QString createTemporaryLogProfile(const QString &nameTemplate, bool remove=false)
Creates an empty file with a unique file name in the log profile directory.
QHash< int, QByteArray > ZRoleNames
Maps role numbers to role names as a hash table object.
void onZubleSettingsModified(const QString &path)
Responds to changes in the Zuble application settingsby updating log manager's internal state...
static QString resolvePath(const QString &path, bool includeUrlScheme=true)
Converts relative file paths into canonical file paths. Paths prefixed with prefix are mapped relativ...
Q_INVOKABLE void setColumnCount(int count)
Sets the number of columns the table will contain. This method may block the current thread...
bool inObjectThread(const QObject &object)
Zuble's Singleton Application Object.
static ZblLogManager * m_zLog
The one and only ZblLogManager object in this process.
Zuble objects embed this class to save local logging state.
#define LOCK_ZLOGCATEGORIES
void stopLogThread()
Stops log manager's background thread.
bool zInit(const QString &logSource, ZTableModel *logBuffer)
Initializes the ZblLogWorker object. This method should be called after the ZblLogWorker object has b...
bool m_enableFileOutput
Enables log output to file.
friend class ZblLogWorker
static const int m_logBufRoleCount
The number of roles contained in a log file record.
Zuble's Qt Exception Object.
static QString getCurrentThreadAddress()
Returns the human-readable memory address of the current thread.
bool m_flush
true = flush output buffers and close streams before returning (used for fatal/abort messages) ...
QScopedPointer< ZSettings > ZScopedSettings
static QString getLogSettingsMetadata()
Returns an xml data structure that defines the zuble application's log settings.
static void zMessageHandler(QtMsgType msgType, const QMessageLogContext &logCtx, const QString &text)
Zuble's Qt message handler.
static ZSettings * getBundleSettings(const QString &id)
Returns the ZSettings object for the specified settings bundle ID. Caller takes ownership of the ZSet...
ZSettings * m_logSettings
A ZSettings object to track the application settings for changes that control Zuble logging...
QString m_LogSource
String inserted into the "source" field of log records.
bool createRuleModel()
Creates the log manager's log rules data model and initializes associated variables used to optimize ...
ZSettings * m_profileSettings
A ZSettings object to track the current log profile for changes to the profile settings.
static void registerLogCategory()
ZblLogManager(QObject *parent=0)
Q_INVOKABLE bool addRole(int roleNumber)
Adds the specified role to the data model. This method may block the current thread.
bool m_enableLogging
Enables Zuble logging.
ZRoleRow m_modelRoleRow
A role row to use as a template for adding logging rules to the rule model.
bool isCommandLineLogging()
Returns true if -zl option is passed in on command line.
Q_INVOKABLE void sync()
Blocks thread until model's event queue has been processed.
QList< ZblLogOutput * > zLogModuleList
static bool insertBundle(const QString &id, const QString &metaPath, QSettings::Scope scope=QSettings::UserScope, const QString organization=QString(), const QString application=QString())
Adds the specified settings bundle to the settings repository.
This class is used to transfer log messages between threads.
static const QString m_logFilterRulesKey
The log filter rules key = "log-filter-rules".
#define ZBL_SLOT_END_RETURN(return_success, return_failed, facility, code, error_message)
bool m_enableStdOutput
Enables log output to stdout.
QThread m_logThread
A background thread to handle logging rules and log record output.
QList< QVariant > ZDataRow
Represents a single row (or column for column headers) of data cell values for a single role...
static const QString m_currentLogSettingsBundleId
The bundle ID for the current logging profile = "current-log-profile".
bool m_enableDetails
Logs will include detailed debugging information.
int m_timerID
ID for the log manager's event timer.
Q_INVOKABLE QObject * getLogRules()
Obtain the logging rules data model.
void setLogOutputParameters()
Gathers the application and log profile settings that affect log output and synchronizes those parame...