Evgenii Legotckoi
Evgenii LegotckoiМаусым 5, 2016, 8:28 Т.Ж.

Qt/C++ - 050-сабақ. Qt қолданбасының оқиғаларын мәтіндік файлға тіркеу

Барлық Qt әзірлеушілері Qt қолданбасын жөндеу кезінде qDebug() пайдаланады, бірақ сонымен қатар qInfo(), qWarning(), qCritical() және qFatal() макростары бар (олар мақаланы жазу уақыты қателермен болды және жұмыс істемеді).

Осы оқиғалардың көмегімен қателерді маңыздылық деңгейлері бойынша санаттауға және қандай қателер туралы хабарлану керек және қайсысы болмауы керек екенін бөлу үшін сүзгілерді қолдануға болады.

Қате туралы хабарларды мәтіндік файлға қайта бағыттау үшін қолданбада CallBack-функциясы өңдеушісін орнату керек. Ол үшін qInstalMessageHandler функциясы пайдаланылады.

Өңдеуші қолтаңбасы келесідей болуы керек:

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

Бұл функция арқылы біз келесі деректерді аламыз:

  1. QtMsgType түрі - Хабар түрі
  2. QtInfoMsg
  3. QtDebugMsg
  4. QtWarningMsg
  5. QtCriticalMsg
  6. QtFatalMsg
  7. QMessageLogContext &context - хабарламаның контексі, оның ішінде ең пайдалысы хабар категориясы. Бұл кодтағы хабарламаның орнын анықтау қажет болғанда пайдалы болуы мүмкін, яғни біз деректерді қай құрамдас бөліктерден аламыз немесе хабарлама қандай өзара әрекеттестік түріне жатады.
  8. 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

Өңдеушіні орнату

Өңдеуші қалай жұмыс істейтінін көрсету үшін төрт түймесі бар графикалық қолданбаны қолданайық.

  • Түзету
  • Ақпарат
  • Ескерту
  • Критикалық

Түймелердің әрқайсысының өңдегішінде сәйкес оқиғаларды тіркеу макростары шақырылады және жоғарыда аталған сәйкес санаттар қолданылады. Қолданба терезесі графикалық дизайнер арқылы жасалады және келесідей көрінеді.

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 қолданбасын жүктеп алу

Бейне оқулық

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

C
  • Қаң. 21, 2017, 5:51 Т.Ж.

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

Evgenii Legotckoi
  • Қаң. 21, 2017, 8:35 Т.Ж.

Добрый день

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

И
  • Там. 15, 2017, 7:08 Т.Ж.

Важно упомянуть, что QLoggingCategory в QT начиная с 5 версии.

Evgenii Legotckoi
  • Там. 15, 2017, 7:10 Т.Ж.

А кто-то ещё использует Qt4? )))

И
  • Там. 15, 2017, 7:14 Т.Ж.

Мало ли ) Мне для взаимодействия с библиотеками Octave приходится)

Evgenii Legotckoi
  • Там. 15, 2017, 7:23 Т.Ж.

Это который GNU Octave? Сочувствую тогда... в Qt5 много полезный вкусностей.

И
  • Там. 15, 2017, 7:40 Т.Ж.

Он самый

Evgenii Legotckoi
  • Там. 15, 2017, 7:44 Т.Ж.

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

Ruslan Polupan
  • Қаз. 28, 2017, 4:23 Т.Ж.

Как здесь кириллицу корректно использовать?

Q_LOGGING_CATEGORY(logWarning,  "Предупреждение")
Evgenii Legotckoi
  • Қаз. 28, 2017, 6:06 Т.Ж.

Фух фух фух.... не люблю я для таких вещей кириллицу использовать ;-)

Но может Вам поможет вот этот топик .
Здесь скорее всего нужно правильно с кодировкой поколдовать.
p
  • Шілде 18, 2018, 8:45 Т.Ж.

А что мешает сохранить адрес дефолтного обработчика и после вывода в файл вызывать и его?

Evgenii Legotckoi
  • Шілде 18, 2018, 10:56 Т.Ж.

Хм.. Как-то даже не подумал ))

b
  • Там. 1, 2019, 1:57 Т.Ж.

таки да, используется, причем активно

b
  • Там. 1, 2019, 1:58 Т.Ж.

таки да. используется

Evgenii Legotckoi
  • Там. 1, 2019, 3:14 Т.Ж.

Мне видимо нужно было добавить тег /sarcasm ?
Всем ясно, что legaci есть и будет, но это не значит, что я, например, добровольно полезу болото месить.

МА
  • Маусым 3, 2020, 11:13 Т.Ж.

Вопрос- как перенести из файла .cpp

// Умный указатель на файл логирования
QScopedPointer<QFile>   m_logFile;
// Объявляение обработчика
void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);

Эти записи?
Если их помещаю как private, то ошибка.
Или обработчик messageHandler должен именно вне класса быть? Хочу его методом класса сделать.
А так- работает.

МА
  • Маусым 3, 2020, 12:40 Т.Қ.

Как только переношу в класс метод messageHandler, он подчеркнут ошибкой в конструкторе:

qInstallMessageHandler(messageHandler);

Сам метод в классе называется уже:

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

с расширение названия класса.
И не пойму как в класс его затулить.

Evgenii Legotckoi
  • Маусым 3, 2020, 5:33 Т.Қ.

Этот обработчик должен быть отдельной функцией.
Не стоит его пытаться запихать в класс.
Как бы скорее всего это возможно, но это тухлого яйца не стоит.

МА
  • Маусым 4, 2020, 3:53 Т.Ж.

Отдельной ф-ей вне класса?
А если у меня еще класс будет, откуда я буду его использовать? То эту же ф-ю вызывать надо будет? Просто extern ее пробросить в то место, где вызываю?

Evgenii Legotckoi
  • Маусым 4, 2020, 4 Т.Ж.

Этот обработчик вызывается автоматически при вызове qDebug(), qWarning() и т.д.
Зачем вам вообще это куда-то пробрасывать?
Нет никакого смысла использовать класс. А даже если и будет класс, то метод должен быть статическим. Бессмысленная затея.

МА
  • Маусым 4, 2020, 4:21 Т.Ж.
    // настройка логгера
    // Устанавливаем файл логирования,
    m_logFile.reset(new QFile("logFile.txt"));
    // Открываем файл логирования
    m_logFile.data()->open(QFile::Append | QFile::Text);
    // Устанавливаем обработчик
    qInstallMessageHandler(messageHandler);

Это делаю в конструкторе класса. Если у меня два класса, откуда я хочу логгирование, то дважды вставляем в конструкторы инициализацию?
Или как правильней поступить?

МА
  • Маусым 4, 2020, 4:24 Т.Ж.

И вопрос по приватной переменной
QLoggingCategory m_category;
где в конструкторе она инициализируется- с каждым классом так проделывать?

Evgenii Legotckoi
  • Маусым 4, 2020, 4:37 Т.Ж.

Это глобальный логгер, а не для отдельных классов. Он один раз устанавливается в main функции.

Evgenii Legotckoi
  • Маусым 4, 2020, 4:38 Т.Ж.

В статье уже есть ответ на этот вопрос

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

МА
  • Маусым 4, 2020, 4:48 Т.Ж.

Эксперимент показал, что инициализация в конструкторе main достаточна. Дальше в конструкторе каждого класса делаю инициализацию приватной переменной m_category(" название класса:")
И уже в логгере отображается
2020-06-04 11:43:57.192 MainWindow: : Button Customers_clicked

Т.о. можно делать разделение по классам.

Разобрался, спасибо.

Отдельно отмечу, что ваш блог помогает разобраться с вопросами по Qt, отдельная благодарность)

AC
  • Маусым 24, 2023, 8:26 Т.Ж.

"И присвоим имена данным категориям "

Я правильно понимаю, что такие имена документация присваивать не рекомендует?
"Avoid the category names: debug, info, warning, and critical."

Evgenii Legotckoi
  • Маусым 24, 2023, 8:56 Т.Ж.

Условно да, для примера не важно, но больше выглядит как набор рекомендаций, который говорит о том, что в итоге что-то может пойти не так и вы сами себе злобные Буратины.

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 6:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 25, 2024, 1 Т.Ж.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 5:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

Бізді әлеуметтік желілерде бақылаңыз