Java – 配置log4j的日誌文件路徑 (附-獲取當前類路徑的多種方法)
- 2019 年 10 月 3 日
- 筆記
目錄
1 日誌路徑帶來的痛點
Java 項目中少不了要和log4j等日誌框架打交道, 開發環境和生產環境下日誌文件的輸出路徑總是不一致, 設置為絕對路徑的方式缺少了靈活性, 每次變更項目路徑都要修改文件, 目前想到的最佳實現方式是: 根據項目位置自動載入並配置文件路徑.
本文借鑒 Tomcat 的配置方式 「${catalina.home}/logs/catalina.out」, 通過相對路徑的方式設置日誌的輸出路徑, 有其他解決方案的小夥伴, 請直接評論區交流哦?
2 log4j.properties文件的配置
# 設置要輸出的日誌的級別 - 注意: properties文件中的注釋資訊只能處於行首, 不要跟在行尾 log4j.rootLogger=INFO,stdout,logfile ### 輸出到控制台, Java程式運行時的標準輸出資訊 log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # 2019-05-25 19:09:46 log4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%t] [%c] [%p] - %m%n ### 輸出到日誌文件 # 按天滾動生成, 不支援MaxFileSize, 而RollingFileAppender支援 log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender # 項目的logs目錄下 # log4j.appender.logfile.File=${base.dir}/logs/elastic-server.log log4j.appender.logfile.Append=true # 輸出INFO及以上的日誌, 按日期滾動就無須配置單個日誌文件的最大體積了 log4j.appender.logfile.Threshold=INFO # log4j.appender.logfile.MaxFileSize=100MB log4j.appender.logfile.layout=org.apache.log4j.PatternLayout log4j.appender.logfile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%t] [%c] [%p] - %m%n
3 徹底解決痛點
3.1 單獨的Java程式包 (非Java Web項目)
單獨的Java程式包, 需要通過命令java -jar
或java -cp
的方式啟動;
我們可以在啟動命令中加入系統運行時變數, 在log4j載入配置文件之前通過System.getProperties("path")
讀取此變數, 即可實現靈活載入當前路徑.
(1) 啟動腳本設置:
假設當前項目的目錄結構為:
/Projects/KafkaConsumer 丨 bin 項目的啟動腳本 丨 conf 項目的配置文件 丨 lib 項目的其他依賴包 丨 bogs 項目的日誌輸出路徑
啟動腳本位於bin目錄下, 內容示例如下:
# 獲取當前腳本所處的目錄, 然後進入其上級目錄, 最後pwd輸出該目錄, 最終的結果是/Project/KafkaConsumer base_dir=$(cd `dirname $0`; cd ..; pwd) # 獲取Java運行程式的位置, 並指定主類 java_bin=$(which java) main_class="org.shoufeng.elastic.ConsumerMain" # 通過-cp、擴展CLASSPATH、指定主類的方式啟動項目, # 並通過「-D」的方式向此程式的運行時環境中設置當前項目的路徑, # 即可在程式中通過System.getProperty("base.dir")獲取此路徑 nohup ${java_bin} -Dbase.dir=${base_dir} -cp ${CLASSPATH}:${base_dir}/conf:${base_dir}/lib/* ${main_class} >> /dev/null &
(2) Java程式讀取變數:
實log4j的FileAppender本身支援動態設置文件路徑, 如:
log4j.appender.logfile.File=${base.log}/logs/app.log
其中「${base.log}」是一個變數, 會被System Property
中的base.log
的值代替, 程式碼中的使用方式為:
public static void main(String[] args) { // 獲取系統運行時變數中的日誌文件的輸出路徑 // 此變數需要在啟動命令中通過-D的方式設置 String baseDir = System.getProperty("base.dir"); if (baseDir == null) { // 開發環境中使用 baseDir = System.getProperty("user.dir"); System.setProperty("base.dir", baseDir); } log.info("==== 系統運行路徑: " + System.getProperty("base.dir") + " ===="); // 其他處理邏輯...... }
需要注意的是, 這種方式設置的環境變數只在當前Java進程(也就是當前項目)中有效, 並不會影響到其他項目.
3.2 Web項目
如果是Web項目, 可通過修改Web容器的環境變數方式實現. 以 Tomcat 為例:
# log4j的配置文件支援伺服器的vm環境變數, 格式類似${catalina.home} log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=${catalina.home}/logs/logs_tomcat.log log4j.appender.R.MaxFileSize=100MB
${catalina.home}
是在${tomcat_home}/bin/catalina.sh
中通過-D參數設置的:
-Dcatalina.home="$CATALINA_HOME"
基於這個思路, 我們也可以向Web容器的VM參數中設置一個參數, 比如-Dmylog.home="/Project/logs"
, 創建日誌對象時即可使用.
4 附錄 – 獲取當前項目、類路徑的幾種方式
public static void main(String[] args) { // 獲取 class 文件的絕對路徑, 定位到具體的包名, 結果如: // /Projects/KafkaConsumer/target/classes/org/shoufeng/consumer/ System.out.println(KafkaConsumer.class.getResource("")); // 獲取 class 文件的絕對路徑, 如: /Projects/KafkaConsumer/target/classes/, // 如果在bin目錄下通過java -jar等命令啟動時, 結果就是 /Projects/KafkaConsumer/bin/ System.out.println(ClassLoader.getSystemResource("")); System.out.println(KafkaConsumer.class.getResource("/")); System.out.println(KafkaConsumer.class.getClassLoader().getResource("")); System.out.println(Thread.currentThread().getContextClassLoader().getResource("")); // 說明: 上述4種用法的返回結果類型都是URL, 其toString()返回的內容以"file:"開頭, 可通過「.toString().substring(5)」去除 // 推薦: 使用「.getPath()」就可以直接獲取到路徑 // 獲取工程的絕對路徑, 如: /Projects/KafkaConsumer, // 若在bin中通過java -jar等命令啟動, 路徑就變成了: /Projects/KafkaConsumer/bin System.out.println(System.getProperty("user.dir")); }
參考資料
版權聲明
出處: 部落格園 瘦風的部落格(https://www.cnblogs.com/shoufeng)
感謝閱讀, 如果文章有幫助或啟發到你, 點個[好文要頂?] 或 [推薦?] 吧?
本文版權歸部落客所有, 歡迎轉載, 但 [必須在文章頁面明顯位置標明原文鏈接], 否則部落客保留追究相關人員法律責任的權利.