嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2015-12-14 2222 次浏览 标签 : Java

免费领取阿里云优惠券 我的直播 - 《PHP 进阶之路》

遇到的问题

总有一些我们自己测试没有发现的问题,在用户那里出现,而我对 java 的错误日志没有做一个很好的管理。现在的情况是所有的请求日志和错误日志都输出在了一个文件,没有规划整理。

我的需求

请求日志在一个文件

每个方法的debug 日志在一个独立的文件

每个方法的错误日志有自己的一个独立的文件

解决方案

slf4j+logback

简单认识 slf4j

SLF4J,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统。按照官方的说法,SLF4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所希望的日志系统。

实际上,SLF4J所提供的核心API是一些接口以及一个LoggerFactory的工厂类。从某种程度上,SLF4J有点类似JDBC,不过比JDBC更简单,在JDBC中,你需要指定驱动程序,而在使用SLF4J的时候,不需要在代码中或配置文件中指定你打算使用那个具体的日志系统。如同使用JDBC基本不用考虑具体数据库一样,SLF4J提供了统一的记录日志的接口,只要按照其提供的方法记录即可,最终日志的格式、记录级别、输出方式等通过具体日志系统的配置来实现,因此可以在应用中灵活切换日志系统。

简单认识 logback

Logback就是SLF4J服务的日志系统,Logback里的logback-classic实现了SLF4J API

我使用的 maven 包管理导入如下两个包

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.13</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.1.3</version>
</dependency>

在我们想用logback记录日志的时候,只需要做类似如下操作即可。

import ch.qos.logback.classic.Logger;
import org.slf4j.LoggerFactory;
//...
protected final static Logger logger = (Logger) LoggerFactory.getLogger(AccountCache.class);

但是我实际测试发现这样写:

package net.mengkang;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by zhoumengkang on 14/12/15.
 */
public class Api {
    protected final static Logger logger = LoggerFactory.getLogger(Bar.class);

    public static void main(String[] args) {
        logger.info("111");
        logger.debug("222");
        logger.error("3333");
        logger.trace("4444");
    }
}

这里并没有把slf4j工厂生成的Logger转成LogbackLogger对象,也能使得logback.xml的配置生效。测试发现logback.xml文件名修改则无法生效。

那么程序执行的时候,是怎么识别logback.xml的呢?debug 也没找到。。我猜想和项目.idea/workspace.xml里的ProjectLibrariesConfigurable.UI有关系

我做了如下配置

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 分日期生成日志仅记录最近30天的日志 -->
    <!-- 仅仅用来记录访问日志不记录错误日志 -->
    <appender name="ApiInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <Encoding>UTF-8</Encoding>
        <File>/Users/zhoumengkang/Documents/logs/api.info.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>/Users/zhoumengkang/Documents/logs/api.info.%d{yyyy-MM-dd}.log</FileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%date [%thread] %-5level %logger{50} %L - %msg%n</pattern>
        </layout>
    </appender>

    <appender name="ApiError" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <Encoding>UTF-8</Encoding>
        <File>/Users/zhoumengkang/Documents/logs/api.error.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>/Users/zhoumengkang/Documents/logs/api.error.%d{yyyy-MM-dd}.log</FileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%date [%thread] %-5level %logger{50} %L - %msg%n</pattern>
        </layout>
    </appender>

    <appender name="ApiDebug" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <Encoding>UTF-8</Encoding>
        <File>/Users/zhoumengkang/Documents/logs/api.debug.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>/Users/zhoumengkang/Documents/logs/api.debug.%d{yyyy-MM-dd}.log</FileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%date [%thread] %-5level %logger{50} %L - %msg%n</pattern>
        </layout>
    </appender>

    <logger name="net.mengkang.Api" level="debug" additivity="false">
        <appender-ref ref="ApiInfo"/>
        <appender-ref ref="ApiError"/>
        <appender-ref ref="ApiDebug"/>
    </logger>

    <root level="debug">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

这样Api这个类的调试日志,访问日志和错误日志就能分开存储了。

能不能具体到某个类下面的方法呢?

具体的更多配置可以参考 http://blog.csdn.net/haidage/article/details/6794509 非常详细。

嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表

回复 康哥本人 2016-01-02 14:29:44
程序是怎么识别logback.xml的呢?
我猜想和项目.idea/workspace.xml里的ProjectLibrariesConfigurable.UI有关系