Bienvenue sur le forum !

Si vous souhaitez rejoindre la communauté, cliquez sur l'un de ces boutons !

Qt 5 : 5.9.1 - Qt Creator : 4.3.1 - Qt Installer : 2.0.3 - JOM : 1.1.2 - Qt Build suite : 1.7.0 - VS Qt 5 : 2.0.0

Du debugage au fichier .log

Je vous présente ici une astuce pour créer facilement un fichier .log sans jamais écrire dedans, ou presque :p

Normalement, en bon utilisateur de Qt, vous utiliser la classe fournis pas celui pour debuguer ou simplement afficher dans la console : QDebug

La fonction suivante va simplement rediriger le flux des debug la ou vous le souhaitez, dans le cas présent un fichier
void myMessageOutput(QtMsgType type, const char *msg)
{
QFile file(QApplication::applicationDirPath()+"/"+qAppName()+".log");
file.open(QIODevice::WriteOnly | QIODevice::Append);
file.write(QString("[").toAscii()+QDateTime::currentDateTime().toString().toAscii()+QString("] ").toAscii());
switch (type) {
case QtDebugMsg:
file.write(QString("Debug: ").toAscii()+msg+QString("\r\n").toAscii());
break;
case QtWarningMsg:
file.write(QString("Warning: ").toAscii()+msg+QString("\r\n").toAscii());
break;
}
}
Cette fonction doit être placé dans votre fichier main.cpp, et avant votre fonction main().
Dans votre fonction main il ne vous reste plus qu'à dire au programme de prendre en compte la fonction, et le tour est joué.
qInstallMsgHandler(myMessageOutput);
Au final votre main.cpp ressemblera à quelque chose comme ca
#include <QtGui>
#include <QDebug>

#include <iostream>
#include "mainwindow.h"

void myMessageOutput(QtMsgType type, const char *msg)
{
QFile file(QApplication::applicationDirPath()+"/"+qAppName()+".log");
file.open(QIODevice::WriteOnly | QIODevice::Append);
file.write(QString("[").toAscii()+QDateTime::currentDateTime().toString().toAscii()+QString("] ").toAscii());
switch (type) {
case QtDebugMsg:
file.write(QString("Debug: ").toAscii()+msg+QString("\r\n").toAscii());
break;
case QtWarningMsg:
file.write(QString("Warning: ").toAscii()+msg+QString("\r\n").toAscii());
break;
}
}

int main(int argc, char *argv[])
{
qDebug(); // Un simple retour à la ligne pour un affichage propre dans la console
QApplication app(argc, argv);
if(!QApplication::arguments().contains("dvp")) // Inutile d’écrire dans le fichier si vous lancer le programme à partir de QtCreator,
qInstallMsgHandler(myMessageOutput); // rajoutez l'argument dvp à l’exécution

MainWindow w;
w.show();

return app.exec();
}

Le programme va ainsi de lui même créer le fichier .log et écrire dedans tout ce qui aurai du etre écrit normalement dans votre console.

Voilou en espérant que cette astuce vous soit utile ;)

Réponses

  • Génial ! :)
    Pour récupérer le log je fais (bientôt faisais donc :D) une redirection depuis une console linux, et il n'est pas aisé de différencier les Debugs des warnings (les deux venant de la sortie standart d'erreur).
    Merci beaucoup, d'ici peu j'implémenterai ça !
  • Par contre avec la mise en place de ce handler, le débug n'est plus affiché dans la console. Pour les avoir encore dans la console (ce qui est pratique en phase de dév), il faut utiliser les flux standards en plus de l'écriture dans un fichier.

    EDIT: je viens de voir qu'il y a une différentiation en mode "dév". Néanmoins ça reste valable, on peut vouloir le log en plus de la sortie en débug ;)
  • J'ai dernièrement eu besoin de rediriger le flux de debug vers un affichage de l'application, et j'ai été surpris du nombre d'obstacle qui se sont mis devant moi. Je poste donc ici ma solution. Il en existe d'autre, et probablement des meilleurs. Je suis bien sur ouvert, à toutes

    L'idée est donc d'afficher la console dans un QPlainTextEdit de l'application, cela évite de retoucher tout les qDebug() du programme.
    Le plus simple à la base étant bien sur d'implémenter une methode log(QString) dans la quelle on écrit tout.
    Alors pourquoi pas ? Ben parce que je suis tétu, parce que j'ai pas envie de créer une fonction pour ca, parce c'est une solution possible pour tout les logiciels que j'ai créer sans retouche majeur, parce que c'est la classe, et parce que ca gère aussi toutes les erreurs généré par le système.
    Bon si l'appli plante on a plus aucune trace, mais l'idée c'est pas de debugger, mais d'afficher les messages d'erreurs qu'on veux pas forcement voir, mais qu'on veux pouvoir voir. Après rien ne vous empeche de la conjuguer avec la version fichier.log ci dessus.

    Mon main change peu par rapport à la version fichier

    int main(int argc, char *argv[])
    {
    qDebug();
    QApplication a(argc, argv);

    if(!QCoreApplication::arguments().contains("dvp"))
    qInstallMsgHandler(myMessageOutput);

    MainWindow w;

    return a.exec();
    }

    Je déclare un namespace dans mon .h avec mes besoins dedans.
    Ce namespace doit etre "visible" de tous les fichiers qui accederont à NSC::send_text(QString);
    Si ca n'est pas le cas, le compilateur criera à l'usurpateur.

    namespace NSC
    {

    extern QPlainTextEdit * get_console();
    extern void send_console(QString text);

    class MyConsoler : public QObject
    {
    Q_OBJECT
    public:
    MyConsoler(){
    connect(this, SIGNAL(signal_text(QString)), NSC::get_console(), SLOT(appendPlainText(QString)));
    }
    void send_text(QString text){
    emit signal_text(text);
    }
    signals:
    void signal_text(QString);
    };

    }
    Dans mon .cpp j'initialise mon namespace.
    Si des petits malins se demandent pourquoi j'initialise à NULL, c'est parce que le namespace ne fait pas partie d'une classe. Il est donc parcouru a l'appel du fichier qui le contient, donc le .cpp. sauf qu'à ce moment la, QApplication n'est pas encore initialiser, et paf ca fait des chocapic !

    namespace NSC
    {

    QPlainTextEdit * console = NULL;
    MyConsoler * consoler = NULL;

    QPlainTextEdit * get_console(){
    return console;
    }
    void set_console(QPlainTextEdit * item){
    console = item;
    consoler = new MyConsoler;
    }
    void send_console(QString text){
    consoler->send_text(text);
    }

    }
    Toujours dans mon .cpp, à l'initialisation de ma fenêtre, donc au plus tôt en fait, j'initialise ma console:

    NSC::set_console(new QPlainTextEdit(this));
    ui->verticalLayout_2->addWidget(NSC::get_console());
    De retour dans mon main, je declare ma fonction de MsgHandler pour Qt:

    void myMessageOutput(QtMsgType type, const char *msg)
    {
    if(!NSC::get_console())
    return;
    switch(type){
    case QtDebugMsg:
    NSC::send_console((QString("[Debug] ").toAscii()+msg+QString("\r\n").toAscii()));
    break;
    case QtWarningMsg:
    NSC::send_console((QString("[Warning] ").toAscii()+msg+QString("\r\n").toAscii()));
    break;
    case QtCriticalMsg:
    NSC::send_console((QString("[Critical] ").toAscii()+msg+QString("\r\n").toAscii()));
    break;
    case QtFatalMsg:
    NSC::send_console((QString("[Fatal] ").toAscii()+msg+QString("\r\n").toAscii()));
    break;
    }
    }
    Je pense que c'est une solution intégrable à partir d'un librairy personnel.
    J'ai pour ma part une librairy qui sert de "coeur" à tous mes programmes professionnels, j'essayerai d'y intégrer cette initialisation pour qu'elle puisse être accessible dans chacun d'eux. Si des intéressés se manifeste, je posterai ma solution quand je l'aurai.

    D'ici la, bon code ;)
Connectez-vous ou Inscrivez-vous pour répondre.