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()方法在记录日志方面很有用。