How to fetch the current file name and line number to be written into a file for logging purpose



  • I am creating a log for my application, printing the current date, time and other stuff. But I am struck at writing the filename and line number(the line from where I am calling my write function) into a file. Basically, I am using

    fileio.write("/tmp/test.log", Qt.formatDateTime(new Date(), "MMM dd hh:mm:ss.zzzzzz") + "|" + "|" + "|" + "Back button clicked" + "|" + "fileName:Menu.qml" + "|" + "lineNumber:30" + "\n");

    in my qml to call a fileio function which does the write operation. As you can see I am printing the line number and filename manually. Is there a way to print it dynamically?
    Can somebody help out?
    TIA.



  • You can do it with qInstallMessageHandler
    This will intercepts call to console.log , console.debug ...
    The example in the documentation outputs the line number like you want.



  • @GrecKo said in How to fetch the current file name and line number to be written into a file for logging purpose:

    documentation

    Thanks @GrecKo , But I dont want to print the line number on the console. I want to pass the line number that is fetched dynamically which is to be printed in a file. Also, any suggestions for fetching the file name dynamically which also needs to e printed into a file.
    TIA.



  • Hi, I had a similar problem, where I wanted to log filename+linenumer with a message as well. I came up with this (note: this was for widget-based .cpp code, no qml):

    // define a class for logging
    class LoggingObject
    {
        QString sFilename = "unknown";
        int     nLineNo   = 0;
    
        public:
        LoggingObject(QString sFilename,int nLineNo)
        {
            this->sFilename = sFilename;
            this->nLineNo   = nLineNo;
        }
    
        void logInvoker(const char *msg,...)
        {
       // build the log message using vasprintf
           va_list ap;
           va_start(ap, msg);
           QString sMsg = QString::vasprintf(msg, ap);
    
       // prefix with filename and lineno. and write to our file
          fileio.write(QString("File %1 lineno. %2 msg: '%3'").arg(sFilename).arg(nLineNo).arg(sMsg));
        }
    };
    

    then #define a macro to call it

    #define log LoggingObject(__FILE__,__LINE__).logInvoker
    

    then in your code you can write something like:

    ...
    log("Back button clicked");
    ...
    


  • @chandan94 with qInstallMessageHandler you do what you want with the message. You can output it to the console, write it to a file or both.



  • @GrecKo Yes I use qInstallMessageHandler in all my programs, it's a handy function, but it can not help me with displaying the filename and linenumber from where I called the log macro to log something. For example:

    ...
    log("First message");
    ...
    log("Second message);
    ...
    

    (Those 2 calls should show the same filename like 'mainWindow.cpp' but different linenumbers).



  • @hskoglund
    Hi, I am making a Qt quick application. Can you suggest something for this? Also, I am confused how to use qInstallMessageHandler.



  • @hskoglund Indeed, you have to use qDebug and friends for that.



  • I'm no expert on Qt quick apps, but qInstallMessageHandler works the same, and instead of qDebug(), in a .qml file you can use console.log. So lets try:

    First declare your messagehandler, easiest is to include it in your main.cpp, something like this:

    void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
    {
    // construct a msg
        QString sFilename = context.category;
        QString sFunction = context.function;
        int nLineNo       = context.line;
    
        QString s = QString("File '%1' function '%2' at line no %3: '%4'\n").arg(sFilename).arg(sFunction).arg(nLineNo).arg(msg);
    
    // write to file
       FILE* f;
    #ifdef _MSC_BUILD
        if (0 != fopen_s(&f,"myfile.log","a+"))   // MSVC compiler: fopen() is frowned upon, use fopen_s()
            f = NULL;
    #else
        f = fopen("myfile.log","a+");          // all other compilers: use standard fopen() call
    #endif
        if (f)
        {
            fprintf(f,"%s",qUtf8Printable(s));
            fclose(f);
        }
    
    // also show if we're running inside Qt Creator (delayed)
        fprintf(stderr,"%s",qUtf8Printable(s));
    }
    

    and then inside your main() install the handler, easiest is at the beginning:

    
    int main(int argc, char *argv[])
    {
        qInstallMessageHandler(myMessageHandler);
    
        QGuiApplication app(argc, argv);
    ...
    

    Now try using a console.log('Hello from qml') in a qml file. Good luck!



  • Hi @chandan94

    u can use the below mentioned way for all the debug, based on critical , fatal also.

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        qDebug() << Q_FUNC_INFO << "In Main " << endl;
    #ifdef DEBUG
        FILE * fp;
        fp = fopen (LOG_FILE_PATH, "a+");
        if(fp==NULL)
            fp = fopen (LOG_FILE_PATH, "w");
        if(fp==NULL){
            return 0;
        }
        fclose(fp);
        qInstallMessageHandler(myAppLogsToFile);
    #endif
        FirstClass firstClassObjecct;
        firstClassObjecct.show();
    
        return a.exec();
    }
    
    void myAppLogsToFile(QtMsgType type, const QMessageLogContext &context, const QString &msg)
    {
        QString timeFormat = "dd-MMM-yyyy hh:mm:ss:zzz"; // u can change the format  of datetime
    
        QByteArray localMsg = msg.toLocal8Bit();
        QByteArray tim = QDateTime::currentDateTime().toString(timeFormat).toLocal8Bit();
        FILE * fp;
        fp = fopen (LOG_FILE_PATH, "a");
    
        if(fp==NULL){
            return;
        }
        switch (type) {
        case QtDebugMsg:
            fprintf(fp, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
            break;
        case QtWarningMsg:
            fprintf(fp, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
            break;
        case QtCriticalMsg:
            fprintf(fp, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
            break;
        case QtFatalMsg:
            fprintf(fp, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
            abort();
        default :
            break;
        }
        fclose(fp);
    }
    

    Thanks,



  • @Pradeep-Kumar said in How to fetch the current file name and line number to be written into a file for logging purpose:

    u can use the below mentioned way for all the debug, based on critical , fatal also.

    Hi @Pradeep-Kumar ,

    I am using :

    class FileIO : public QObject
    {
    Q_OBJECT
    public slots:
    bool write(const QString& source, const QString& data)
    {
    if (source.isEmpty())
    return false;

        QFile file(source);
        if (!file.open(QFile::Append | QFile::Truncate))
            return false;
    
        QTextStream out(&file);
        out << data;
        file.close();
        return true;
    }
    

    for write function.
    And in qml:
    fileio.write("/tmp/test.log", Qt.formatDateTime(new Date(), "MMM dd hh:mm:ss.zzzzzz") + "|" + "|" + "|" + "Back button clicked" + "|" + "fileName:Menu.qml" + "|" + "lineNumber:30" + "\n");
    So is there some property like QT.formatDateTime property, which I can use directly to get the line number and filename?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.