【目的】
- 將 qDebug() 導入 DebugView。
- 以下提供使用官方 API (OutputDebugString) 配合 qInstallMsgHandler 輸出到 DebugView 的方式。
【環境】
- Windows XP/Vista。
- DebugView http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx
【說明】
先由一些資料建立觀念
- 使用 qDebug() 時可以將 DebugView 打開看看,有時輸出訊息會直接導到 DebugView。
左圖紅色框第二個為DebugView打開前, Application Output還可以看到訊息。
第三個是DebugView 打開後,只會看到下面訊息,表示訊息已被導到 DebugView。Cannot retrieve debugging output!
- OutputDebugString (基本程式 main.cpp)
- 官方輸出到 DebugView
在user-space就是呼叫 OutputDebugString ,
而kernel-space就是呼叫DbgPrint。以下列出主要程式。#include <QtGui/QApplication> #include "dialog.h" #include <windows.h> int main(int argc, char *argv[]) { QApplication a(argc, argv); OutputDebugString(L"Echo Message to DebugView"); Dialog w; w.show(); return a.exec(); }
- 結果一樣可以在 DebugView 可以看到
- 官方輸出到 DebugView
- qInstallMsgHandler
- qInstallMsgHandler 的用法類似下面,可以自己指定輸出的方式,
不過卻卻無法輸出到 DebugView。#include <QtGui/QApplication> #include "dialog.h" #include <qDebug> void myMessageOutput(QtMsgType type, const char *msg) { switch (type) { case QtDebugMsg: fprintf(stderr, "Debug: %s\n", msg); break; case QtWarningMsg: fprintf(stderr, "Warning: %s\n", msg); break; case QtCriticalMsg: fprintf(stderr, "Critical: %s\n", msg); break; case QtFatalMsg: fprintf(stderr, "Fatal: %s\n", msg); abort(); } } int main(int argc, char *argv[]) { qInstallMsgHandler(myMessageOutput); QApplication a(argc, argv); Dialog w; w.show(); qDebug("Dialog is shown"); return a.exec(); }
- 要解決這個問題,需要修改讓訊息可輸出到 DebugView
#include <QtGui/QApplication> #include "dialog.h" #include <qDebug> #include <windows.h> void myMessageOutput(QtMsgType type, const char *msg) { char str[255]; switch (type) { case QtDebugMsg: sprintf(str, "Debug: %s", msg); break; case QtWarningMsg: sprintf(str, "Warning: %s", msg); break; case QtCriticalMsg: sprintf(str, "Critical: %s", msg); break; case QtFatalMsg: sprintf(str, "Fatal: %s", msg); abort(); default: sprintf(str, "Unknown: %s", msg); } OutputDebugStringA(str); } int main(int argc, char *argv[]) { qInstallMsgHandler(myMessageOutput); QApplication a(argc, argv); Dialog w; w.show(); qDebug("Dialog is shown"); qWarning("Dialog is shown"); qCritical("Dialog is shown"); //qFatal("Dialog is shown"); return a.exec(); }
- 目前問題
- 此處為方便 char 輸出,直接使用 OutputDebugStringA代替OutputDebugString。
若須轉型,請
[參考] QString CString char三者之转换集锦。 http://hi.baidu.com/koko200147/blog/item/7e3cad828c9b9bb66d8119cb.html - qFatal 無法輸出,因為呼叫 abort() 的關係嗎,還需再研究。
- 此處為方便 char 輸出,直接使用 OutputDebugStringA代替OutputDebugString。
- qInstallMsgHandler 的用法類似下面,可以自己指定輸出的方式,
- 延伸到 Linux 平台
- 如果要將訊息輸出到 syslog,先看一下基本用法
#incluse <syslog.h> main(int argc,char *argv[]){ char *str = "test"; openlog(argv[0],LOG_PID,LOG_USER); syslog(LOG_INFO,"%s\n",str); closelog(); }
- 通常會寫成一個巨集比較方便
#ifndef NDEBUG #define printd(msg, args...) \ do { \ openlog("[Log]",LOG_PID,LOG_USER); \ syslog(LOG_INFO, msg, ##args); \ closelog(); \ }while(0) #else #define printd(msg, args...) do { } while(0) #endif
- 所以 myMessageOutput 可以改成如此
void myMessageOutput(QtMsgType type, const char *msg) { openlog(argv[0],LOG_PID,LOG_USER); switch (type) { case QtDebugMsg: syslog(LOG_INFO,"Debug : %s\n",str); break; case QtWarningMsg: syslog(LOG_INFO,"Warning : %s\n",str); break; case QtCriticalMsg: syslog(LOG_INFO,"Critical: %s\n",str); break; case QtFatalMsg: syslog(LOG_INFO,"Fatal : %s\n",str); //abort(); } closelog(); }
- 和 Windows平台的DebugView 作整合,目前的想法是透過 ifdefine 控制, 目前程式碼先省略。
- 如果要將訊息輸出到 syslog,先看一下基本用法
- 嘗試修改讓訊息輸出到 檔案
直接將 Debug message 輸出到檔案也是一個不錯的方式 myMessageOutput 可以寫成這樣。
請注意 fclose() 要放在 if 裡面,表示開檔成功才作關檔動作。const char* logfile = "/var/log/log.txt"; void myMessageOutput(QtMsgType type, const char *msg) { FILE *fp = fopen(logfile, "a"); if (fp) { switch (type) { case QtDebugMsg: fprintf(fp, "Debug : %s\n", msg); break; case QtWarningMsg: fprintf(fp, "Warning : %s\n", msg); break; case QtCriticalMsg: fprintf(fp, "Critical: %s\n", msg); break; case QtFatalMsg: fprintf(fp, "Fatal : %s\n", msg); //abort(); } fclose(fp); } }
- 輸出到Kiwi Syslog Server
如果使用 busybox 的話建議直接啟用將 –R 參數將訊息往遠端機器丟,
除非特殊需求否則不需自己調用 socket 。
[參考] BusyBox - The Swiss Army Knife of Embedded Linux
http://www.busybox.net/downloads/BusyBox.htmlbusybox syslogd -R 192.168.1.1:601
【想法】
- 其實調用 qDebug/qWarning/qCritical/qFatal 對除錯而言,幫助並不大,要做的應該是將要做的事按照
Init/Process/Close … 作分類會比較好。
【參考】
- <QtGlobal> - Global Qt Declarations
http://doc.qt.nokia.com/4.6/qtglobal.html#qInstallMsgHandler - 用Kiwi Syslog Server收集Fortigate Log
http://www.askasu.idv.tw/index.php/2010/09/07/1210/