zoukankan      html  css  js  c++  java
  • 一次Logback日志无法在Linux上输出的解决过程

    之前,在Linux上查看日志,一直是用:tail -f catalina.out 的方式,只能实时看,没有记录文件,很不方便

    于是决定把"老项目"(是spring MVC的项目,spring boot的绕道)的日志全部 切换成logback的(至于为什么要选logback,有疑问的请自行百度),并以日志文件存留

    先说一下,老项目之前启动一直是有一个警告的:(A)SLF4J: Class path contains multiple SLF4J bindings. 就是有冲突日志文件,但是由于不影响项目启动,所以没有多管。。。

    但是现在就是要管一管TA,由于老项目pom文件有点大,也有好多冗余,就不再说一些细节,提供一些解决问题的思考方向:

    最开始的警告是这样的:

    ERROR StatusLogger No Log4j context configuration provided. This is very unusual.
    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/opt/min_meerkat_test/meerkat/apache-tomcat-7.0.79/webapps/meerkat-web/WEB-INF/lib/log4j-slf4j-impl-2.4.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/opt/min_meerkat_test/meerkat/apache-tomcat-7.0.79/webapps/meerkat-web/WEB-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/opt/min_meerkat_test/meerkat/apache-tomcat-7.0.79/webapps/meerkat-web/WEB-INF/lib/slf4j-log4j12-1.6.6.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
    ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

    第一步:直接在pom.xm用 <exclusion> 标签找到 有引入其他日志 依赖的,给“剔除”掉

    这里多说一下,有些一层依赖的,像下面zookeeper依赖这样的,剔除比较简单

    剔除如下:

         <dependency>
                <groupId>org.apache.zookeeper</groupId>
                <artifactId>zookeeper</artifactId>
                <version>3.4.12</version>
                <!--排除这个slf4j-log4j12-->
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-log4j12</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>log4j</groupId>
                        <artifactId>log4j</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

    但是有的是嵌套多层的,就比较麻烦了,比如下面这种:

    剔除就麻烦一点,如下:

    <dependency>
                <groupId>org.apache.hive</groupId>
                <artifactId>hive-common</artifactId>
                <version>${hive.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.apache.logging.log4j</groupId>
                        <artifactId>log4j-1.2-api</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.apache.logging.log4j</groupId>
                        <artifactId>log4j-slf4j-impl</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.apache.logging.log4j</groupId>
                        <artifactId>log4j-web</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.apache.hive</groupId>
                <artifactId>hive-jdbc</artifactId>
                <version>${hive.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.apache.hive</groupId>
                        <artifactId>hive-common</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

    PS:就是先把整个 hive-common 给剔除掉,但是这样对一些功能是有影响的,所以再单独引入 hive-common依赖,再在里面把不想要的 日志包 剔除掉

    其他的类似处理思路,如果依赖比较少,IDEA有一种很快发现重复依赖的方式:左侧maven最上方的一排图标里面,有一个Show Dependencies,点开看,十分方便!

    第二步:通过第一步的“剔除”,正常是应该把其他非logback的都干掉了的,但是有一些,或者项目乱七八糟的的依赖多了,你是发现不了的,那么还有一种方式,强行把其他日志的输出“适配”到SLF4j上,目前发现有这几种:

            <!-- log4j 输出到 slf4j -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>log4j-over-slf4j</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <!-- common-logging 输出到 slf4j -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>jcl-over-slf4j</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <!-- java.util.logging 输出到 slf4j -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>jul-to-slf4j</artifactId>
                <version>${slf4j.version}</version>
            </dependency>    

    就是把其他日志的输出强行用统一的SLF4j来打印,但是这样做会引发另一个警告:

    SLF4J: Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path, preempting StackOverflowError. 

    翻译一下就是:在类路径上检测到log4j-over-slf4j.jar和slf4j-log4j12.jar,防止堆栈溢出错误

    这里补充一点,笔者用第一步的方式剔除能找到的其他日志后,启动时发现还是警告:

    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/D:/mavenStore/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/D:/mavenStore/repository/org/slf4j/slf4j-log4j12/1.6.6/slf4j-log4j12-1.6.6.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    
    
    //SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

    所以额外又引入了 log4j-over-slf4j 这个依赖,引入后,原来项目用 log4j 引入写日志的地方都会报错,需要一一修改过来!(笔者就是当发现项目开始报错时,就发现转机来了,后面处理的思路就清晰了。。。)

    经过上面两步处理后,日志是实现了统一用SLF4J打印的,但是 SLF4J: Class path contains multiple SLF4J bindings. 这个警告还是在的(但是已经没什么影响了)

    最后说一下spring MVC这种项目,用 SLF4J + Logback 这种方式打印日志的 pom 需要的依赖:

         <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.7.5</version>
            </dependency>
            <!-- 这个和上面的两个是关键 -->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>1.2.3</version>
            </dependency>
            <!-- 这个有的说 上面的classic的已经包含了,可以不引入 -->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.3</version>
            </dependency>

    最后,在 src/resource 下还需要一个 logback.xml配置文件:(一个简单的示例)

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration scanPeriod="2 seconds" debug="true">
        <!--定义日志文件的存储地址 勿在,勿在,勿在 LogBack 的配置中使用相对路径 -->
        <!--<property name="LOG_HOME" value="D:/logs/meerkat-web/" />-->
        <!--<property name="LOG_HOME" value="/logs/meerkat-web/" />-->
        <property name="LOG_HOME" value="logs/meerkat-web/" />
        <!-- 控制台输出 -->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <!-- 日志输出编码 -->
            <Encoding>UTF-8</Encoding>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
                </pattern>
            </layout>
        </appender>
        <!-- 按照每天生成日志文件 -->
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <Encoding>UTF-8</Encoding>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--日志文件输出的文件名-->
                <!--<FileNamePattern>${LOG_HOME}/myApp.log.%d{yyyy-MM-dd}.log</FileNamePattern>-->
                <!--<FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}.%i.log</FileNamePattern>-->
                <!-- windows上不能加 %i,且 相对或绝对路径 都可以正常打印 -->
                <FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}.log</FileNamePattern>
                <MaxHistory>30</MaxHistory>
            </rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
                </pattern>
            </layout>
            <!--日志文件最大的大小-->
            <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
                <MaxFileSize>10MB</MaxFileSize>
            </triggeringPolicy>
        </appender>
    
        <!-- show parameters for ibatis sql 专为 ibatis 定制 -->
        <!--<logger name="com.ibatis" level="DEBUG" />
        <logger name="com.ibatis.common.jdbc.SimpleDataSource" level="DEBUG" />
        <logger name="com.ibatis.common.jdbc.ScriptRunner" level="DEBUG" />
        <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="DEBUG" />
        <logger name="java.sql.Connection" level="DEBUG" />
        <logger name="java.sql.Statement" level="DEBUG" />
        <logger name="java.sql.PreparedStatement" level="DEBUG" />-->
    
        <!-- 日志输出级别 -->
        <root level="INFO">
            <appender-ref ref="STDOUT" />
            <appender-ref ref="FILE" />
        </root>
    
        <!--日志异步到数据库 -->
        <!--   <appender name="DB" class="ch.qos.logback.classic.db.DBAppender"> -->
        <!--日志异步到数据库 -->
        <!-- <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"> -->
        <!--连接池 -->
        <!--<dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
         <driverClass>com.mysql.jdbc.Driver</driverClass>
         <url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
         <user>root</user>
         <password>root</password>
        </dataSource>
      </connectionSource>
    </appender> -->
    </configuration>

     当然,logback的配置很强大、也很丰富,自行百度!!!

    参考:

    Java的Log系统介绍和切换(转):https://yq.aliyun.com/articles/270133?spm=a2c4e.11153940.0.0.54b2414avRADHt

    log4j-over-slf4j工作原理详解参考:https://blog.csdn.net/john1337/article/details/76152906

    通过IDEA快速定位和解决依赖冲突:https://www.cnblogs.com/jajian/p/11002521.html

    logback日志不打印到文件问题深入剖析:https://blog.csdn.net/maoyuanming0806/article/details/82085239(内含logback.xml的一份按日划分日志的的配置参考)

  • 相关阅读:
    Sqlserver根据条件去除重复数据并且留下的是最大值数据
    C# Linq及Lamda表达式实战应用之 GroupBy 分组统计
    MVVM模式WPF的ComboBox数据绑定,使用Dictionary作为数据源
    C# System.Timers.Timer定时器的使用和定时自动清理内存应用
    SQL优化策略
    只要不放弃,总有出头之路
    2 Python基础
    4 动态库和静态库
    1 VS常用快捷键
    2 C语言环境、编译
  • 原文地址:https://www.cnblogs.com/zz-3m23d-begining/p/11421251.html
Copyright © 2011-2022 走看看