首页 > 学院 > 开发设计 > 正文

【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:11.定制化Log输出

2019-11-15 00:11:07
字体:
来源:转载
供稿:网友
【迷你微信】基于MINA、Hibernate、SPRing、Protobuf的即时聊天系统:11.定制化Log输出

欢迎阅读我的开源项目《迷你微信》服务器与《迷你微信》客户端

前言

在《迷你微信》服务器中,我们用了Log4J来进行输出,这可以在我们程序出现异常的时候找到错误发生时的上下文。然而吗,在项目的组件迭代过程中,我们发现,log出来的内容越来越多,往往在储蓄出现异常去查Log的时候,会被一大堆不相干的Log给淹没,这时,我们想:如果能够只输出我要的那部分岂不是很爽,这样就能快速的找到我们要的Log了,所以博主自己别编写了一个定制化输出的方法。

Log4J的Name

Log4J在创建时是需要设置名称的,可以把它理解成一个索引,以此在其他地方拿到它。

public class MyLogTest {private Logger logger = Logger.getLogger(this.getClass().getSimpleName());ppublic void method_1(){logger.info("abcdefg");}}public class Test_2 {public Logger getMyLogger(String name){return Logger.getLogger(name);}}

上述MyLogTest类中,我们用类名创建了一个Log4J的Logger对象,在第二个类Test_2中,我们有一个getMyLogger方法,如果我们调用时传入的是MyLogTest的类名,则会返回MyLogTest中的那个Logger对象。

注:Logger.getLogger(name) 方法在以name命名对象不存在时,会创建一个新的返回,当已经被创建后调用则会返回之前创建过的那个Logger对象。

定制化Log输出配置xml

想要做到定制化Log输出,我们需要有一个配置文件来设置哪些Logger输出,哪些不输出。(详细源码请参考《迷你微信》服务器)

<?xml version=""1.0" encoding="UTF-8"?><LoggerRule><TypeContain>False</TypeContain><TypeList><ProtoHead logType="class">server.Server_User</ProtoHead></TypeList></LoggerRule>

先来解释一下上述代码所代表的意义:

  • LoggerRule : 代表Log规则的根,内不包含所有规则
  • TypeContain :参数为True时,代表包含,只输出列表中所述Logger的内容,Flase代表“除外”,即下面列表所述的Logger都不输出。
  • ProtoHead :每一个(不)要输出的条目(注:叫这个名字时历史遗留问题)

整体来说,就是在项目运行时,叫server.Server_User这个名字的Logger将被忽略输出。

编写读取类
private void readLogRule() {        DocumentBuilderFactory domfac=DocumentBuilderFactory.newInstance();try {            DocumentBuilder dombuilder=domfac.newDocumentBuilder();            InputStream is=new FileInputStream(LoggerXML);                Document doc=dombuilder.parse(is);        Element root = doc.getDocumentElement(); // 获取根元素String typeContain = root.getElementsByTagName("TypeContain").item(0).getFirstChild().getNodeValue().toString();loggerRule = new LoggerRule(typeContain.equals("True") ? LoggerType.Contain: LoggerType.Ignore);NodeList nodeList = root.getElementsByTagName("ProtoHead");Node node1, node2;NamedNodeMap namedNodeMap;String nodeValue;for (int i=0; i<nodeList.getLength(); i++) {node1 = nodeList.item(i);namedNodeMap = node1.getAttributes();for (int j=0; j<namedNodeMap.getLength(); j++) {node2 = namedNodeMap.item(j);if (node2.getNodeName().equals("logType")) {nodeValue = node1.getFirstChild().getNodeValue().toString();if (node2.getNodeValue().equals("Network")) {// 显示服务器发了什么包的LogloggerRule.loggerSet.add(ProtoHead.ENetworkMessage.valueOf(nodeValue));} else if (node2.getNodeValue().equals("class")) {loggerRule.logCalssList.add(nodeValue);}}}}} catch (Exception e) {logger.error("MyLogger : load " + LoggerXML + " file error!/n" + MyException.getStackStr(e.getStackTrace()));}}class LoggerRule {public static enum LoggerType {Contain, Ignore};public LoggerType loggerType;HashSet<ProtoHead.ENetworkMessage> loggerSet;public ArrayList<String> logCalssList;public LoggerRule(LoggerType loggerType) {this.loggerType = loggerType;loggerSet = new HashSet<ProtoHead.ENetworkMessage>();logCalssList = new ArrayList<String>();}}

通过上面这个方法,我们从配置文件中读出了我们制定的输出规则,存储在一个ArrayList中,接着,只要进行以此遍历,将指定的Logger关掉即可:

public void closeLoggerNotWant(){for (String className : loggerRule.logCalssList)Logger.getLogger(className).setAdditivity(false);}
优点

通过这种方式,我们实现了配置编程,在不修改项目源码的前提下,我们可以通过修改配置文件的方式来设置哪些Logger不惊醒输出。甚至,在对上述程序做一些修改后,可以动态的进行变化(如:定时读取XML),即可以在不重启整个进程的前提下修改输出设置。

欢迎阅读我的开源项目《迷你微信》服务器与《迷你微信》客户端


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表