Logging in Javascript
寫程式的時候,通常我們可以利用 printf() 之類的函式,把一些程式內部的資料印出來,以追蹤程式的運行狀態。以程式設計的術語來說,這個叫做 logging。對於有 console 可以使用的程式來說,printf() 通常便已足敷使用,但若寫的是視窗程式之類沒有 console 的程式,就很麻煩,因為用以替代的 MessageBox() 可以顯示的資料不多[1],又沒辦法將訊息內容複製到剪貼簿裡。當「簡易法」無法奏效的這個時候,就必須啟用「真正的」logging 機制,把 logging 確實當作一個程式運作所必須的 component 來處理。
SHELL> find /usr/ports/devel -type d -name 'log4*' -maxdepth 1 /usr/ports/devel/log4c /usr/ports/devel/log4cpp /usr/ports/devel/log4j /usr/ports/devel/log4cplus /usr/ports/devel/log4cxx /usr/ports/devel/log4sh
如上所示,常見的程式語言,我們有 log4* 系列的函式庫可以用,log4j 是其濫觴。對於商業軟體開發工具而言,也通常會有其對應的 logging solution 可用。
言歸正傳,最近我在用 AJAX 寫一個加強 trac 的程式時,發現 logging 之於 javascript 寫作,也很重要,因為 alert() 就跟 MessageBox() 一樣地不方便。安裝 debugger 之類的網頁整合開發環境,是個不錯的辦法。不過,其實我們也可以自己來。
簡單講,logging 其實就是把指定的資料,送到某處顯示,以便於當下或事後檢視。因此,logging 基本上必須有「傳送」與「顯示」這兩個步驟,若要做的好一點的話,可以再加個「記錄」,以便於事後檢視。因此,不考慮進階的「記錄」功能的話,要在 javascript 裡做 logging,其實很簡單,基本把握「傳送」與「顯示」兩原則即可:
function JSLogPrint(msg, tag)
{
var JSLogEnabled = document.JSLogEnabled;
if (JSLogEnabled == null) {
JSLogEnabled = true;
}
if (JSLogEnabled) {
/*
* A magic string identifier prefix that used to avoid conflict with
* any other HTML element id or CSS class name when we are generating
* them dynamically.
*/
var JSLogPrefix = document.JSLogPrefix;
if (JSLogPrefix == null) {
JSLogPrefix = 'JSLog';
}
/*
* Create output panel for displaying log messages.
*/
var idLogPanel = (JSLogPrefix + 'Panel');
var domLogPanel = document.getElementById(idLogPanel);
if (domLogPanel == null) {
domLogPanel = document.createElement('div');
domLogPanel.id = idLogPanel;
domLogPanel.className = JSLogPrefix + 'Panel';
var domBody = document.getElementsByTagName('body')[0];
domBody.appendChild(domLogPanel);
}
var domEntry = document.createElement('div');
domEntry.className = JSLogPrefix + 'Entry';
if (tag != null) {
var domTag = document.createElement('div');
domTag.className = JSLogPrefix + 'Tag';
domTag.appendChild(document.createTextNode(tag));
domEntry.appendChild(domTag);
}
var domMsg = document.createElement('div');
domMsg.className = JSLogPrefix + 'Msg';
domMsg.appendChild(document.createTextNode(msg));
domEntry.appendChild(domMsg);
domLogPanel.appendChild(domEntry);
}
}
只要把上面的 javascript function 引入,即可使用。若有 HTML element id 或 CSS class name conflict 時,請建立 document.JSLogPrefix 變數[2],並將之設成一個不會造成 conflict 的字串,其預設值為 'JSLog'。同時,也可以建立 document.JSLogEnabled 變數,以決定是否要啟動 logging,其預設值為 true。在使用時,呼叫 JSLogPrint() 傳入參數即可,每呼叫一次,便會建立一個 log entry,附加在網頁最下方。msg 參數指 log message,tag 參數可以被忽略,是用來方便識別各個 log entry,使用時,可以以 timestamp 或程式所在行數[3]為其值。顯示的 log messages 結構如下:
<div id="JSLogPanel" class="JSLogPanel"> <div class="JSLogEntry"> <div class="JSLogTag">tag</div> <div class="JSLogMsg">msg</div> </div> </div>
若有設定 document.JSLogPrefix,則其中的 HTML element id 與 CSS class name 的 JSLog 字樣,應改以 document.JSLogPrefix 的值替代。為畫面美觀起見,建議設定這幾個 CSS class:JSLogPanel、JSLogEntry、JSLogTag 與 JSLogMsg。我使用的 CSS 設定如下:
.JSLogPanel
{
width: 100%;
border-top: 1px solid;
}
.JSLogEntry
{
padding: 0.5em;
border-bottom: 1px dashed #ccb;
font-size: x-small;
}
.JSLogTag
{
text-decoration: underline;
font-weight: bold;
}
.JSLogMsg
{
margin-top: 0.5em;
}
如欲測試,請按這裡,填入測試用的 log message,剛輸入的 log message,將會在網頁下方顯示。另外,A List Aprt 也有一篇文章在談 JavaScript Logging,亦十分值得一讀。
[1] 另一個替代方案是,使用 OutputDebugString() 這個 Win32 API,會把傳入的字串,輸出到安裝到系統裡,目前正在作用的 debugger 上。
[2] 即在網頁裡的 javascript 全域變數。
[3] 有人知道 javascript 怎麼取得程式所在行數嗎?
2 Comments
要在 browser 的 javascript console 寫 log,請這麼寫:
function JSConsoleLog(msg, tag) { if (window.console) { var s; if (tag) { s += (tag + ': '); } s += msg; window.console.log(s); } } JSConsoleLog('test1', 'INFO'); JSConsoleLog('test2', 'DEBUG');我写了一个javascriptlog
下载地址:
http://www.box.net/shared/ziytr4pc80#1:12948521
Post a Comment