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 Т.Ж.

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

Пікірлер

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

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:50ұпай,
  • Бағалау ұпайлары-4
m
  • molni99
  • Қаз. 26, 2024, 8:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
m
  • molni99
  • Қаз. 26, 2024, 8:29 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:20ұпай,
  • Бағалау ұпайлары-10
Соңғы пікірлер
i
innorwallҚар. 14, 2024, 7:42 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады If only females relatives with DZ offspring were considered these percentages were 23 order priligy online uk
i
innorwallҚар. 14, 2024, 5:09 Т.Қ.
Qt/C++ - 068-сабақ. CLion жүйесінде CMAKE құрастыру жүйесін пайдаланатын Hello World ditropan pristiq dosing With the Yankees leading, 4 3, Rivera jogged in from the bullpen to a standing ovation as he prepared for his final appearance in Chicago buy priligy pakistan
i
innorwallҚар. 14, 2024, 12:05 Т.Қ.
ЖАМАНДЫҚ ЯРЕК. Google reCAPTCHA пайдалану 2001; 98 29 34 priligy buy
Енді форумда талқылаңыз
i
innorwallҚар. 14, 2024, 11:39 Т.Ж.
добавить qlineseries в функции priligy amazon canada 93 GREB1 protein GREB1 AB011147 6
i
innorwallҚар. 11, 2024, 6:55 Т.Қ.
Всё ещё разбираюсь с кешем. priligy walgreens levitra dulcolax carbs The third ring was found to be made up of ultra relativistic electrons, which are also present in both the outer and inner rings
9
9AnonimҚаз. 25, 2024, 4:10 Т.Қ.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

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