加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

log4j 日志文件配置(控制台打印、生成日志文件、写入数据库)

(2014-06-10 15:06:24)
分类: web杂谈
参考文献:http://blog.csdn.net/ziruobing/article/details/3919501
   log4j是一个优秀的开源日志记录项目,我们不仅可以对输出的日志的格式自定义,还可以自己定义日志输出的目的地,比如:屏幕,文本文件,数据 库,甚至能通过socket输出。本节主要讲述如何将日志信息输入到数据库(可以插入任何数据库,在此主要以MSSQL为例进行详解)。
用 log4j将日志写入数据库主要用到是log4j包下的JDBCAppender类,它提供了将日志信息异步写入数据的功能,我们可以直接使用这个类将我 们的日志信息写入数据库;也可以扩展JDBCAppender类,就是将JDBCAppender类作为基类。下面将通过一个实例来讲解log4j是如何 将日志信息写入数据库的。
我们的需求:我们在软件开发的过程中需要将调试信息、操作信息等记录下来,以便后面的审计,这些日志信息包括用户ID、用户姓名、操作类、路径、方法、操作时间、日志信息。
设 计思想:我们采用JDBCAppender类直接将日志信息插入数据库,所有只需要在配置文件配置此类就可以;要获得用户信息需要用过滤器来实现;(假如 不需要用户的信息,就不需要设计过滤器,其实大部分情况下都是需要这些用户信息,尤其是在web应用开发中)在日志信息中获得用户信息,就的通过过滤器的 request或session对象,从session中拿到用户信息怎样传到log4j呢,log4j为我们提供了MDC(MDC是log4j种非常有 用类,它们用于存储应用程序的上下文信息(context infomation),从而便于在log中使用这些上下文信息。MDC内部使用了类似map的机制来存储信息,上下文信息也是每个线程独立地储存,所不 同的是信息都是以它们的key值存储在”map”中。相对应的方法,

MDC.put(key, value); MDC.remove(key); MDC.get(key);

在配置PatternLayout的时候使用:%x{key}来输出对应的value)。有了MDC,我们可以在过滤器中先获得用户信息,再用MDC.Put(“key”)方法,log在执行sql语句时通过%X{key}来输出对应的value。

实现步骤:
1、在你的项目中要确保有log4j和commons-logging这两个jar文件;
2、设置要你要插入日志信息的表结构:

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[WDZLOG]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[WDZLOG]
GO

CREATE TABLE [dbo].[WDZLOG] (
    [WDZLOGID] [int] IDENTITY (1, 1) NOT NULL ,
    [LogName] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,//用户ID
    [UserName] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,//用户姓名
    [Class] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,//类名
    [Mothod] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL //,方法名
    [CreateTime] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,//产生时间
    [LogLevel] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,//日志级别
    [MSG] [varchar] (555) COLLATE Chinese_PRC_CI_AS NULL //日志信息
) ON [PRIMARY]
GO
3、创建配置文件(log4j.properties:一般放在web项目的根目录下,我是直接放在src下的):

# 参数
# %p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
# %d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
# %r: 输出自应用启动到输出该log信息耗费的毫秒数
# %c: 输出日志信息所属的类目,通常就是所在类的全名
# %t: 输出产生该日志事件的线程名
# %l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
# %x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
# %%: 输出一个”%”字符
# %F: 输出日志消息产生时所在的文件名称
# %L: 输出代码中的行号
# %m: 输出代码中指定的消息,产生的日志具体信息
# %n: 输出一个回车换行符,Windows平台为”\r\n”,Unix平台为”\n”输出日志信息换行
# 可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:
# 1) c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。
# 2)%-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,”-”号指定左对齐。
# 3)%.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
# 4) .30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边交远销出的字符截掉


log4j.appender.encoding = UTF-8
####################定义3个输出端###################
log4j.rootLogger=INFO,dailyFile,A1,A3

# 每天产生一个日志文件(dailyFile)
log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender
#当天的日志文件全路径
log4j.appender.dailyFile.File=${catalina.base}/logs/hcart/hcart.log
#服务器启动日志是追加,false:服务器启动后会生成日志文件把老的覆盖掉
log4j.appender.dailyFile.Append=true
#日志文件格式 
log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.dailyFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%t] %c %x - %m%n
log4j.appender.dailyFile.Threshold=INFO
#设置每天生成一个文件名后添加的名称,备份名称:年月日.log
log4j.appender.dailyFile.DatePattern='.'yyyy-MM-dd'.log'

#定义A1输出到控制器
log4j.appender.A1=org.apache.log4j.ConsoleAppender
#定义A1的布局模式为PaternLayout
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
# 定义A1的输出格式
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%t] %F:%L - %m%n


#定义A3输出到数据库
log4j.appender.A3=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.A3.URL=jdbc:mysql://localhost:3306/hcart?characterEncoding=utf8
log4j.appender.A3.driver=com.mysql.jdbc.Driver
log4j.appender.A3.user=root
log4j.appender.A3.password=123456
#定义A3的布局和执行的SQL语句
log4j.appender.A3.layout=org.apache.log4j.PatternLayout
log4j.appender.A3.Threshold=FATAL
log4j.appender.A3.sql=INSERT INTO log4j(loguserid,logusername,loguseMothod,createDate,thread,level,class,message) values('%X{clerk_id}','%X{clerk_name}','%M','%d{yyyy-MM-dd HH:mm:ss}','%t','%-5p','%c','%m')

4、编写过滤器(ResFilter.java)

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.MDC;

public class LoginFilter extends HttpServlet implements Filter {

   
    private static final long serialVersionUID = 1L;
   
    private final static double DEFAULT_USERID= Math.random()*100000.0;

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub

    }
   
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
         
        //这里设置如果没有登陆将要转发到的页面
           RequestDispatcher dispatcher = request.getRequestDispatcher("/jsp/admin/login.jsp");
           HttpServletRequest req = (HttpServletRequest) request;  
           HttpServletResponse res = (HttpServletResponse) response;  
           HttpSession session = req.getSession(true);  
         
           if (session==null){ 
                MDC.put("clerk_id",DEFAULT_USERID);   
            }else{
                 // 从session里取的用户id
                String clerk_id = (String) session.getAttribute("clerk_id");//这里获取session,为了检查session里有没有保存用户信息,没有的话回转发到登陆页面  
                 String clerk_name=(String)session.getAttribute("clerk_name");
               // 判断如果没有取到用户信息,就跳转到登陆页面  
               if (clerk_id == null || "".equals(clerk_id))  
                
                  MDC.put("clerk_id",DEFAULT_USERID); 
                 MDC.put("clerk_name",DEFAULT_USERID);
                // 跳转到登陆页面  
                 dispatcher.forward(request,response);  
                 System.out.println("用户没有登陆,不允许操作");  
                 res.setHeader("Cache-Control","no-store");     
                 res.setDateHeader("Expires",0);  
                 res.setHeader("Pragma","no-cache");  
                }else{  
                // 已经登陆,继续此次请求  
                 chain.doFilter(request,response);  
                 System.out.println("用户已经登陆,允许操作");
                MDC.put("clerk_id",clerk_id); 
               MDC.put("clerk_name",clerk_name);
                }
            }
    }
   
     public void destroy()
      
         
     }

}

5、在需要写入日志的地方引入

private Log logger = LogFactory.getLog(this.getClass());
在具体方法中就可以写入日志
logger.info("");
logger.debug("");
logger.warn("");
logger.error("");

注意:有的用户不希望在控制台打印过多的信息,而我们调试程序的时候,需要打印信息,所以,一般将logger的记录为logger.debug("");这样,当项目正式启动的时候,若不想打印相关信息到控制台,将日志文件的输入等级设置为info就可以了;相对的,我需要一些指定的信息写入数据库,为了写入过多不必要的信息,我写入数据库的日志等级都设置为fatal的

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有