tomcat日志及logback相关日志框架

时间:2024-03-04 10:09:21

一、重点问题整理

1.1 关于logback.xml中的路径设置问题

准备金系统的logback.xml中设置的路径是:

<!-- 定义日志文件 输出位置 -->

<property name="log_dir" value="E:\logs" />

在Windows环境下,会识别E:为系统的E盘,默认在E盘下创建logs文件夹。但是正在Linux环境下,不存在E盘,会将E:\logs识别为E:logs文件夹。此时为相对路径,而tomcat在创建文件时:会从程序启动的地方去创建这个文件(Java项目中也是如此),那么web应用是从有tomcat来执行的,tomcat这个程序是从哪里启动文件是startup.bat?位置是tomcat/bin。会在bin目录下创建E:logs文件夹,而不是在tomcat的默认根路径故tomcat文件夹下创建E:logs文件夹。(验证:若是用sh bin/startup.sh命令,在tomcat目录下启动tomcat,则会在tomcat路径下创建E:logs文件夹。)

所以为了使日志文件在我们指定的目录下,有两只方式:

【1】我们可以使用绝对路径:      /

【2】也可以使用相对路径:

./ 当前目录。

../ 父级目录。

/ 根目录。

但是并不及建议用E:这种写死的路径。可以用以下方式创建日志文件的路径:

方式一:

value="${catalina.home}/logs":
本地:会在tomcat目录下创建logs文件。
Linux:Linux上会在tomcat目录下创建logs文件。

方式二:

value="${catalina.base}/logs":
本地:会在C:\Users\Administrator\.IntelliJIdea2017.2\system\tomcat\Unnamed_reserve_10目录下创建logs文件。(因为
本地tomcat为每个idea项目在这里创建了一个副本,项目是在这里启动的)
Linux:会在tomcat目录下创建logs文件。

方式三:

value="logs":会在tomcat/bin目录下创建logs文件。

../webapps/工程名:会在工程名目录下创建logs文件。

注意:我上次本地启动项目是在E盘创建的logs文件夹,这次可能是改啥东西了?我也不知道,反正本地的logs文件夹又跑tomcat/bin目录下了。奇怪。

 

 

 这个是用tomcat启动的web项目。我在这个项目里建了个main主方法,创建的logs文件又跑项目的根路径下了:

邪了门了,本地启动项目,好像配置的路径不起作用了。。。

1.2 查看日志是输出的格式,及在不同级别文件中都是怎么记录日志信息的?是否与控制台的输出内容一致?

答:一致。

本地文件:

 

 

 控制台:

1.3 为什么要用日志框架来进行日志管理?

日志框架对日志的管理能力非常强大,可以根据自定义的日志等级输出日志到指定位置,还可以对日志文件进行切分。Java自带的功能满足不了需要。

1.4 tomcat - catalina.out 日志过大处理方法

解决方案:

1.4.1 修改tomcat的日志配置,配置输出日志级别

修改conf/logging.properties日志配置文件来屏蔽掉这部分的日志信息。

将level级别设置成WARNING就可以大量减少日志的输出,当然也可以设置成OFF,直接禁用掉。

1.4.2 修改工程的日志配置:输出在控制台的级别

删除log4j中的输出控制台的日志配置,catalina.out中不再记录应用的日志。  日志输出级别:ALL、DEBUG、INFO、WARN、ERROR  这下它不会涨的那么快了。设置工程项目输出至控制台catalina.out日志的级别: WARN

1.4.3 对catalina.out 启动定时清空

  编写清空脚本脚本:(默认目录tomcat 根目录) 

1.4.4 tomcat不输出到catalina.out

由于最近项目需要部署到外网环境,之前在内网测试看日志都是在catalina.out,但是现在修改了一下,不需要看这个了,而且如果项目在外网环境部
署,这个文件一直会增大,浪费空间,所有墨迹了半天,才重网上找到一个比较好的方法,不输出到catalina.out. 找到tomcat下的   bin
/catalina.sh;  找到下面这一段, 把#CATALINA_OUT="$CATALINA_HOME"/logs/catalina.out 注释掉,改为CATALINA_OUT=/dev/null, if [ -z "$CATALINA_OUT" ] ; then #CATALINA_OUT="$CATALINA_HOME"/logs/catalina.out CATALINA_OUT=/dev/null fi 对于/dev/null,我在网上了解是,它相当于垃圾桶一样,输出什么到它哪里,它直接丢了.所有我们在/dev/null,看到null这个文件,大小是空的,所有并不会占用空间大小了.

1.4.4 禁止日志输出到catalina.out

1、修改tomcat/conf/logging.properties中的日志输出级别

把 catalina.org.apache.juli.AsyncFileHandler.level = FINE

更改为 catalina.org.apache.juli.AsyncFileHandler.level = OFF

OFF为禁止

 改后效果如图:

 

2、关闭localhost_access_log日志

注释tomcat/conf/server.xml中最下方AccessLogValue

 

3、修改tomcat/bin/catalina.sh中 185行左右

if [ -z "$CATALINA_OUT" ] ; then

  CATALINA_OUT="$CATALINA_BASE"/logs/catalina.out

fi

改为

 

null作为垃圾桶,因此大小为0

原文链接:https://blog.csdn.net/su1573/article/details/87883126

1.5 Windows下生成calalina.out 日志文件

之前我们在linux系统下查看日志的时候,总有个习惯,启动项目后会进入logs/下,敲击类似

tail -fn500 catalina.out
tail -f catalina.out

 

的命令,便可以进入到catalina.out中实时的显示出最新的500行信息,但是有个问题,在windows系统中我们却没发现这个catalina.out,难道是只有在linux系统下才有catalina.out文件吗?其实不是这样的,首先说下为什么在linux下是叫catalina.out,这是由于catalina_home/bin/catalina.sh文件指定的,参看下面部分源码:

shift

  touch "$CATALINA_BASE"/logs/catalina.out

  if [ "$1" = "-security" ] ; then

    echo "Using Security Manager"

    shift

    "$_RUNJAVA" $JAVA_OPTS "$LOGGING_CONFIG" $CATALINA_OPTS \

      -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \

      -Djava.security.manager \

      -Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \

      -Dcatalina.base="$CATALINA_BASE" \

      -Dcatalina.home="$CATALINA_HOME" \

      -Djava.io.tmpdir="$CATALINA_TMPDIR" \

      org.apache.catalina.startup.Bootstrap "$@" start \

      >> "$CATALINA_BASE"/logs/catalina.out 2>&1 &

      if [ ! -z "$CATALINA_PID" ]; then

        echo $! > $CATALINA_PID

      fi

注:touch命令可以创建一个不存在的文件。

  那么同理可以想象在windows下也可以存在catalina.out文件(只是默认建的文件不叫这个名而已),那么可不可以在windows系统下也看的见,或者说创建出catalina.out呢?答案是肯定的,参考如下:

由于tomcat本身是可以跨平台的,故既然有linux下的catalina.sh,就会对应有windows下的catalina.bat。

问题:windows下的tomcat的日志只输出在控制台下,且日志文件输出只有一些基本信息。如何把所有日志都输出到catalina.out?

解决方案

需要修改两个地方:

1、修改startup.bat

把call “%EXECUTABLE%” start %CMD_LINE_ARGS%修改为call “%EXECUTABLE%” run %CMD_LINE_ARGS%.   
2、修改catalina.bat
查找catalina.bat含有%ACTION%的4行内容(在文件末),在后面添加 
>> %CATALINA_HOME%\logs\catalina.out 
或者
>> %CATALINA_BASE%\logs\catalina.out
修改之后如下图(没有显示完全):

 重启tomcat后,发现在logs文件下会生成catalina.out的文件,内容为tomcat的日志。

3、不过有个弊端就是日志在命令行不输出了。

二、应用实例

2.1、maven依赖

<!-- logback begin-->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.7</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
      <version>1.1.3</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-access</artifactId>
      <version>1.1.3</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.1.3</version>
    </dependency>
    <!-- logback end-->

2.2、完整的logback.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- 级别从高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
<!-- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 -->
<!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志 -->
<!-- scan 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 -->
<!-- scanPeriod 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
 
    <!-- 动态日志级别 -->
    <jmxConfigurator />
     
    <!-- 定义日志文件 输出位置 -->
    <property name="log_dir" value="E:\logs" />
     
    <!-- 日志最大的历史 30天 -->
    <property name="maxHistory" value="30" /> 
        
    <!-- ConsoleAppender 控制台输出日志 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>
                <!-- 设置日志输出格式 -->
                %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n
            </pattern>
        </encoder>
    </appender>
 
    <!-- ERROR级别日志 -->
    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender -->
    <appender name="ERROR"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录WARN级别的日志 -->
        <!-- 果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">         
            <!-- 设置过滤级别 -->
            <level>ERROR</level>
            <!-- 用于配置符合过滤条件的操作 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 用于配置不符合过滤条件的操作 -->
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志输出位置 可相对、和绝对路径 -->
            <fileNamePattern>
            ${log_dir}/error/%d{yyyy-MM-dd}/error-log.log
            </fileNamePattern>
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6, 则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除 -->
            <maxHistory>${maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>
                <!-- 设置日志输出格式 -->
                %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n
            </pattern>
        </encoder>
    </appender>
 
     
    <!-- WARN级别日志 appender -->
    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录WARN级别的日志 -->
        <!-- 果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 设置过滤级别 -->
            <level>WARN</level>
            <!-- 用于配置符合过滤条件的操作 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 用于配置不符合过滤条件的操作 -->
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志输出位置 可相对、和绝对路径 -->
            <fileNamePattern>${log_dir}/warn/%d{yyyy-MM-dd}/warn-log.log</fileNamePattern>
            <maxHistory>${maxHistory}</maxHistory> 
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>
     
     
     <!-- INFO级别日志 appender -->
    <appender name="INFO" 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>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_dir}/info/%d{yyyy-MM-dd}/info-log.log</fileNamePattern> 
            <maxHistory>${maxHistory}</maxHistory> 
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>
     
     
    <!-- DEBUG级别日志 appender -->
    <appender name="DEBUG" 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>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_dir}/debug/%d{yyyy-MM-dd}/debug-log.log</fileNamePattern> 
            <maxHistory>${maxHistory}</maxHistory> 
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>
     
     
    <!-- TRACE级别日志 appender -->
    <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>TRACE</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_dir}/trace/%d{yyyy-MM-dd}/trace-log.log</fileNamePattern> 
            <maxHistory>${maxHistory}</maxHistory> 
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>
     
     
    <!-- root级别   DEBUG -->
    <root>
        <!-- 打印info级别日志及以上级别日志 -->
        <level value="INFO" />
        <!-- 控制台输出 -->
        <appender-ref ref="console" />
        <!-- 文件输出 -->
        <appender-ref ref="ERROR" />
        <appender-ref ref="INFO" />
        <appender-ref ref="WARN" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="TRACE" />
    </root>
</configuration>

我这里定义的路径为:

 <!-- 定义日志文件 输出位置 -->
    <property name="log_dir" value="E:\logs" />

2.3 自定义异常

package com.asd.common.utils;

public class BusinessException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    public BusinessException(){
    }

    public BusinessException(String message){
        super(message);
    }
}

2.4、应用

2.4.1 main方法

public static final Logger log = LoggerFactory.getLogger(DWSHttpServletServiceImpl.class);
    public static void main(String[] args) {
        int a = 0;
        log.info("验证logback记录日志");
        try{
            //
            a = testException();
        } catch (BusinessException be) {
            String exceptionMessge = be.getMessage();
            //在日志里记录自定义异常信息
            log.error(exceptionMessge);
        } catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(a);
    }

    public static int testException(){

        int a = 0;
        try {
            a = 1/0;
        }
        catch (Exception e){
            throw new BusinessException("除数不能为0");//抛出自定义异常
        }
        return a;
    }

控制台输出:

 删除配置文件后:

 说明配置文件是起作用的。

 我这里是直接在一个web项目里(准备金系统)创建的一个main方法进行测试的,可见logback并不需要使用容器。

在web项目中的使用方式也一样。

三、logback等日志框架

3.1 概念

Log Java日志:(slf4j、log4j、logback、common-logging )

  • slf4j 是规范/接口
  • 日志实现:log4j、logback、common-logging

简单地说,Logback 是一个 Java 领域的日志框架。它被认为是 Log4J 的继承人。

Logback 主要由三个模块组成:

  • logback-core
  • logback-classic
  • logback-access

logback-core 是其它模块的基础设施,其它模块基于它构建,显然,logback-core 提供了一些关键的通用机制。
logback-classic 的地位和作用等同于 Log4J,它也被认为是 Log4J 的一个改进版,并且它实现了简单日志门面 SLF4J。
logback-access 主要作为一个与 Servlet 容器交互的模块,比如说 tomcat 或者 jetty,提供一些与 HTTP 访问相关的功能。


根据不同的日志系统,你可以按如下规则组织配置文件名,就能被正确加载:

  • Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
  • Log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
  • Log4j2:log4j2-spring.xml, log4j2.xml
  • JDK (Java Util Logging):logging.properties

Logback 与 Log4J

实际上,这两个日志框架都出自同一个开发者之手,Logback 相对于 Log4J 有更多的优点:

  • 同样的代码路径,Logback 执行更快
  • 更充分的测试
  • 原生实现了 SLF4J API(Log4J 还需要有一个中间转换层)
  • 内容更丰富的文档
  • 支持 XML 或者 Groovy 方式配置
  • 配置文件自动热加载
  • 从 IO 错误中优雅恢复
  • 自动删除日志归档
  • 自动压缩日志成为归档文件
  • 支持 Prudent 模式,使多个 JVM 进程能记录同一个日志文件
  • 支持配置文件中加入条件判断来适应不同的环境
  • 更强大的过滤器
  • 支持 SiftingAppender(可筛选 Appender)
  • 异常栈信息带有包信息

logback是java的日志开源组件,是log4j创始人写的,性能比log4j要好,目前主要分为3个模块。

  1. logback-core:核心代码模块
  2. logback-classic:log4j的一个改良版本,同时实现了slf4j的接口,这样你如果之后要切换其他日志组件也是一件很容易的事
  3. logback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能。

3.2 实现原理:slf4j是什么

slf4j只是一套标准,通俗来讲,就是定义了一系列接口,它并不提供任何的具体实现。所以,我们使用这套接口进行开发,可以任意的切换底层的实现框架。比如,一开始项目用的是log4j的实现,后来发现log4j的性能太差了,想换成logback,由于我们代码中都是面向slf4j接口的,这样我们只要吧log4j的依赖换成logback就可以了。

3.3 总结

日志组件的使用一般都非常简单,几乎所有的项目中都会用到各种各样的日志组件。但是可能就是由于太简单了,比较少的人会愿意深入系统的去了解。本人也只是对logback的配置以及一些简单的原理做了一些了解,并没有很深入的去看logback的具体实现。

因此,本文的内容大部分都是基于官网的文档以及网上一些其他关于logback的博客,虽然也做了一些简单的测试,但并不保证全部都是正确的。

参看链接:

logback介绍和配置详解:https://www.jianshu.com/p/04065d8cb2a9

Logback配置使用:https://www.jianshu.com/p/638b4e2c4068

tomcat 日志详解:https://www.cnblogs.com/operationhome/p/9680040.html

Java日志框架:slf4j作用及其实现原理:https://www.cnblogs.com/xrq730/p/8619156.html