JFinal 使用slfj4+log4j2打印日志

之所以想要写这一篇分享是因为前一段时间看了另一个分享,使用日志打印出完整的sql语句,而不是像JFinal内置的devMode中带"?"的sql语句.链接如下:

http://www.jfinal.com/share/324

但是遇到了一个问题,该分享中使用的日志框架是logback,但是我的项目中使用的是JFinal自带的日志框架(即配置了log4j.properties),会打印出来很多无用的日志,当时并不知道怎么配置"日志过滤",就放弃了该分享中的功能,现在终于解决了这个问题,现分享如下:

分享从几个问题开始

  1. JFinal中使用的是什么日志框架?如何更改?

  2. 应该选用什么框架实现日志过滤的功能?

  3. 如何配置日志框架才能实现日志过滤的功能?



回答:

  1. JFinal使用的是什么日志框架?默认实现是什么?如何更改?

    JFinal使用的是封装了一层的日志框架,可以兼容其余所有日志框架,为何这么说,看源码,JFinal源码中有一个接口ILogFactory,一个抽象类Log,JFinal源代码中使用的日志工具就是Log的子类.为什么说JFinal可以兼容其余所有日志框架呢?看下JFinal提供的Log实现类,有两个,一个JdkLog,一个Log4jLog,从名字就可以看出,一个是封装Jdk默认log,一个是封装log4j的log,部分代码如下:


public class Log4jLog extends Log {
   
   private org.apache.log4j.Logger log;
   private static final String callerFQCN = Log4jLog.class.getName();
   
   Log4jLog(Class<?> clazz) {
      log = org.apache.log4j.Logger.getLogger(clazz);
   }
   
   Log4jLog(String name) {
      log = org.apache.log4j.Logger.getLogger(name);
   }
   
   public static Log4jLog getLog(Class<?> clazz) {
      return new Log4jLog(clazz);
   }
   
   public static Log4jLog getLog(String name) {
      return new Log4jLog(name);
   }
   
   public void info(String message) {
      log.log(callerFQCN, Level.INFO, message, null);
   }
   ...
 }

就是封装了一个org.apache.log4j.Logger,所有的操作调用log4j的log完成

JFinal的默认实现又是什么呢?

初始化的代码在抽象类Log中

public abstract class Log {
   
   private static ILogFactory defaultLogFactory = null;
   
   static {
      init();
   }
   
   static void init() {
      if (defaultLogFactory == null) {
         try {
            Class.forName("org.apache.log4j.Logger");
            Class<?> log4jLogFactoryClass = Class.forName("com.jfinal.log.Log4jLogFactory");
            defaultLogFactory = (ILogFactory)log4jLogFactoryClass.newInstance();   // return new Log4jLogFactory();
         } catch (Exception e) {
            defaultLogFactory = new JdkLogFactory();
         }
      }
   }
   ...
 }

如果可以加载log4j的jar包,就使用log4j,否则使用JdkLog

如何更改日志框架呢?

在configConstant中配置即可

@Override
public void configConstant(Constants me) {
   ...
   me.setLogFactory(new Slf4jLogFactory());
   ...
}

其中Slf4jLogFactory类直接使用了cn.dreampie的代码,表示感谢,maven如下

<dependency>
    <groupId>cn.dreampie</groupId>
    <artifactId>jfinal-slf4j</artifactId>
    <version>0.1</version>
</dependency>


2.应该选用什么框架实现日志过滤的功能?

在此之前需要了解以下日志框架体系,链接如下:

http://blog.csdn.net/kxcfzyk/article/details/38613861

从上面已经看到,日志门面使用的是slf4j,便于修改,但是底层的日志使用什么实现呢?log4j最新的一版是2012的,太老了直接淘汰,查了下比较常用的是log4j2和logback,从网上查到的资料个人感觉log4j2好用点,就决定使用log4j2,需要一共四个依赖

<!--slf4j及log4j日志-->
<!--门面-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>${slf4j.version}</version>
</dependency>
<!--桥接器:告诉slf4j使用Log4j2-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>${log4j2.version}</version>
    <exclusions>
        <exclusion>
            <artifactId>slf4j-api</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
    </exclusions>
</dependency>
<!--具体实现,log4j2-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>${log4j2.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>${log4j2.version}</version>
</dependency>
<log4j2.version>2.9.1</log4j2.version>
<!--不能升级为1.8.*,log4j2的2.9.1版本依赖1.7.25,使用1.8提示No SLF4J providers were found-->
<slf4j.version>1.7.25</slf4j.version>

注意:slf4j不可使用1.8.*.否则不兼容


3.如何配置日志框架才能实现日志过滤的功能?

由于日志选择使用slf4j+log4j2,其实配置就是配置log4j2,网上关于如何配置log4j2的文章很多,都可以查到.

我配置的时候遇到一个坑,log4j2有两种模式,一种strict,一种非strict,strict模式是严格按照xsd标准的配置文件,当时觉得strict模式符合xsd标准,idea也不会报error,就尽力想使用strict模式配置,后来发现一些功能配置实现不了,而且网上的文章多数都是使用非strict模式配置,最后就放弃了,决定使用非strict模式配置,于是idea一打开log4j2.xml文件,就全是error,真是丑

总结:

1.JFinal抽象了日志实现,可以兼容任何日志框架

2.使用slf4j+log4j2实现日志框架,当时要注意jar包版本,注意兼容问题

3.使用非strict模式配置log4j2,虽然丑,但是能用

当时下定决心修改日志框架是因为要让日志打印sql语句,最后该功能当然是实现了,不过使用的并不是文章开头链接中提到的方法,而是----->druid,下一篇分享写下如何配置druid


评论区

pfjia

2017-11-22 18:30

反馈:分享不能发表情

弯道加速跑

2017-11-23 11:09

你对日志框架的研究比我深刻多了~~我当初仅仅是为了解决完整sql语句输出的需要,看了你的文章,受教了

dadu

2017-11-23 22:57

就喜欢看这么条理清晰的分享啊,太科普了。赞!

lishixing

2017-12-08 09:29

请问jfinal吧日志改成log4j2需要怎么配置,最近尝试修改,一直未成功

pfjia

2017-12-14 18:47

@lishixing 你好,我好久没有看官网了,其实网上很多log4j2的配置,以下是我的配置




${sys:catalina.base}/webapps/logs/root









fileName="${LOG_ROOT}/debug.log"
filePattern="${LOG_ROOT}/$${date:yyyy-MM}-debug/debug-%d{yyyy-MM-dd}-%i.log.gz">

pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>







fileName="${LOG_ROOT}/info.log"
filePattern="${LOG_ROOT}/$${date:yyyy-MM}-info/info-%d{yyyy-MM-dd}-%i.log">

pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>







fileName="${LOG_ROOT}/warn.log"
filePattern="${LOG_ROOT}/$${date:yyyy-MM}-warn/warn-%d{yyyy-MM-dd}-%i.log">

pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>







fileName="${LOG_ROOT}/error.log"
filePattern="${LOG_ROOT}/$${date:yyyy-MM}-error/error-%d{yyyy-MM-dd}-%i.log">

pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>







fileName="${LOG_ROOT}/sql.log"
filePattern="${LOG_ROOT}/$${date:yyyy-MM}-sql/sql-%d{yyyy-MM-dd}-%i.log">

pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>




























饺子包

2018-01-15 09:32

@pfjia 为什么我的me.setLogFactory(new Slf4jLogFactory());这一句会提示无法访问ILogFactory类?

pfjia

2018-01-18 15:27

@饺子包 你的jfinal是哪一个版本?此文章所有操作均在jfinal 3.3版本下

yaqi

2018-06-25 10:14

@lishixing 具体可以看这边博客:https://mp.csdn.net/postedit/80783882

JFinal

2019-12-10 21:09

jfinal 4.8 已改进了日志模块:
1: 添加了 trace 日志级别
2: 添加了可变参数系列方法,例如: log.error("参数错误 {} ", para);
3: 添加了 slf4j 实现,配置方法:
me.setToSlf4jLogFactory();

由于 slf4j 是一个日志门面系统,所以使用 slf4j 可以用上很多其它的具体日志实现

建议升级到 jfinal 4.8,很多打磨与改进,谁用谁爽 ^_^

热门分享

扫码入社