http://java.sun.com/j2se/1.4.0/docs/guide/util/logging/overview.html
QuickServer目前只支持Java Logging API (java.util.logging)。1.4版的Java已加入logging。如果你還在使用舊的版本,你可以安裝Lumberjack庫提供的可選的實現(http://javalogging.sourceforge.net/)。
讓我們給我們的EchoServer做一個日誌器。QuickServer默認已可以使用日誌器,但是除了ConsoleHandler和設置INFO的級別之外它什麼也沒有處理。因而無論何時我們在EchoServer關閉和客戶端的連接,我們都會在控制檯看見一些相似的信息
Feb 16, 2000 10:11:25 PM ClientHandler sendSystemMsg
INFO: Closing connection : /127.0.0.1
上面的信息指明IP爲127.0.0.1的客戶端關閉了連接。這條消息的顯示使用了ClientHalder類的sendSystemMsg()方法.
讓我們看看我們怎樣在我們的項目中控制日誌。使用java logging必須先在類中導入java.util.logging包。
從上面的日誌,我們發現某些客戶端關閉了連接或掉線,但是它是怎樣顯示的,我們並沒有寫任何有關日誌的命令。它會顯示是因爲QuickServer使用了內部的日誌器ClientHandler類的sendSystemMsg()方法。
查看QuickServer文檔可以找到sendSystemMsg(),如果沒有指定級別,它默認使用INFO。你可以在ClientCommandHandler或Authenticator或任何類中使用sendSystemMsg()來記錄一個事件。
1. 簡單的日誌
現在我們來記錄每一個連接EchoServer的客戶端IP地址。編輯EchoCommandHandler.java文件。在gotConnected(ClientHandler handler)後添加
handler.sendSystemMsg("New Client : " +
handler.getSocket().getInetAddress().getHostAddress(),
Level.INFO);
還要導入包import java.util.logging.*;
編譯並運行,連接到EchoServer,你將看到當客戶端連接時控制檯會顯示你的地址。
讓QuickServer將日誌記錄到文件中(XML格式)。下面是修改的文件:
01 package echoserver; 02 03 import org.quickserver.net.*; 04 import org.quickserver.net.server.*; 05 06 import java.io.*; 07 import java.util.logging.*; 08 09 public class EchoServer { 10 public static void main(String s[]) { 11 12 String cmd = "echoserver.EchoCommandHandler"; 13 String auth = "echoserver.EchoServerQuickAuthenticator"; 14 String data = "echoserver.EchoServerPoolableData"; //Poolable 15 16 QuickServer myServer = new QuickServer(); 17 18 //setup logger to log to file
19 Logger logger = null;
20 FileHandler xmlLog = null;
21 File log = new File("./log/");
22 if(!log.canRead()) 23 log.mkdir();
24 try { 25 logger = Logger.getLogger(""); //get root logger 26 logger.setLevel(Level.INFO);
27 xmlLog = new FileHandler("log/EchoServer.xml"); 28 logger.addHandler(xmlLog);
29 } catch(IOException e){
30 System.err.println("Could not create xmlLog FileHandler : "+e);
31 }
32 //set logging level to fine 33 myServer setConsoleLoggingLevel(Level INFO); 34 35 36 myServer.setClientCommandHandler(cmd); 37 myServer.setAuthenticator(auth); 38 myServer.setClientData(data); 39 40 myServer.setPort(4123); 41 myServer.setName("Echo Server v 1.0"); 42 43 //store data needed to be changed by QSAdminServer 44 Object[] store = new Object[]{"12.00"}; 45 myServer.setStoreObjects(store); 46 47 //config QSAdminServer 48 myServer.setQSAdminServerPort(4124); 49 myServer.getQSAdminServer().getServer().setName("EchoAdmin v 1.0"); 50 try { 51 //add command plugin 52 myServer.getQSAdminServer().setCommandPlugin( 53 "echoserver.QSAdminCommandPlugin"); 54 myServer.startQSAdminServer(); 55 myServer.startServer(); 56 } catch(AppException e){ 57 System.out.println("Error in server : "+e); 58 } catch(Exception e){ 59 System.out.println("Error : "+e); 60 } 61 } 62 } |
在上面的代碼中,我們首先檢查是否存在一個日誌文件夾(21、22行),如果沒有先創建它。
在25行,我們嘗試獲得一個日誌器,28行,添加一個新的FileHandler,這裏我們沒有指定格式因爲默認的格式就是XML的。
在33行,我們設置日誌的控制級別爲INFO。
接下來修改EchoCommandHandler.java
01 // EchoCommandHandler.java 02 package echoserver; 03 04 import java.net.*; 05 import java.io.*; 06 import org.quickserver.net.server.ClientCommandHandler; 07 import org.quickserver.net.server.ClientHandler; 08 import java.util.logging.*; 09 10 public class EchoCommandHandler implements ClientCommandHandler { 11 12 public void gotConnected(ClientHandler handler) 13 throws SocketTimeoutException, IOException { 14 handler.sendSystemMsg("New Client : "+ 15 handler.getSocket().getInetAddress().getHostAddress(), 16 Level.INFO); 17 handler.sendClientMsg("+++++++++++++++++++++++++++++++"); 18 handler.sendClientMsg("| Welcome to EchoServer v 1.0 |"); 19 handler.sendClientMsg("| Note: Password = Username |"); 20 handler.sendClientMsg("| Send 'Quit' to exit |"); 21 handler.sendClientMsg("+++++++++++++++++++++++++++++++"); 22 } 23 public void lostConnection(ClientHandler handler) 24 throws IOException { 25 handler.sendSystemMsg("Connection lost : " + 26 handler.getSocket().getInetAddress()); 27 } 28 public void closingConnection(ClientHandler handler) 29 throws IOException { 30 handler.sendSystemMsg("Closing connection : " + 31 handler.getSocket().getInetAddress()); 32 } 33 34 public void handleCommand(ClientHandler handler, String command) 35 throws SocketTimeoutException, IOException { 36 if(command.equals("Quit")) { 37 handler.sendClientMsg("Bye ;-)"); 38 handler.closeConnection(); 39 return; 40 } 41 if(command.equals("What's interest?")) { 42 handler.sendClientMsg("Interest is : "+ 43 (String)handler.getServer().getStoreObjects()[0]+ 44 "%"); 45 } else if(command.equalsIgnoreCase("hello")) { 46 EchoServerData data = (EchoServerData) handler.getClientData(); 47 data.setHelloCount(data.getHelloCount()+1); 48 if(data.getHelloCount()==1) { 49 handler.sendClientMsg("Hello "+data.getUsername()); 50 } else { 51 handler.sendClientMsg("You told Hello "+data.getHelloCount()+ 52 " times. "); 53 } 54 } else { 55 handler.sendClientMsg("Echo : "+command); 56 } 57 } 58 } |
編譯並運行程序,現在嘗試連接,你將看到它會同時在控制檯和xml文件記錄你的IP地址。
讓我們使用QSAdminGUI設置日誌級別爲FINEST,觀察日誌內容的變化。日誌記錄增加了。另外一個改變日誌級別的方法是修改代碼,可以使用logger.setLevel()或者QuickServer的方法setLoggingLevel()來設置所有句柄的日誌級別。
2. 日誌的高級應用
當我們設置日誌級別爲FINEST時,會記錄很多信息。一個可能的需要是分離QuickServer和應用的日誌。下面的代碼允許你這麼做。
01 package echoserver; 02 03 import org.quickserver.net.*; 04 import org.quickserver.net.server.*; 05 06 import java.io.*; 07 import java.util.logging.*; 08 09 public class EchoServer { 10 public static void main(String s[]) { 11 12 String cmd = "echoserver.EchoCommandHandler"; 13 String auth = "echoserver.EchoServerQuickAuthenticator"; 14 String data = "echoserver.EchoServerPoolableData"; //Poolable 15 16 QuickServer myServer = new QuickServer(); 17 18 //setup logger to log to file 19 Logger logger = null; 20 FileHandler xmlLog = null; 21 FileHandler txtLog = null; 22 File log = new File("./log/"); 23 if(!log.canRead()) 24 log.mkdir(); 25 try { 26 logger = Logger.getLogger("org.quickserver.net"); //get QS logger 27 logger.setLevel(Level.FINEST); 28 xmlLog = new FileHandler("log/EchoServer.xml"); 29 logger.addHandler(xmlLog); 30 31 logger = Logger.getLogger("echoserver"); //get App logger 32 logger.setLevel(Level.FINEST); 33 txtLog = new FileHandler("log/EchoServer.txt"); 34 txtLog.setFormatter(new SimpleFormatter()); 35 logger.addHandler(txtLog); 36 myServer.setAppLogger(logger); //img : Sets logger to be used for app. 37 } catch(IOException e){ 38 System.err.println("Could not create xmlLog FileHandler : "+e); 39 } 40 //set logging level to fine 41 myServer.setConsoleLoggingLevel(Level.INFO); 42 43 44 myServer.setClientCommandHandler(cmd); 45 myServer.setAuthenticator(auth); 46 myServer.setClientData(data); 47 48 myServer.setPort(4123); 49 myServer.setName("Echo Server v 1.0"); 50 51 //store data needed to be changed by QSAdminServer 52 Object[] store = new Object[]{"12.00"}; 53 myServer.setStoreObjects(store); 54 55 //config QSAdminServer 56 myServer.setQSAdminServerPort(4124); 57 myServer.getQSAdminServer().getServer().setName("EchoAdmin v 1.0"); 58 try { 59 //add command plugin 60 myServer.getQSAdminServer().setCommandPlugin( 61 "echoserver.QSAdminCommandPlugin"); 62 myServer.startQSAdminServer(); 63 myServer.startServer(); 64 } catch(AppException e){ 65 System.out.println("Error in server : "+e); 66 } catch(Exception e){ 67 System.out.println("Error : "+e); 68 } 69 } 70 } |
代碼中的註釋說明的很清楚了。編譯並運行,連接後你將看見QuickServer內部的日誌記錄到了xml文件,應用級別的日誌記錄到了我們想要的txt文件。
注意:
要儘量減少控制檯中的日誌數量,使用文件記錄詳細的日誌,並降低日誌的級別。這樣可以改善應用的性能。避免使用System.out.println(),用logging代替。ClientHandler中的sendSystemMsg()方法在記錄日誌方面很有用。