再厲害的高手也是要靠著不斷琢磨自己的 code 才能減少錯誤的發生。錯誤不只是低級錯誤,更多的是思慮上差異造成操作時的認知不同。
Genero 的 DEBUG除錯工具位於 GeneroStudio 套件內。但本章節談論一下不使用除錯器怎麼判斷大概錯誤的地方。
Genero編譯後形成 p-code,必須透過DVM-fglrun 來執行。因此可以透過外界的干預,例如調整『環境變數』來達到窺探程式執行過程的需求。
fglrun執行的過程中可透過許多環境變數來進行操作干預。例如 FGLGUI(設定客戶端樣態)、FGLSERVER(設定客戶IP)...等,可以查閱 https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_EnvVariables_fgl.html
以下先討論對於除錯相關的 FGLSQLDEBUG 與 FGLGUIDEBUG
預設值 0 可異動範圍
也就是說,我們可以透過調整FGLSQLDEBUG的設定,在程式執行過程中查看訊息
export FGLSQLDEBUG=3
以 Genero 3.20來說,設定後再操作程式,就可以看到『**DVM-fglrun 與 ODI 及數據庫訊息交換的過程 **』,包含 4GL內組裝的指令樣式、經過 ODI 轉換後的樣式 (因為程式必須以 INFORMIX相容語法來寫,所以ODI會有一層轉換) ,ODI送到資料庫端最後的樣式,以及資料庫執行結果和回填資料。
例如:
SQL: CONNECT TO "ds+driver='dbmoraB2x',source='t30dev'" AS "ds" USER "***" USING "***"
| 4gl source : lib_cl_db.4gl line=594 #程式出現的位置
| loading driver : [/u1/gst/3.20.09/fgl32013/dbdrivers/dbmora_11] #ODI
| db driver type : ora
| ora.c:00859(3) : Connection parameters for 'ds':
| ora.c:00860(3) : Oracle server = 't30dev' #ORACLE或其他資料庫連線訊息
| ora.c:00861(3) : Schema = ''
| ora.c:00862(3) : User name = '*'
| ora.c:00863(3) : Password = '*'
SQL: SELECT userenv('SESSIONID') FROM dual #SQL語句
| 4gl source : lib_cl_db.4gl line=796 #code出處
| ../ODI_common.h:00795(3) : adaptStatement: stmt type = 1 #ODI轉換
| ../ODI_common.h:00800(3) : adaptStatement: ifxemul = 1
| ora.c:01734(3) : Nat stmt1 = select userenv('SESSIONID') from dual #轉換成果
| ora.c:01755(3) : Preparing SQL (0x278e540): [select userenv('SESSIONID') from dual]
| ora.c:01686(3) : Prefetch rows = 1
| ora.c:01693(3) : Prefetch memory = 0
| ora.c:03227(3) : Executing SQL (0x278e540)
| sqlcode : 0 #執行狀態
| curr driver : ident='dbmora_11'
| curr connection : ident='ds' (dbspec=[ds+driver='dbmoraB2x',source='t30dev'])
| into: 1
| t: DECIMAL(20,0) f:04 v:"35192778" #執行結果
| Execution time : 0 00:00:00.00173 #花費時間
從上面範例可以清楚理解,透過 FGLSQLDEBUG 能夠探知所有的 SQL指令現在運行狀態。很有可能實際出錯的時候,發生的成因其實是前一個,或前方很遠的段落就已經發生選擇錯誤:若用 DEBUG 查詢問題時不會很容易抓出實際狀況,因此透過 FGLSQLDEBUG 的輸出查詢會必較容易理解成因。
由於 FGLSQLDEBUG 的訊息量多,因此通常以倒出為檔案的方式進行查看,例如透過重導指令:
export FGLSQLDEBUG=3; $FGLRUN test-app > $TEMPDIR/debug.log 2>&1
將訊息存放到 debug.log 再慢慢查閱即可。
程式若能正常運行出結果,接下來需要考慮的就會是執行效能。應該從上面的範例,可以看出FGLSQLDEBUG=3 的時候有包含『SQL執行時間』。因此,不管是 FourJs 或以 FGL 為底層工具開發出的平台,自然都想利用這個數值來對效能旁敲側擊。因此有不同對應的工具,可進行操作
在T100的環境中,可使用 r.h 來執行作業。執行出的 FGLSQLDEBUG log 資料會被收集、統計。將一致的數值收集起來進行平均,就可以取出** 『總執行次數、平均執行時間』 ** 兩個指標,接下來評估數值是否合理,要不要透過調整進行優化 (如適當的增加 index 或變換低成本(lower cost)的語法) 就會有比較清晰的答案。
在 FourJs 也在 github 中提供類似工具
FGLSQLDEBUG在處理上更為細緻 (因為是FourJS自己的),能夠結合 FGLSOURCEPATH(原始碼所在路徑) 搭配分析,因此還可以依照 42m module 來進行比序與問題確認。
不管透過 r.h 或 FGLSQLDEBUG log viewer ,都能對開發人理解:程式被操作時的效能,有更清楚的感知。
上方的 FGLSQLDEBUG 在探索 DVM與資料庫的關係。而操作的時候,DVM對上客戶端軟體 (如GDC/GBC/GMA...) 會出問題的,大抵就在網路上了。『封包是否正常的、循序的派送,兩端是否保持著連線,License的狀況是否支持繼續執行,』
這些,在前面的篇章中,曾經提到,都是靠著 AUI TREE變動的訊息封包傳遞而得來。那麼要除錯,就是要觀測 DVM是否正確送出封包、客戶端是否正確得到封包。
在 [GDC] 基本的概念與操作中能理解到從 Monitor中查看的方法。下面範例看一下 DVM-fglrun 看的方法:
預設值 0 可異動範圍 1 (顯示傳送內容)
export FGLGUIDEBUG=1
基本上,下列的封包訊息並不容易閱讀,但是可以拿來查關鍵字
*** uic_FT_ackFileTransfer.972: id=-1 localName=!!__cached__!!
*** uic_read.578: returns:0
*** uic_read.568: ...
*** uic_readMessage.417: ...
*** uic_readMessage.439: length=138 comp_length=138
*** uic_processMessage.458: FILE_TRANSFER
*** uic_FT_processMessage.1209: id=-2 mtype=GET_REQ
*** uic_FT_processGet.1161: requestedName=16/worksheethidden.png realName=/u1/t30dev/res/img/ui/16/worksheethidden.png
例如可以探察到資源到底是否送出對的,也可以和 GDC 做比對,以釐清是否在封包的傳遞上出問題。
善用上述兩個變數,可以不用每次都 step by step的操作除錯器,對於整體環境的掌控能力會較好,可以多加習練。