以前,在Linux上查看日誌,一直是用:tail -f catalina.out 的方式,只能實時看,沒有記錄文件,很不方便html
因而決定把"老項目"(是spring MVC的項目,spring boot的繞道)的日誌所有 切換成logback的(至於爲何要選logback,有疑問的請自行百度),並以日誌文件存留java
先說一下,老項目以前啓動一直是有一個警告的:(A)SLF4J: Class path contains multiple SLF4J bindings. 就是有衝突日誌文件,可是因爲不影響項目啓動,因此沒有多管。。。mysql
可是如今就是要管一管TA,因爲老項目pom文件有點大,也有好多冗餘,就再也不說一些細節,提供一些解決問題的思考方向:web
最開始的警告是這樣的:spring
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> 標籤找到 有引入其餘日誌 依賴的,給「剔除」掉sql
這裏多說一下,有些一層依賴的,像下面zookeeper依賴這樣的,剔除比較簡單數據庫
剔除以下:apache
<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>
可是有的是嵌套多層的,就比較麻煩了,好比下面這種:windows
剔除就麻煩一點,以下:api
<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快速定位和解決依賴衝突:http://www.javashuo.com/article/p-auyakpty-eg.html
logback日誌不打印到文件問題深刻剖析:https://blog.csdn.net/maoyuanming0806/article/details/82085239(內含logback.xml的一份按日劃分日誌的的配置參考)