原文链接:http://www.cnblogs.com/shenliang123/archive/2012/05/02/2479286.html

由于最近正在扩展卫生局考务系统,由于上一次使用过一次该系统后,发现很多考生最后出现说已打印报名表但却在数据库中找不到她的报名记录;

因此为了以后有依据,将所有用户的操作日志文件写入数据供管理员查询成为了这次扩张项目的一个内容;

这里我决定使用的log4j日志文件,在多次的使用中感觉这个很不错;

首先我们要使用log4j日志文件时,我们需将两个必须的包放入lib目录下:log4j.XX.jar和commons-logging.XX.jar;

然后在classpath目录下(IDE中即为项目下的src目录下)新建一个日志文件,统一命名为:log4j.properties;

1.需求一:只需要满足存储数据库:

a.以下我们一ms sql 2000为例:首先在数据库中建一个用来存储日志的数据库命名为 operate_log;字段如下:

b.数据库成功建立后,就可以去配置日志文件log4j.properties,代码如下:

log4j.properties  

log4j.rootLogger=INFO,db

########################  

# JDBC Appender  

#######################  

#log4j.logger.business=INFO,db
#log4j.appender.db=com.neam.commons.MyJDBCAppender log4j.appender.db=org.apache.log4j.jdbc.JDBCAppender log4j.appender.db.BufferSize=1 log4j.appender.db.driver=net.sourceforge.jtds.jdbc.Driver log4j.appender.db.URL=jdbc:jtds:sqlserver://localhost:1433;DatabaseName=infor_manage
#enter
log4j.appender.db.user=sa log4j.appender.db.password=123
log4j.appender.db.sql=insert into operate_log(class,method,createtime,loglevel,logmsg,user_id,user_type) values ('%C','%M','%d{yyyy-MM-dd HH\:mm\:ss}','%p','%m','1',1) log4j.appender.db.layout=org.apache.log4j.PatternLayout

上面的配置就是最精简的将日志内容直接存储进入数据库
下面来稍微解释:

log4j.rootLogger=INFO,db语法为:

##log4j.rootLogger = [ level ] , appenderName1, appenderName2, …
##level : 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、##WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志##信息将不被打印出来。
##appenderName:就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。
##例如:log4j.rootLogger=info,A1,B2,C3 配置了3个输出地方,这个名字可以任意(如上面的db),但必须与我们在后面进行的设置名字对应;

然后下面就是进行数据库连接的配置,log4j是使用jdbc进行连接的,该封转的类就是log4j包下的 org.apache.log4j.jdbc.JDBCAppender,大家对jdbc了解的话上面的内容应该是很简单的;

这里要注意的就是:1.记得把数据库连接的相关包放到lib目录下,2.在写连接数据库的信息时如user等注意后面不要有空格,否则就不能连上数据库

c.日志文件配置完成后,我们就可以进行测试了,我们可以随便在后台写一个类:

package xidian.sl.action.admin;

import org.apache.log4j.Logger;

import com.opensymphony.xwork2.ActionSupport;

public class HelloWorld extends ActionSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
private static final Logger log = Logger.getLogger(HelloWorld.class);//日志文件 public static void main(String[] args) {
log.error("访问了HelloWorld");
log.warn("访问了HelloWorld");
log.info("访问了HelloWorld");
log.debug("访问了HelloWorld");
}
}

然后右键运行,如果没有报错的话应该是成功了,可以去数据库看看:

可以看到日志信息已经进行了存储,但发现只有三条,少了debug,对了,由于我们进行了日志优先级的配置:log4j.rootLogger=INFO,db,只有debug级别就不能进行打印了;

到这里我们可以说基本成功了,但还远远不能满足我的需求:

我们发现数据库中出现了很多的日志信息,这个日志信息应该是启动等,从系统文件(spring等)中打印的,但这个其实不是我们需要的,或者说我们需要将其分开:

我们重新进行日志文件的配置

log4j.properties  

log4j.rootLogger=INFO,stdout
log4j.logger.xidian=INFO,db
log4j.logger.org=WARN, A1
log4j.logger.com =WARN, A2 #stdout\u5e94\u7528\u4e8e\u63a7\u5236\u53f0
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%d %5p (%c\:%L) - %m%n #A1\u5e94\u7528\u4e8e\u6587\u4ef6\u56de\u6eda
log4j.appender.A1=org.apache.log4j.RollingFileAppender
log4j.appender.A1.File=${webapp.root}/WEB-INF/logs/org.log
log4j.appender.A1.MaxFileSize=500KB
log4j.appender.A1.MaxBackupIndex=50
log4j.appender.A1.Append=true
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} - [%p] [%C{1}] - %m%n #A2\u5e94\u7528\u4e8e\u6587\u4ef6\u56de\u6eda
log4j.appender.A2=org.apache.log4j.RollingFileAppender
log4j.appender.A2.File=${webapp.root}/WEB-INF/logs/com.log
log4j.appender.A2.MaxFileSize=500KB
log4j.appender.A2.MaxBackupIndex=50
log4j.appender.A2.Append=true
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} - [%p] [%C{1}] - %m%n ######################## # JDBC Appender ####################### #log4j.logger.business=INFO,db
#log4j.appender.db=com.neam.commons.MyJDBCAppender log4j.appender.db=org.apache.log4j.jdbc.JDBCAppender log4j.appender.db.BufferSize=1 log4j.appender.db.driver=net.sourceforge.jtds.jdbc.Driver log4j.appender.db.URL=jdbc:jtds:sqlserver://localhost:9433;DatabaseName=infor_manage
#enter
log4j.appender.db.user=sa log4j.appender.db.password=123@sports log4j.appender.db.sql=insert into operate_log(class,method,createtime,loglevel,logmsg,user_id,user_type) values ('%C','%M','%d{yyyy-MM-dd HH\:mm\:ss}','%p','%m','1',1) log4j.appender.db.layout=org.apache.log4j.PatternLayout

这次的配置要复杂点

log4j.logger.xidian=INFO,db  
log4j.logger.org=WARN, A1
log4j.logger.com =WARN, A2

这个配置就是将不同的包下的信息输出到不同的文件中,根据下面的配置可知以xidian开头的包下的java文件的日志信息时进行数据库存储的,而org与com包开头的日志信息是输出到文件中,文件的输出地址是${webapp.root}/WEB-INF/logs/org.log即项目的WEB-INF目录下的logs文件夹中,为了得到${webapp.root}我们还需要到web.xml文件中进行配置:

 <!--由Sprng载入的Log4j配置文件位置-->
<context-param>
<param-name>log4jConfigLocation</param-name> <param-value>classpath:log4j.properties</param-value>
</context-param>
<!--Spring log4j Config listener-->
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>

这样我们再次运行HelloWorld程序
查看数据库(很干净了,哈哈):

然后在到WEB-INF目录下的logs文件夹中查看输出的日志文件:

由于我们在根Logger下也进行了配置:这个根Logger的配置是对所有日志操作都是有作用的

log4j.rootLogger=INFO,stdout

#stdout\u5e94\u7528\u4e8e\u63a7\u5236\u53f0
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%d %5p (%c\:%L) - %m%n

这个配置是进行控制太的输出,因此我们在控制台中也会发现有输出:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

到此为止我们日志的基本操作都应该掌握了,但我还有一个需求没有满足,就是我一开始数据库字段的设计中还包含了两个字段:

这两个字段是存储用户的id和用户类型的,以便我们在后面日志的核查中能正确的找出用户信息;但这里就有一个问题了我们就靠上面的操作还是不能将用户信息得到的,

还有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中,然后再在log4j.properties配置文件中的sql语句中进行读取:

过滤器代码:

package xidian.sl.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession; import org.apache.log4j.MDC; public class LogResFilter implements Filter { private final static double DEFAULT_USERID= 0.0; @Override
public void destroy() { } @Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//System.out.println("进入过滤器");
HttpServletRequest req=(HttpServletRequest)request;
HttpSession session= req.getSession();
if (session==null){
MDC.put("userId",DEFAULT_USERID);
MDC.put("userType",DEFAULT_USERID);
}
else{
//StuInfor stuInfor =(StuInfor)session.getAttribute("admin");
//用户的id
Integer userId = (Integer)session.getAttribute("userId");
//用户的类型
String adminType = (String)session.getAttribute("adminType");
if (userId == null&& adminType == null){
MDC.put("userId",DEFAULT_USERID);
MDC.put("userType",DEFAULT_USERID);
}
else
{
System.out.println("用户id"+userId+ "类型"+ adminType);
MDC.put("userId", userId);
MDC.put("userType", adminType);
}
}
chain.doFilter(request, response);
} @Override
public void init(FilterConfig arg0) throws ServletException { } }

然后在web.xml中进行过滤器的配置:

    <filter>
<filter-name>LogResFilter</filter-name>
<filter-class>xidian.sl.filter.LogResFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LogResFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>

这样用户登录后存储在session中的信息通过该过滤器就存储MDC中,然后我们在日志文件中写sql语句:

log4j.appender.db.sql=insert into operate_log(class,method,createtime,loglevel,logmsg,user_id,user_type) values ('%C','%M','%d{yyyy-MM-dd HH\:mm\:ss}','%p','%m','%X{userId}','%X{adminType}')  

到这里我的需求基本上满足了,不知道有没有满足你的需求。

【转】玩转log4j的更多相关文章

  1. 玩转log4j

    我的目标是授人以渔,而不是授人以鱼,我相信你仔细看完这篇文章,玩转log4j不成问题 先来一个log4j最简单的例子 public class MyApp { static Logger logger ...

  2. 玩转Spring MVC(五)----在spring中整合log4j

    在前边的基础上,本文主要总结一下如何在spring 中配置log4j,在本文末尾会给出完整项目的链接. 首先是web.xml中要新添加的代码: <!-- 6. 配置log4j --> &l ...

  3. 项目自动化建构工具gradle 入门2——log4j输出helloWorld

    上一章节呢,有一个能跑的程序了.但是对做工程的人来说,用日志输出感觉比用System.out要有档次一点.比如使用log4j.直接上例子: 1进入D:\work\gradle\log目录  ,您电脑没 ...

  4. 玩转Nodejs日志管理log4js(转)

    转自:http://blog.fens.me/nodejs-log4js/ 前言 日志对任何的应用来说都是至关重要的.在Nodejs中使用express框架并没有自带的日志模块,我们可以选择log4j ...

  5. 玩转mongodb(九):通过log4jmongo来实现分布式系统的日志统一管理

    背景 在分布式系统中,我们有多个web app,这些web app可能分别部署在不同的物理服务器上,并且有各自的日志输出.当生产问题来临时,很多时候都需要去各个日志文件中查找可能的异常,相当耗费人力. ...

  6. (转)log4j(一)——为什么要用log4j?

    1 试验环境 OS:win7 JDK:jdk7 Log4j:1.2.17(好尴尬,原本是想试验下log4j2的,结果阴差阳错用了这个版本,不过幸好,试验也不白试验,试验的作用是一样的) 2 先看两个简 ...

  7. log4j(一)——为什么要用log4j?

    一:试验环境 OS:win7 JDK:jdk7 Log4j:1.2.17(好尴尬,原本是想试验下log4j2的,结果阴差阳错用了这个版本,不过幸好,试验也不白试验,试验的作用是一样的) 二:先看两个简 ...

  8. Java logger组件:slf4j, jcl, jul, log4j, logback, log4j2

    先说结论 建议优先使用logback 或 log4j2.log4j2 不建议和 slf4j 配合使用,因为格式转换会浪费性能. 名词:jcl 和 jul 标题中的 jcl 是 apache Jakar ...

  9. log4j.xml——java日志处理组件配置简介

    (从一篇好文开始)log4j(一)——为什么要用log4j? 三:看完栗子后的感想 (1)很明显我们在编写代码的时候有各种需要打印日志的需求,比如:我们调试代码的时候:我们的应用出现了问题,我们分析. ...

随机推荐

  1. Codeforces 505 A Mr. Kitayuta's Gift【暴力】

    题意:给出一个字符串,可以向该字符串的任意位置插入一个字母使其变成回文串 因为字符串的长度小于10,枚举插入的字母,和要插入的位置,再判断是否已经满足回文串 #include<iostream& ...

  2. BZOJ 1452 Count

    长知识啦..二维BIT. #include<iostream> #include<cstdio> #include<cstring> #include<alg ...

  3. [反汇编练习] 160个CrackMe之026

    [反汇编练习] 160个CrackMe之026. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  4. (六)6.11 Neurons Networks implements of self-taught learning

    在machine learning领域,更多的数据往往强于更优秀的算法,然而现实中的情况是一般人无法获取大量的已标注数据,这时候可以通过无监督方法获取大量的未标注数据,自学习( self-taught ...

  5. 【英语】Bingo口语笔记(67) - turn系列

  6. Android 实现切换主题皮肤功能(类似于众多app中的 夜间模式,主题包等)

    首先来个最简单的一键切换主题功能,就做个白天和晚上的主题好了. 先看我们的styles文件: <resources> <!-- Base application theme. --& ...

  7. 锋利的jQuery读书笔记---jQuery中Ajax--get、post等方法

    load()方法通常用来从Web服务器上获取静态的数据文件,然而这并不能体现ajax的全部价值. 在项目中,如果需要传递一些参数给服务器中的页面,那么可以使用$.get()或者$.post()方法(或 ...

  8. Web开发基础

    一.后台 1.MyEclipse:Java Web的编辑器 2.Java Servlet:后台代码 3.Velocity:前后台接口 4.mySql:数据库 二.前台 1.js:前台代码 2.jQue ...

  9. Sde表结构分析

    原文 Sde表结构分析 今天开始想分析一下sde的表结构,希望能够弄明白sde一个要素类的每个Feature是如何存储的. 弄ArcSDE的人都知道,ArcSDE内一个要素类在关系数据库(以MS SQ ...

  10. ADO.NET+Access: 2,至少一个参数没有被指定值

    ylbtech-Error-ADO.NET+Access: 2,至少一个参数没有被指定值. 1.A,错误代码返回顶部  2,至少一个参数没有被指定值. 1.B,出错原因分析返回顶部  未解决 1.C, ...