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

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

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
OI
  • Ora Iro
  • Жел. 24, 2024, 6:38 Т.Ж.

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

  • Нәтиже:40ұпай,
  • Бағалау ұпайлары-8
AD

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

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

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

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
Соңғы пікірлер
ИМ
Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEҚаз. 19, 2024, 8:19 Т.Ж.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectМаусым 4, 2022, 3:49 Т.Ж.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimҚаз. 25, 2024, 9:10 Т.Ж.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

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