কিভাবে qDebug, qWarning, qCritical ইত্যাদি আউটপুট পুনর্নির্দেশ করবেন?


85

আমি qDebug() <<ডিবাগ আউটপুট জন্য প্রচুর বিবৃতি ব্যবহার করছি । শেল স্ক্রিপ্টগুলির অবলম্বন না করেই কোনও ডিফল্ট আউটপুট কোনও ফাইলে পুনর্নির্দেশ করতে পারি এমন কোনও ক্রস-প্ল্যাটফর্ম উপায় আছে কি? আমি অনুমান করছি যে ওপেন () এবং ডুপ 2 () লিনাক্সে কাজ করবে তবে এটি কি উইন্ডোজে MinGW এর সাথে সংকলিত কাজ করবে?

এবং এটি করার একটি Qt উপায় আছে?

উত্তর:


121

আপনাকে qInstallMsgHandlerফাংশন ব্যবহার করে একটি বার্তা হ্যান্ডলার ইনস্টল করতে হবে এবং তারপরে, আপনি কোনও ফাইলে ডিবাগ বার্তা QTextStreamলিখতে ব্যবহার করতে পারেন । এখানে একটি নমুনা উদাহরণ:

#include <QtGlobal>
#include <stdio.h>
#include <stdlib.h>

void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QByteArray localMsg = msg.toLocal8Bit();
    switch (type) {
    case QtDebugMsg:
        fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        break;
    case QtInfoMsg:
        fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        break;
    case QtWarningMsg:
        fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        break;
    case QtCriticalMsg:
        fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        break;
    case QtFatalMsg:
        fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        abort();
    }
}

int main(int argc, char **argv)
{
    qInstallMessageHandler(myMessageOutput); // Install the handler
    QApplication app(argc, argv);
    ...
    return app.exec();
}

এর দস্তাবেজ থেকে নেওয়া qInstallMsgHandler(আমি কেবল মন্তব্যগুলি যুক্ত করেছি):

উপরের উদাহরণে, ফাংশনটি myMessageOutputব্যবহার করে stderrযা আপনি অন্য কোনও ফাইল স্ট্রিমের সাথে প্রতিস্থাপন করতে বা ফাংশনটি সম্পূর্ণ নতুন করে লিখতে চাইতে পারেন!

একবার আপনি লিখতে এবং এই ফাংশন ইনস্টল করুন, সব আপনার qDebug(সেইসাথে qWarning, qCriticalইত্যাদি) বার্তাগুলি হ্যান্ডলার করা তুমি লেখা ফাইল থেকে আপনাকে পুনঃনির্দেশিত করা হবে।


4
আরে, অনেক ধন্যবাদ এটি কেবল আমাকে কোনও ফাইলে ডিবাগ আউটপুট পুনঃনির্দেশ করতে দেয় না, এটি আমাকে টাইমস্ট্যাম্পের মতো আরও দরকারী তথ্যও মুদ্রণ করতে সক্ষম করে
তোলে

4
@ সেপ্টগ্রাম: হুবহু আপনি হ্যান্ডেল্ডারে নিজেই কিছু দরকারী বার্তা যুক্ত করতে পারেন; এবং আপনি বিভিন্ন ফাইল, আপনি কি ব্যবহারের উপর ভিত্তি করে এমনকি আউটপুট বিভিন্ন বার্তা may qDebug, qWarning, qCriticalইত্যাদি!
নওয়াজ

4
যাইহোক, কলব্যাক যা আসল আউটপুট করে - মাইমেজেজ আউটপুট বাতিল করে (কিউটিএমএসজিটাইপ টাইপ, কনস্ট চর ***) - কোন এনকোডিংয়ে এটি একটি বার্তা পায়?
Septagram

8
ডকুমেন্টেশন লিঙ্ক এবং এপিআই কিছুটা পরিবর্তন হয়েছে। Qt5 এ অবহিত qInstallMsgHandlerএবং প্রতিস্থাপিত হয়েছিল qInstallMessageHandler(একই ধারণা)। 5.0 এর qInstallMsgHandlerজন্য Qt-project.org/doc/qt-5.0/qtcore/…রয়েছে এবং qInstallMessageHandlerসেখানেও রয়েছে। 5.1 এর জন্য qInstallMsgHandlerসম্পূর্ণ অপসারণ করা হয়েছিল।
জেসন সি

4
@ আদিত্য: Qt4 এ, কলব্যাকটি কেবল দুটি আর্গুমেন্ট নেয়। সুতরাং আপনি এটি ব্যবহার করতে পারেন:void myMessageOutput(QtMsgType type, const char *msg) { ... }
নওয়াজ

19

থেকে এখানে সব ক্রেডিট যায় আত্মা

#include <QApplication>
#include <QtDebug>
#include <QFile>
#include <QTextStream>

void myMessageHandler(QtMsgType type, const QMessageLogContext &, const QString & msg)
{
    QString txt;
    switch (type) {
    case QtDebugMsg:
        txt = QString("Debug: %1").arg(msg);
        break;
    case QtWarningMsg:
        txt = QString("Warning: %1").arg(msg);
    break;
    case QtCriticalMsg:
        txt = QString("Critical: %1").arg(msg);
    break;
    case QtFatalMsg:
        txt = QString("Fatal: %1").arg(msg);
    break;
    }
    QFile outFile("log");
    outFile.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream ts(&outFile);
    ts << txt << endl;
}

int main( int argc, char * argv[] )
{
    QApplication app( argc, argv );
    qInstallMessageHandler(myMessageHandler);   
    ...
    return app.exec();
}

কেসফেটাল এমএসজি: ... গর্ভপাত (); // এটি লগটি লেখার আগে
ছাড়বে

কিউটি 5 থেকে শুরু করুন, বার্তা হ্যান্ডলারটি পরিবর্তনের qInstallMessageHandlerপরিবর্তে ব্যবহার করা উচিত qInstallMsgHandler
SuB

এই বার্তা হ্যান্ডলারটি থ্রেড-নিরাপদ নয়। আপনি লগ বার্তাগুলি হারাবেন যদি সেগুলি একই সময়ে দুটি থ্রেড দ্বারা প্রেরণ করা হয় (আউটফাই.ওপেন () থ্রেডগুলির একটিতে মিথ্যা ফিরিয়ে দেবে)। আপনি ফাইলটি খোলার চেষ্টা করার আগে আপনি একটি QMutex লক করতে পারেন, তারপরে ফাইলটি বন্ধ করার পরে মুটেক্সটিকে আনলক করুন। এটি সহজতম পদ্ধতির তবে এটি থ্রেড যুক্তি প্রবর্তন করবে। আপনাকে অন্যথায় লো-ওভারহেড থ্রেড-নিরাপদ বার্তাটি কুইউ করা দরকার ... এবং আপনি একটি ফ্রেমওয়ার্ক ব্যবহার করে আরও ভাল হতে পারেন।
অ্যান্টনি

9

এখানে ডিফল্ট বার্তা হ্যান্ডলারের হুকিংয়ের কার্যকারী উদাহরণ is

আপনাকে ধন্যবাদ @ রস রজার্স!

// -- main.cpp

// Get the default Qt message handler.
static const QtMessageHandler QT_DEFAULT_MESSAGE_HANDLER = qInstallMessageHandler(0);

void myCustomMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    // Handle the messages!

    // Call the default handler.
    (*QT_DEFAULT_MESSAGE_HANDLER)(type, context, msg);
}

int main(int argc, char *argv[])
{
    qInstallMessageHandler(myCustomMessageHandler);

    QApplication a(argc, argv);

    qDebug() << "Wello Horld!";

    return 0;
}

8

কনসোলটিতে লগ করার জন্য এখানে ক্রস-প্ল্যাটফর্ম সমাধান রয়েছে, যদি অ্যাপটি কিউটি ক্রিয়েটার থেকে এবং debug.logফাইলটিতে চালিত হয়, যখন এটি সংকলিত হয় এবং স্ট্যান্ড স্টোন অ্যাপ হিসাবে চালিত হয়।

main.cpp :

#include <QApplication>
#include <QtGlobal>
#include <QtDebug>
#include <QTextStream>
#include <QTextCodec>
#include <QLocale>
#include <QTime>
#include <QFile>   

const QString logFilePath = "debug.log";
bool logToFile = false;
    
void customMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QHash<QtMsgType, QString> msgLevelHash({{QtDebugMsg, "Debug"}, {QtInfoMsg, "Info"}, {QtWarningMsg, "Warning"}, {QtCriticalMsg, "Critical"}, {QtFatalMsg, "Fatal"}});
    QByteArray localMsg = msg.toLocal8Bit();
    QTime time = QTime::currentTime();
    QString formattedTime = time.toString("hh:mm:ss.zzz");
    QByteArray formattedTimeMsg = formattedTime.toLocal8Bit();
    QString logLevelName = msgLevelHash[type];
    QByteArray logLevelMsg = logLevelName.toLocal8Bit();

    if (logToFile) {
        QString txt = QString("%1 %2: %3 (%4)").arg(formattedTime, logLevelName, msg,  context.file);
        QFile outFile(logFilePath);
        outFile.open(QIODevice::WriteOnly | QIODevice::Append);
        QTextStream ts(&outFile);
        ts << txt << endl;
        outFile.close();
    } else {
        fprintf(stderr, "%s %s: %s (%s:%u, %s)\n", formattedTimeMsg.constData(), logLevelMsg.constData(), localMsg.constData(), context.file, context.line, context.function);
        fflush(stderr);
    }

    if (type == QtFatalMsg)
        abort();
}

int main(int argc, char *argv[])
{
    QByteArray envVar = qgetenv("QTDIR");       //  check if the app is ran in Qt Creator

    if (envVar.isEmpty())
        logToFile = true;

    qInstallMessageHandler(customMessageOutput); // custom message handler for debugging

    QApplication a(argc, argv);
    // ...and the rest of 'main' follows

লগ ফর্ম্যাটিং QString("%1 %2: %3 (%4)").arg...(ফাইলের জন্য) এবং fprintf(stderr, "%s %s: %s (%s:%u, %s)\n"...(কনসোলের জন্য ) পরিচালনা করে ।

অনুপ্রেরণা: https://gist.github.com/polovik/10714049


আমি দেখতে পাচ্ছি যে আপনি প্রতিটি লগ ইভেন্টে "আউট ফাইল ফাইল বন্ধ ()" কল করেন। আমি কি তা বাদ দিতে পারি?
ডাইভারগার

আমি এই সেটআপে এটি প্রস্তাব দিচ্ছি না, যেহেতু আপনি প্রতিবার লগ ফাইল খোলেন এবং সুতরাং এটি বন্ধ করা উচিত। তবে আপনি একটি উপায়ে অ্যালগরিদম পরিবর্তন করতে পারেন, সেই লগ ফাইলটি অ্যাপ্লিকেশনটির init এ কেবল একবার খোলা হচ্ছে। এই অ্যাপ্লিকেশনটির প্রস্থান করার সময় আপনাকে কেবল একবার এটি বন্ধ করতে হবে।
নিউরোট্রান্সমিটার 12

4
ধন্যবাদ! এটা খুব সহায়ক।
হারুন

এই বার্তা হ্যান্ডলারটি থ্রেড-নিরাপদ নয়। আপনি লগ বার্তাগুলি হারাবেন যদি সেগুলি একই সময়ে দুটি থ্রেড দ্বারা প্রেরণ করা হয় (আউটফাই.ওপেন () থ্রেডগুলির একটিতে মিথ্যা ফিরিয়ে দেবে)। আপনি ফাইলটি খোলার চেষ্টা করার আগে আপনি একটি QMutex লক করতে পারেন, তারপরে ফাইলটি বন্ধ করার পরে মুটেক্সটিকে আনলক করুন। এটি সহজতম পদ্ধতির তবে এটি থ্রেড বিতর্ক প্রবর্তন করবে। আপনাকে অন্যথায় লো-ওভারহেড থ্রেড-নিরাপদ বার্তাগুলির সন্ধান করা উচিত ... অন্যথায় আপনি ফ্রেমওয়ার্কটি আরও ভাল ব্যবহার করতে পারেন!
অ্যান্টনি

আমি আপনার সাথে একমত - এটি নিখুঁত থেকে অনেক দূরে। তবে এটি বেশিরভাগ সময় এর কাজটি করে। যাইহোক, যে কোনও পরিবর্তন স্বাগত!
নিউরোট্রান্সমিটার

6

ঠিক আছে, আমি বলব যে আপনি যখন আপনার ডিবাগ আউটপুটটি স্টডারারের চেয়ে আলাদা কিছুতে পুনর্নির্দেশের প্রয়োজন সেই মুহুর্তটি যখন আপনি কোনও লগিং সরঞ্জাম সম্পর্কে ভাবতে পারেন। আপনার যদি মনে হয় আপনার একটি দরকার আছে তবে আমি লাইব্রেরি থেকে QxtLogger( "দ্য QxtLogger শ্রেণি ব্যবহার করা সহজ, লগিং সরঞ্জাম প্রসারিত করা সহজ" " ) সুপারিশ করব Qxt


0

লগ stderrএবং ফাইল উভয়ই লগ করার জন্য এখানে একটি সরল, থ্রেড নিরাপদ idiomatic Qt উদাহরণ রয়েছে :

অকার্যকর বার্তা হ্যান্ডলার (কিউটিএমএসজিটাইপ প্রকার, কনস্ট্রেট কিউমেসেজলগ কনটেক্সট এবং প্রসঙ্গ, কনস্ট্রেন কিউ স্ট্রিং এবং বার্তা)
{
    স্ট্যাটিক কিউমিটেক্স মুটেক্স;
    কিউমিটেক্সলকার লক (& মিটেক্স);

    স্ট্যাটিক কিউফিল লগফাইলে (LOGFILE_LOCATION);
    স্ট্যাটিক বুল logFileIsOpen = logFile.open (কিউআইডিওয়াইস :: সংযোজন | কিউআইডেভাইস :: পাঠ্য);

    এসটিডি :: সেরার << কিউপ্রিন্টেবল (কিফর্ম্যাটলগমেসেজ (প্রকার, প্রসঙ্গ, বার্তা)) << স্টাডি :: এন্ডল;

    যদি (logFileIsOpen) {
        লগফিল.উইরাইট (qFormatLogMessage (প্রকার, প্রসঙ্গ, বার্তা) .toUtf8 () + '\ n');
        logFile.flush ();
    }
}

qInstallMessageHandler(messageHandler)অন্যান্য উত্তরে বর্ণিত হিসাবে এটি ইনস্টল করুন ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.