Реклама

Qt/C++ - Урок 050. Логирование событий Qt приложения в текстовый файл

РуководствоQtfile, log, Logger, qDebug, qFatal, qInfo, qWarning, Логирование5510

Все Qt-разработчики используют qDebug(), когда отлаживают приложение, написанное на Qt, но также имеются макросы qInfo(), qWarning(), qCritical() и qFatal() (который на момент написания статьи был с ошибками и не работал).

С помощью этих событий, вы можете разделить ошибки по уровням значимости и применить фильтры, для разделения того, какие ошибки нужно выводить, а какие нет.

Для перенаправления сообщений об ошибках в текстовый файл, вам необходимо установить CallBack-функцию обработчик в приложение. Для этого используется функция qInstalMessageHandler .

Сигнатура обработчика должна выглядеть следующий образом:

void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);

Через эту функцию мы будем получать следующие данные:

  1. QtMsgType type - Тип сообщения
    1. QtInfoMsg
    2. QtDebugMsg
    3. QtWarningMsg
    4. QtCriticalMsg
    5. QtFatalMsg
  2. QMessageLogContext &context - контекст сообщения, самое полезное в котором - это категория сообщения. Это может быть полезным, когда необходимо определить местоположение сообщения в коде, то есть из каких компонентов мы получаем данные или к какому типу взаимодействия относится сообщение.
  3. QString &msg - передаваемое сообщение об ошибке.

Дополнительные категории - QLoggingCategory

Дополнительные категории являются объектами класса QLoggingCategory. Может быть несколько подходов к работе с категориям, например, мы можем создать категорию объекта в каком-либо классе и передать его в сообщение об ошибке:

QLoggingCategory  m_category("Test");
qDebug(m_category) << "Check it";

Получим следующий вывод:

Test: Check it

Неудобство данного подхода заключается в том, что несколько классов могут иметь одни и те же категории ошибок, но в каждом классе необходимо создавать одни и те же категории. Поэтому воспользуемся другим подходом. А именно регистрацией категории через макрос.

LoggingCategories.h

Мы объявим четыре категории в данном заголовочном классе.

#ifndef LOGGER_H
#define LOGGER_H

#include <QLoggingCategory>

Q_DECLARE_LOGGING_CATEGORY(logDebug)
Q_DECLARE_LOGGING_CATEGORY(logInfo)
Q_DECLARE_LOGGING_CATEGORY(logWarning)
Q_DECLARE_LOGGING_CATEGORY(logCritical)

#endif // LOGGER_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")

Использование LoggingCategories

Для того, чтобы применить данные категории, вы должны подключить заголовочный файл в тот файл, где будут использоваться данные категории. И затем использовать их:

qDebug(logDebug()) << "Check it";

Получим следующий вывод:

Debug: Check it

Установка обработчика

Для демонстрации работы обработчика воспользуемся графическим приложением, в котором будет четыре кнопки.

  • Debug
  • Info
  • Warning
  • Critical

В обработчике каждой из кнопок будут вызываться соответствующие макросы логирования событий и применяться соответствующие категории, перечисленные выше. Окно приложение создано через графический дизайнер и выглядит следующим образом.

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_debugButton_clicked();
    void on_infoButton_clicked();
    void on_warningButton_clicked();
    void on_criticalButton_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

#include "LoggingCategories.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_debugButton_clicked()
{
    qDebug(logDebug()) << "Debug Button";
}

void MainWindow::on_infoButton_clicked()
{
    qInfo(logInfo()) << "Info Button";
}

void MainWindow::on_warningButton_clicked()
{
    qWarning(logWarning()) << "Warning Button";
}

void MainWindow::on_criticalButton_clicked()
{
    qCritical(logCritical()) << "Critical Button";
}

main.cpp

#include "mainwindow.h"
#include <QApplication>
#include <QFile>
#include <QDir>
#include <QScopedPointer>
#include <QTextStream>
#include <QDateTime>
#include <QLoggingCategory>

// Умный указатель на файл логирования
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("C:/example/logFile.txt"));
    // Открываем файл логирования
    m_logFile.data()->open(QFile::Append | QFile::Text);
    // Устанавливаем обработчик
    qInstallMessageHandler(messageHandler);

    MainWindow w;
    w.show();

    return a.exec();
}

// Реализация обработчика
void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    // Открываем поток записи в файл
    QTextStream out(m_logFile.data());
    // Записываем дату записи
    out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz ");
    // По типу определяем, к какому уровню относится сообщение
    switch (type)
    {
    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;
    }
    // Записываем в вывод категорию сообщения и само сообщение
    out << context.category << ": "
        << msg << endl;
    out.flush();    // Очищаем буферизированные данные
}

Итог

В результате логирования событий будет создан файл C:\example\logFile.txt (Примечание. Но только если перед запуском приложения папка C:\example уже существовала).

При нажатии кнопок в окне приложения содержимое файла будет выглядеть следующим образом:

2016-06-04 17:05:57.439 DBG Debug: Debug Button
2016-06-04 17:05:57.903 INF Info: Info Button
2016-06-04 17:05:58.367 WRN Warning: Warning Button
2016-06-04 17:05:58.815 CRT Critical: Critical Button

Скачать Qt приложение с логированием в текстовый файл

Видеоурок

Реклама

Комментарии

Добрый день. А как сделать, что бы ещё и в консоль выводилось?

Добрый день

Многого хотите ))) Установка обработчика же как раз для того, чтобы перенаправить вывод qDebug в файл.
Вывод здесь забирается и перенаправляется в файл. Но если так сильно хочется выводить в консоль, то используйте std::cout в обработчике сообщений.

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
Последние комментарии
  • EVILEG
  • 13 июля 2017 г. 2:12

Qt/C++ - Урок 023. Перетаскивание QGraphicsItem на QGraphicsScene мышью

Ну например так можете сделать.void MoveItem::mousePressEvent(QGraphicsSceneMouseEvent *event){ if (QApplication::mouseButtons() == Qt::RightButton) { this->deleteLa...

  • Mark
  • 13 июля 2017 г. 1:26

Qt/C++ - Урок 023. Перетаскивание QGraphicsItem на QGraphicsScene мышью

Подскажите пожалуйста как в данном проекте по перетаскиванию организовать удаление объекта со scene методом delete item, допустим при щелчке ПКМ по объекту QGraphicsScene. Мои попытки оказалис...

  • EVILEG
  • 10 июля 2017 г. 21:34

Qt/C++ - Урок 048. QThread - работа с потоками с помощью moveToThread

А что делали? Повторяете урок или как? Пытались просто скачать проект в конце статьи и запустить?

Qt/C++ - Урок 048. QThread - работа с потоками с помощью moveToThread

У меня происходит переполнение счетчика count, появляется ошибка malloc(): memory corruption (fast). Не подскажите, как с этим бороться?

  • EVILEG
  • 9 июля 2017 г. 2:07

GameDev на Qt - Урок 3. Уничтожение противников

Поэтому в пятом уроке есть исходники всего проекта )))). Вообще, все эти материалы были не предыдущей версии сайта, которая на WordPress. Во время переноса мог что-то потерять.

Сейчас обсуждают на форуме

тестирование классов в QT

это вопрос.

Как реализовать отправку e-mail

Возможно что уже и нет необходимости в почтовом клиенте, но в своё время так же столкнулся с данной проблемой в QT. Нашел один интересный проект под названием libqxt, там реализовано дов...

  • Asteri
  • 14 июля 2017 г. 12:23

css

Делюсь, может, пригодится когда-нибудь) QTableView QHeaderView { background-color: #ffffff; } Вот так эта проблема лечится, градиент задать не получается, но хоть...

  • EVILEG
  • 12 июля 2017 г. 19:52

QSqlQuery выполнение sql запросов из файла

Мне думается, что это уже будет дело вкуса и вашего взгляда на проект. Если Вы действительно собираетесь просто скармливать своему софту SQL скрипты, которые должны будут выполняться для...

QML Canvas + Line. Bug?

Вот оно что, значит не баг) Спасибо