Java进阶(五十二)利用LOG4J生成服务日志

时间:2023-03-08 18:41:28

Java进阶(五十二)利用LOG4J生成服务日志

前言

由于论文写作需求,需要进行流程挖掘。前提是需要有真实的事件日志数据。真实的事件日志数据可以用来发现、监控和提升业务流程。

为了获得真实的事件日志数据,决定采用Log4J日志生成工具。首先,对工具有个大致的了解:日志是应用软件中不可缺少的部分,Apache的开源项目Log4j是一个功能强大的日志组件,提供方便的日志记录。

Log4j下载

在apache网站:http://logging.apache.org/log4j/1.2/download.html

可以免费下载到Log4j最新版本的软件包。

Log4j使用

Log4j的包下载完成后,解压,将其中打包好的的log4j-1.x.x.jar导入你的工程lib中。

Log4j之所以受欢迎的原因之一是它的灵活性。Log4j提供了灵活的配置方法,默认是调用BasicConfigurator.configure()来进行配置,但如果只是简单的调用BasicConfigurator.configure()来进行配置工作,那么所有的配置都是固定的,不方便以后修改配置。另一种是动态配置,Log4j提供了PropertyConfigurator.configure(……)来动态配置,参数可以是一个properties文件所在路径的String对象,可以是一个properties文件所在路径的URL对象,也可以是一个properties对象。如果要用XML文件来配置信息,则可用类型的DOMConfigurator()函数来从一个XML文件中加载配置信息。这种方式更方便修改配置。

package http;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
public class Log4jDemo {
     static Logger log = Logger.getLogger(Log4jDemo.class.getClass());
     public static void main(String[] args) {
         BasicConfigurator.configure();//默认配置
         PropertyConfigurator.configure("c:/log4j.properties");
//动态配置,参数可以是一个properties文件所在路径的String对象
//可以是一个properties文件所在路径的URL对象,也可以是一个properties对象
//PropertyConfigurator.configure()的参数还可以是XML、Properties对象
         DOMConfigurator.configure("c:/log4j.xml");//XML配置文件
         //下面就可使用log4j
         log.info("info");
         log.debug("debug");
         log.error("error");
         log.warn("warn");
     }
 }  

J2EE应用log4j

在J2EE应用使用Log4j,必须先在启动服务时加载Log4j的配置文件进行初始化,可以在web.xml中进行。

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;   

public class J2eeLog4jDemo extends HttpServlet {
    public void destroy() {
        super.destroy();
    }
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
    public void init() throws ServletException {
        //通过web.xml来动态取得配置文件
        String prefix = getServletContext().getRealPath("/");
        String file = getInitParameter("log4j");
        //如果没有给出相应的配置文件,则不进行初始化
        if(file != null)
        {
            PropertyConfigurator.configure(prefix+file);
        }
    }
}

Web.xml 代码

<servlet>
    <servlet-name>j2eelog4jdemo<servlet-name>
    <servlet-class>J2eeLog4jDemo<servlet-class>
    <init-param>
    <param-name>log4j<param-name>
    <param-value>log4j.properties<param-value>
    </init-param>
    <load-on-startup>1<load-on-startup> //设为1时Web容器启动即进行加载
</servlet> 

Log4j配置内容

Log4j配置内容主要是依据配置文件log4j.properties:

#指定根Logger,及日志输出级别

#大于等于该级别的日志将被输出( DEBUG < INFO < WARN < ERROR < FATAL ),设为OFF可以关闭日志,指定日志信息输出到哪个地方。可以同时指定多个输出目的地。

log4j.rootLogger=DEBUG, A1,A2

#指定log输出目的,这里设为输出日志到指定目录的文件my.log中

log4j.appender.A1=org.apache.log4j.FileAppender

log4j.appender.A1.File=\\logs\\my.log   #当前根目录下

#指定日志信息的格式

log4j.appender.A1.layout=org.apache.log4j.PatternLayout

log4j.appender.A1.layout.ConversionPattern=%r %d{yyyy-MM-dd HH:mm:ss} %c %p -%m%n

#把A2输出到控制台

log4j.appender.A2=org.apache.log4j.ConsoleAppender

log4j.appender.A2.layout=org.apache.log4j.SimpleLayout

#还可以单独指定输出某个包的日志级别

#log4j.logger.com.study.HelloLog4j=INFO

1、配置根Logger

其语法为: log4j.rootLogger = [ level ] , appenderName, appenderName2

level:日志的级别,指定这条日志信息的重要性。分为ALL < DEBUG < INFO < WARN < ERROR < FATAL。一般常用的为 DEBUG , INFO ,WARN ,ERROR四种,分别对应Logger类的四种方法

debug(Object message ) ;

info(Object message ) ;

warn(Object message ) ;

error(Object message ) ;

如果设置级别为INFO,则优先级大于等于INFO级别(如:INFO、WARN、ERROR)的日志信息将可以被输出,小于该级别的如:DEBUG将不会被输出

appenderName :就是指定日志信息输出目的地,比如(打印到控制台,输出到文件等)。同一条日志信息可以配置多个输出目的地。

2、配置log输出目的地

Log4j提供以下几种:

org.apache.log4j.ConsoleAppender(控制台)

org.apache.log4j.FileAppender(文件)

org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)

org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)

org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

3、log信息的格式

org.apache.log4j.HTMLLayout(HTML表格形式)

org.apache.log4j.SimpleLayout(简单格式的日志,只包括日志信息的级别和指定的信息字符串 ,如:DEBUG - Hello)

org.apache.log4j.TTCCLayout(日志的格式包括日志产生的时间、线程、类别等等信息)

org.apache.log4j.PatternLayout(灵活地自定义日志格式)

当使用org.apache.log4j.PatternLayout来自定义信息格式时,可以使用

log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p -%m%n 来格式化信息

%c    输出所属类的全名,可写为 %c{Num} ,Num类名输出的范围  如:"com.sun.aaa.classB", %C{2}将使日志输出输出范围为:aaa.classB

%d    输出日志时间其格式为 可指定格式 如 %d{HH:mm:ss}等

%l    输出日志事件发生位置,包括类目名、发生线程,在代码中的行数

%n    换行符

%m    输出代码指定信息,如info(“message”),输出message

%p    输出日志的优先级,即 FATAL ,ERROR 等

%r    输出从启动到显示该条日志信息所耗费的时间(毫秒数)

%t    输出产生该日志事件的线程名

更详细参数信息可参看类org.apache.log4j.PatternLayout的API doc文档

后知后觉

经过查看,才发现原来项目中已经使用了log4j,自己需要给其再加上时间戳。不过这些日志还得经过后期的处理,因为现在的信息太琐碎了。

以下为某一交易的日志数据:

[21:20:52][weiming.lmapp.servlet.DoUpdate] pkgtype=json

[21:20:52][weiming.lmapp.servlet.DoUpdate] content-length=106

[21:20:52][weiming.lmapp.servlet.RequestMessage] receiver:{"billtype":"1236","version":"1.0","fore_time":"2015-12-09 21:20:52","uid":"18853883588","tx_code":"9010"}

[21:20:52][weiming.lmapp.trans.Transaction]

------------Order_Query_9010 debug info-------------

请求数据包信息:{"billtype":"1236","version":"1.0","fore_time":"2015-12-09 21:20:52","uid":"18853883588","tx_code":"9010"}

[21:20:52][weiming.lmapp.trans.Transaction] stat:[1]

[21:20:52][weiming.lmapp.trans.Transaction] stat:[2]

[21:20:52][weiming.lmapp.trans.Transaction] stat:[3]

[21:20:52][weiming.lmapp.trans.Transaction] stat:[6]

[21:20:52][weiming.lmapp.trans.Transaction] 查询条件:[buy_uid='U18853883588' AND ( stat='1' OR stat='2' OR stat='3' OR stat='6' )ORDER BY tx_time DESC]

[21:20:52][weiming.database.lmapp.MyDatabase] sqlstr=select billid,tx_time,buy_uid,merch_uid,msg,old_amt,amt,receiver,tel,buy_addr,stat,pay_type,pl_stat from lm_bill where buy_uid='U18853883588' AND ( stat='1' OR stat='2' OR stat='3' OR stat='6' )ORDER BY tx_time DESC limit 0,1000

[21:20:52][weiming.lmapp.trans.Transaction] count:[1]

[21:20:52][weiming.database.lmapp.MyDatabase]sqlstr=select billid,cnt,medid,medname,medcnt,medprice,medamt,cfid from lm_bill_dtl where billid='LM2015120935888906' limit 0,1000

[21:20:52][weiming.lmapp.servlet.DoUpdate] Transaction 9010 success

[21:20:52][weiming.lmapp.servlet.RequestMessage] OUTSTR:

{"cnt":1,"data":[{"med_amt":8,"amt":8,"med_cnt":1,"tx_time":"2015-12-09 21:20:49","medname":"感冒灵颗粒","medid":"TZ20055267","stat":"1","billid":"LM2015120935888906"}],"result":"0000","errtext":""}

经过观察,发现以上日志数据并不完全满足自己的需求,需做进一步的改进。改进后产生的日志信息如下:

[15/12/09 21:50:36:332][weiming.lmapp.servlet.DoUpdate] pkgtype=json

[15/12/09 21:50:36:333][weiming.lmapp.servlet.DoUpdate] content-length=107

[15/12/09 21:50:36:333][weiming.lmapp.servlet.RequestMessage] receiver:{"billtype":"12369","version":"1.0","fore_time":"2015-12-09 21:50:36","uid":"18853883588","tx_code":"9010"}

[15/12/09 21:50:36:333][weiming.lmapp.trans.Transaction]

------------Order_Query_9010 debug info-------------

请求数据包信息:{"billtype":"12369","version":"1.0","fore_time":"2015-12-09 21:50:36","uid":"18853883588","tx_code":"9010"}

[15/12/09 21:50:36:333][weiming.lmapp.trans.Transaction] stat:[1]

[15/12/09 21:50:36:334][weiming.lmapp.trans.Transaction] stat:[2]

[15/12/09 21:50:36:334][weiming.lmapp.trans.Transaction] stat:[3]

[15/12/09 21:50:36:334][weiming.lmapp.trans.Transaction] stat:[6]

[15/12/09 21:50:36:334][weiming.lmapp.trans.Transaction] stat:[9]

[15/12/09 21:50:36:334][weiming.lmapp.trans.Transaction] 查询条件:[buy_uid='U18853883588' AND ( stat='1' OR stat='2' OR stat='3' OR stat='6' OR stat='9' )ORDER BY tx_time DESC]

[15/12/09 21:50:36:334][weiming.database.lmapp.MyDatabase] sqlstr=select billid,tx_time,buy_uid,merch_uid,msg,old_amt,amt,receiver,tel,buy_addr,stat,pay_type,pl_stat from lm_bill where buy_uid='U18853883588' AND ( stat='1' OR stat='2' OR stat='3' OR stat='6' OR stat='9' )ORDER BY tx_time DESC limit 0,1000

[15/12/09 21:50:36:335][weiming.lmapp.trans.Transaction] count:[1]

[15/12/09 21:50:36:336][weiming.database.lmapp.MyDatabase] sqlstr=select billid,cnt,medid,medname,medcnt,medprice,medamt,cfid from lm_bill_dtl where billid='LM2015120935888906' limit 0,1000

[15/12/09 21:50:36:337][weiming.lmapp.servlet.DoUpdate] Transaction 9010 success

[15/12/09 21:50:36:338][weiming.lmapp.servlet.RequestMessage] OUTSTR:

{"cnt":1,"data":[{"med_amt":8,"amt":8,"med_cnt":1,"tx_time":"2015-12-09 21:20:49","medname":"感冒灵颗粒","medid":"TZ20055267","stat":"9","billid":"LM2015120935888906"}],"result":"0000","errtext":""}

通过观察可以发现,以上日志主要包含的信息有:服务请求者、服务时间段、服务内容、服务结果

org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)

学术需要,现在自己需要实现按日期生成日志文档,log4j配置如下:

log4j.appender.appender2=org.apache.log4j.DailyRollingFileAppender
log4j.appender.appender2.DatePattern=yyyy-MM-dd'.log'
log4j.appender.appender2.layout=org.apache.log4j.PatternLayout
log4j.appender.appender2.layout.ConversionPattern=[%d{yy/MM/dd 	HH:mm:ss:SSS}][%c] %m%n
log4j.appender.appender2.File=e\:\\MyEclipse10\\logs\\log_

当天生成的日志,保存在项目的根路径下的","tx_code":""}

[15/12/09 22:02:21:532][weiming.lmapp.trans.Transaction]

------------Order_Query_9010 debug info-----------

请求数据包信息:

{"billtype":"1236","version":"1.0","fore_time":"2015-12-09 22:02:22","uid":"18853883588","tx_code":"9010"}

[15/12/09 22:02:21:547][weiming.lmapp.trans.Transaction] stat:[1]

[15/12/09 22:02:21:547][weiming.lmapp.trans.Transaction] stat:[2]

[15/12/09 22:02:21:547][weiming.lmapp.trans.Transaction] stat:[3]

[15/12/09 22:02:21:547][weiming.lmapp.trans.Transaction] stat:[6]

[15/12/09 22:02:21:547][weiming.lmapp.trans.Transaction] 查询条件:

[buy_uid='U18853883588' AND ( stat='1' OR stat='2' OR stat='3' OR stat='6' )ORDER BY tx_time DESC]

[15/12/09 22:02:21:547][weiming.database.lmapp.MyDatabase] sqlstr=

selectbillid,tx_time,buy_uid,merch_uid,msg,old_amt,amt,receiver,tel,buy_addr,stat,pay_type,pl_stat from lm_bill where buy_uid='U18853883588' AND ( stat='1' OR stat='2' OR stat='3' OR stat='6' )ORDER BY tx_time DESC limit 0,1000

[15/12/09 22:02:21:595][weiming.lmapp.trans.Transaction] count:[0]

[15/12/09 22:02:21:595][weiming.lmapp.trans.Transaction]

[15/12/0922:02:21:595][weiming.lmapp.servlet.DoUpdate]Transaction 9010 error

[15/12/09 22:02:21:595][weiming.lmapp.servlet.RequestMessage] OUTSTR:

{"cnt":0,"result":"9999","errtext":"无订单信息"}

获取到了数据源信息,自己就需要做进一步的处理了。