Logging-Setup
Durch die Protokollierung der Unterstützung in der Anwendung können Sie mindestens die folgenden Aufgaben lösen:
- Korrigieren von Benutzeraktionen in der Anwendung;
- Festlegen der Ausführung von Operationen mit Daten;
- Behebung kritischer Ereignisse während des Programmbetriebs.
Und im Allgemeinen ist das Auslesen von Protokollen ein spannender und spannender Prozess, der gleichzeitig den Betrieb der Software unterstützt.
Ich habe die Organisation der Protokollierung von Anwendungsereignissen aus diesem Artikel übernommen. Leichte Änderung der Handler-Implementierung, sodass Nachrichten im Konsolenfenster dupliziert werden.
Wir fügen dem Projekt über ein Makro die Registrierung von Protokollierungskategorien hinzu.
loggingcategories.h
#ifndef LOGGINGCATEGORIES_H #define LOGGINGCATEGORIES_H #include <QLoggingCategory> Q_DECLARE_LOGGING_CATEGORY(logDebug) Q_DECLARE_LOGGING_CATEGORY(logInfo) Q_DECLARE_LOGGING_CATEGORY(logWarning) Q_DECLARE_LOGGING_CATEGORY(logCritical) #endif // LOGGINGCATEGORIES_H
loggingcategories.cpp
#include "loggingcategories.h" Q_LOGGING_CATEGORY(logDebug, "Debug") Q_LOGGING_CATEGORY(logInfo, "Info") Q_LOGGING_CATEGORY(logWarning, "Warning") Q_LOGGING_CATEGORY(logCritical, "Critical")
main.cpp ändern.
main.cpp
#include "mainwindow.h" #include "LoggingCategories/loggingcategories.h" #include <QApplication> #include <QFile> #include <QDateTime> // Умный указатель на файл логирования static QScopedPointer<QFile> m_logFile; // Объявление обработчика void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); int main(int argc, char *argv[]) { QApplication a(argc, argv); // Устанавливаем файл логирования m_logFile.reset(new QFile("iMpos.log")); // Открываем файл логирования m_logFile.data()->open(QFile::Append | QFile::Text); // Устанавливаем обработчик qInstallMessageHandler(messageHandler); qInfo(logInfo()) << "Запуск программы."; MainWindow w; w.show(); return a.exec(); } void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { // Открываем поток записи в файл QTextStream out(m_logFile.data()); QTextStream console(stdout); // Записываем дату записи out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz "); // По типу определяем, к какому уровню относится сообщение switch (type) { #ifdef QT_DEBUG case QtInfoMsg: out << "[INF] "; console << "Info: " << msg << endl; break; case QtDebugMsg: out << "[DBG] "; console << "Debug: " << msg << endl; break; case QtWarningMsg: out << "[WRN] "; console << "Warning: " << msg << endl; break; case QtCriticalMsg: out << "[CRT] "; console << "Critical: " << msg << endl; break; case QtFatalMsg: out << "[FTL] "; console << "Fatality: " << msg << endl; break; #else case QtInfoMsg: out << "[INF] "; break; case QtDebugMsg: out << "[DBG] "; break; case QtWarningMsg: out << "[WRN] "; break; case QtCriticalMsg: out << "[CRT] "; break; case QtFatalMsg: out << "[FTL] "; break; #endif } // Записываем в вывод категорию сообщения и само сообщение out << context.category << ": " << msg << endl; // Очищаем буферизированные данные out.flush(); console.flush(); }
Wir starten das Programm. Protokollmeldungen werden in der Konsole angezeigt.
Im Assembly-Ordner des Projekts wurde eine iMpos.log-Datei erstellt
Datenbank mit Anwendungseinstellungen erstellen und lesen
Wir werden eine SQLite-Datenbank verwenden, um Anwendungseinstellungen und andere Daten zu speichern. Sobald wir beginnen, Datenbanken zu verwenden, müssen wir den Parameter qmake QT += sql zur Projektdatei hinzufügen.
QT += core gui sql
Hinzufügen der DataBases-Klasse zum Projekt
Datenbanken.h
#ifndef DATABASES_H #define DATABASES_H #include <QObject> class DataBases : public QObject { Q_OBJECT public: explicit DataBases(QObject *parent = nullptr); bool connectOptions(); //Подключение к базе данный опций приложения signals: public slots: }; #endif // DATABASES_H
Datenbanken.cpp
#include "databases.h" #include "LoggingCategories/loggingcategories.h" #include <QFile> #include <QSqlQuery> #include <QSqlError> #define DATABASE_NAME "iMpos.opt" #define DATABASE_HOSTNAME "iMpos" DataBases::DataBases(QObject *parent) : QObject(parent) { } bool DataBases::connectOptions() { bool result; //Проверяемналичие файла базы данных if(QFile(DATABASE_NAME).exists()){ //Файл существует создаем подключение к базе данных qInfo(logInfo()) << "Открываем файл настроек приложения."; QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE","options"); db.setHostName(DATABASE_HOSTNAME); db.setDatabaseName(DATABASE_NAME); if(db.open()){ qInfo(logInfo()) << "Файл настроек открыт успешно"; result = true; } else { qCritical(logCritical()) << "Не удалось открыть файл настроек приложения."; result = false; } } else { //Файл отсутсвует, создем базу данных QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE","options"); db.setHostName(DATABASE_HOSTNAME); db.setDatabaseName(DATABASE_NAME); if(db.open()){ QStringList listSQL; //Список запросов QSqlQuery q = QSqlQuery(db); //Создаем таблицу OPTIONS и добавлем в нее записи listSQL << "CREATE TABLE `options` (`option_id` INTEGER NOT NULL, `value` TEXT NOT NULL, `comment` TEXT, PRIMARY KEY(`option_id`))"; listSQL << "INSERT INTO `options`(`option_id`,`value`,`comment`) VALUES (1000, 'false', 'Использовать аутентификацию')"; listSQL << "INSERT INTO `options`(`option_id`,`value`,`comment`) VALUES (1010, 'false', 'Использовать привязку по региону')"; //Создаем таблицу пользователей приложения и добавляем в нее запись listSQL << "CREATE TABLE `users` ( `user_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `fio` TEXT NOT NULL, `password` TEXT, `isactive` TEXT NOT NULL DEFAULT 'true' )"; listSQL << "INSERT INTO `users`(`fio`,`password`) VALUES ('Администратор','masterkey')"; //Выполняем запросы for (int i =0;i<listSQL.size();++i) { if(!q.exec(listSQL.at(i))) qCritical(logCritical()) << Q_FUNC_INFO << "Не удалось выполнить запрос." << listSQL.at(i) << q.lastError().text(); } qInfo(logInfo()) << "Создан файл настроек приложения."; result = true; } else { qCritical(logCritical()) << "Не удалось создать файл настроек приложения."; result = false; } } return result; }
Fügen Sie in main.cpp vor dem Exportieren des Hauptfensters hinzu
DataBases *db = new DataBases(); if(!db->connectOptions()){ qInfo(logInfo()) << "Аварийное завершение работы."; return 1; }
Die iMpos.opt-Datei wird bei der ersten Ausführung im Projekt-Build-Ordner angezeigt
Beim nächsten Start stellt es eine Verbindung zu einer vorhandenen SQLite-Datenbank her.
Aktueller Projektstatus auf GitHub hier.
Projektarchiv.
iMpos_ch003.zip
Я с некоторых пор перестал использовать вот такие дефайны (знаю, что в моих статьях попадаются, но это в старых статьях)
Сейчас пишу так
Header
CPP
Дело в том, что если изменить этот дефайн
То будут перекомпилироваться абсолютно все места в проекте, где он использовался. А в случае со статическими константными переменными будет перекомпилироваться только DataBaseSettings. Это даёт очень большой выигрыш по времени перекомпиляции в очень крупных проектах при частом использовании тех или иных переменных подобного рода.
Спасибо. Возьму на заметку.