為了在生產環境動態開啟/關閉預存程序日誌、歸檔管理、多代理程式並行寫入不衝突,本文提出一套基於共享記憶體的 C 語言日誌框架,包含管理預存程序(UPDATE_SP_CONFIG、GET_SP_CONFIG、GET_SP_LOG)與記錄預存程序(OPEN_LOG、LOGINFO、LOGGER、CLOSE_LOG),並支援 SQL-PL 與外部 C 預存程序直接呼叫。
archive 目錄,避免單一檔案過大。LOG_SPLIT=Y 依應用程式 ID 建立獨立日誌檔;=N 合寫 sp.log 並以應用程式 ID 區分。| 預存程序 | 用途 | 關鍵參數 |
|---|---|---|
| DB2.UPDATE_SP_CONFIG | 設定/更新標記配置(全域與私有) | log_token_name, value (Y/N/R) |
| DB2.GET_SP_CONFIG | 查詢目前所有標記與除錯模式 | 無 |
| DB2.GET_SP_LOG | 讀取指定日誌檔內容回傳結果集 | log_file_name |
| DB2.OPEN_LOG | 啟動日誌,取得 48 位元組句柄 | log_token_name, handle CHAR(48) FOR BIT DATA |
| DB2.LOGINFO | 記錄資訊層級訊息(標記存在即寫入) | handle, message |
| DB2.LOGGER | 記錄除錯層級訊息(需標記 DEBUG=Y) | handle, message |
| DB2.CLOSE_LOG | 關閉日誌,記錄經過時間 | handle |
-- 全域開關
CALL DB2.UPDATE_SP_CONFIG('GLOBAL_LOGGING','Y'); -- 啟用
CALL DB2.UPDATE_SP_CONFIG('GLOBAL_LOGGING','N'); -- 關閉
-- 日誌分離
CALL DB2.UPDATE_SP_CONFIG('LOG_SPLIT','Y'); -- 依代理分檔
CALL DB2.UPDATE_SP_CONFIG('LOG_SPLIT','N'); -- 合併寫入
-- 私有標記(以 TESTSP 為例)
CALL DB2.UPDATE_SP_CONFIG('TESTSP','Y'); -- 建立並啟用除錯
CALL DB2.UPDATE_SP_CONFIG('TESTSP','N'); -- 停用除錯(保留標記)
CALL DB2.UPDATE_SP_CONFIG('TESTSP','R'); -- 移除標記(含配置檔與共享記憶體)
配置檔 .splogrc 位於 ~/sqllib/splog/<dbname>/,DBA 需預先建立目錄並授權 fenced user 讀寫。
CREATE PROCEDURE TESTSP()
LANGUAGE SQL
BEGIN
DECLARE h CHAR(48) FOR BIT DATA;
DECLARE cnt INT DEFAULT 0;
CALL DB2.OPEN_LOG('TESTSP', h);
SET cnt = cnt + 1;
CALL DB2.LOGINFO(h, 'loginfo ' || CHAR(cnt));
SET cnt = cnt + 1;
CALL DB2.LOGGER(h, 'logger ' || CHAR(cnt));
-- 更多記錄...
CALL DB2.CLOSE_LOG(h);
END
日誌輸出範例:
12-25-2005 22:29:39.839:[testsp:051226021028] Begin Stored Procedure *** [681574408]
12-25-2005 22:29:39.839:[testsp:051226021028] loginfo 1
12-25-2005 22:29:39.839:[testsp:051226021028] logger 2
...
12-25-2005 22:29:39.839:[testsp:051226021028] End Stored Procedure *** Elapsed 0.000
#include "logger.h"
#define BYTEHANDLESIZE 48
void openLog(char *name, char *handle);
void closeLog(char *handle);
void setDBName(struct sqludf_dbinfo *dbInfo);
void logger(char *handle, char *fmt, ...);
void logginfo(char *handle, char *fmt, ...);
範例:
SQL_API_RC SQL_API_FN Snow(..., struct sqludf_dbinfo *dbInfo) {
char byteHandle[BYTEHANDLESIZE];
setDBName(dbInfo); // 必須先呼叫以設定資料庫名
openLog("TESTSP", byteHandle);
logger(byteHandle, "DB name: %s", dbInfo->dbname);
logger(byteHandle, "HOME: %s", getenv("HOME"));
logger(byteHandle, "Appl ID: %s", dbInfo->appl_id);
closeLog(byteHandle);
return 0;
}
註冊時需指定 DBINFO 選項以取得 dbInfo 結構。
~/sqllib/samples/c/bldrtn、embprep(平台專屬版本),而非原始碼附帶腳本。ALTER PROCEDURE ... EXTERNAL NAME 'newlib!func'(見 spalter 腳本)。ipcrm -m <id> 釋放(需 fenced user 身分)。CALL DB2.UPDATE_SP_CONFIG('GLOBAL_LOGGING','N') 即時生效,零負擔。sed 's/CALL DB2./--CALL DB2./' 批次註解所有日誌呼叫,保留原始碼以便未來啟用。此框架提供生產級動態日誌能力:零停機切換、多代理隔離、共享記憶體高效配置同步、彈性歸檔。開發團隊可視專案需求採用整套或部分元件,將預存程序可觀測性納入標準交付流程。