1. 程式人生 > >slf4j.Logger的全面講解及e.getMessage()為何為空

slf4j.Logger的全面講解及e.getMessage()為何為空

測試:

   @Test
    publicvoid testDelegateHandleRequestFour2() {
        Filefile = new File("E:\\study\\text.txt");
        FileReaderfr = null;
        try{
            fr= new FileReader(file);
        }catch (FileNotFoundException e) {       
          //log.error("測試 : ",e.getMessage());
	  //log.error("測試 :"+e.getMessage());
          //log.err(“測試:”+e);
          //log.error("測試 : ",e); 
          //log.error("測試:%s",e.getMessage(), e);  
          // e.printStackTrace();
	}
}

1、log.error("測試:" ,e.getMessage());   // e.getMessage()為空,不會列印異常資訊


2、log.error("測試:" +e.getMessage());  // e.getMessage()只是獲取了異常的詳細訊息字串,沒有堆疊資訊。


3、log.error("測試:" +e);    //只會打印出異常名稱,不會列印堆疊資訊


4、log.error("測試:%s",e.getMessage(), e);  //在slf4j中 %s不是字串轉換符,不起作用 %s會原樣輸出到日誌。 需要刪除。


5、可以使用e.printStackTrace() 列印異常的堆疊資訊,但是後面不要在使用log.error("測試:" ,e);   //這樣異常堆疊資訊會列印重複

可以使用log.error("查詢賬戶資產時:" +e.getMessage()); 這種只會列印異常的字串。

6、只認緊挨著的{}符號

log.error("測試 ,姓名:{{}} 年齡:{}"+e,name,age);


 網上看到有人說:試了下其他的幾個runtime異常,發現getMessage都是為空的,之後又去試了下SQLException和IOException,發現者兩種異常的在catch的時候getMessage是不為null的。由此覺得runtime異常發生的時候JVM呼叫的是父類無參的構造器。

public Exception() {        super();    }

而SQLException和IOException異常發生的時候JVM呼叫的是父類有參的構造器

publicException(String message) {       super(message);    }

所以SQLException和IOException的getMessage不為null,而runtime異常卻為空。

但是實際測試結果:

@Test
    publicvoid testDelegateHandleRequestOfSQLException() {
        Modeluser = null;
        try{
            StringBuffersql = new StringBuffer();
            List<v_user_users>v_user_users_list = null;
           
            sql.append(SQLTempletes.SELECT);
            sql.append(SQLTempletes.V_USER_USERS);
            sql.append("where andt_users.id = ?");   //讓sql語法錯誤
            EntityManagerem = JPA.em();
           Query query = em.createNativeQuery(sql.toString(),v_user_users.class);
           query.setParameter(1, 1);
           query.setMaxResults(1);
           v_user_users_list = query.getResultList();
           if(v_user_users_list.size() > 0){
             user = v_user_users_list.get(0);
           }
        }catch(Exception e) {
            //e.printStackTrace();
            log.info("使用者setId填充時(lazy=true):",e.getMessage());    }
    }


使用log.info("使用者setId填充時(lazy=true):",e.getMessage());


使用log.info("使用者setId填充時(lazy=true):",e); 


說明在報sql異常或IO異常的時候getMessage在第二個引數時也是null。

這種寫法log.error("測試 : ",e.getMessage()); 為null的原因最終原因其實是:Log的方法檢測最後一個引數是不是一個Throwable ,如果是則列印異常的堆疊資訊,如果不是就當成前面format的引數,如果沒有{}佔位符,則忽略。

error方法的api如下:

public void error(String msg);

public void error(String format, Object arg);

public void error(String format, Object arg1,Object arg2);

public void error(String format, Object...arguments);

public void error(String msg, Throwable t);

public void error(Marker marker, String msg);

public void error(Marker marker, String format,Object arg);

public void error(Marker marker, String format,Object arg1, Object arg2);

public void error(Marker marker, String format,Object... arguments);

public void error(Marker marker, String msg,Throwable t);

參考資料:

Slf4j官方網站:

https://www.slf4j.org/

Slf4j原始碼請參考:

下面就一起學習和總結下slf4j

slf4j的使用與繫結原理

slf4J的使用

前文說到了,單獨的slf4j是不能工作的,必須帶上其他具體的日誌實現方案。就以apache的log4j作為具體日誌實現方案為例,如果在工程中要使用slf4j作為介面,並且要用log4j作為具體實現方案,那麼我們需要做的事情如下:(下面的xxx表示具體版本號)

l   將slf4j-api-xxx.jar加入工程classpath中;

l   將slf4j-log4jxx-xxx.jar加入工程classpath中;

l   將log4j-xxx.jar加入工程classpath中;

l   將log4j.properties(log4j.xml)檔案加入工程classpath中。

log4j.rootLogger=DEBUG,console

log4j.appender.console=org.apache.log4j.ConsoleAppender

log4j.appender.console.layout=org.apache.log4j.PatternLayout

log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-ddHH:mm:ss,SSS} [%c]-[%p] %m%n

使用 SLF4J  的程式碼:

public class TestSlf4j {

    private static finalLogger logger = LoggerFactory.getLogger(TestSlf4j.class);

    public static voidmain(String[] args) {

        logger.info("Hello{}","SLF4J");

    }

}

執行它,控制檯輸出:

2017-05-23 09:14:51,390[com.unmi.TestSlf4j]-[INFO] Hello SLF4J

slf4j的工作原理:

首先,slf4j-api作為slf4j的介面類,使用在程式程式碼中,這個包提供了一個Logger類和LoggerFactory類,Logger類用來打日誌,LoggerFactory類用來獲取Logger;slf4j-log4j是連線slf4j和log4j的橋樑,怎麼連線的呢?我們看看slf4j的LoggerFactory類的getLogger函式的原始碼:

/**

 * Return alogger named corresponding to the class passed as parameter, using

 * the staticallybound {@link ILoggerFactory} instance.

 *

 * @paramclazz the returned logger will be named after clazz

 * @returnlogger

 */

public static Logger getLogger(Class clazz) {

  returngetLogger(clazz.getName());

}

/**

 * Return alogger named according to the name parameter using the statically

 * bound{@link ILoggerFactory} instance.

 *

 * @paramname The name of the logger.

 * @returnlogger

 */

public static Logger getLogger(String name) {

 ILoggerFactory iLoggerFactory = getILoggerFactory();

  returniLoggerFactory.getLogger(name);

}

  publicstatic ILoggerFactory getILoggerFactory() {

  if(INITIALIZATION_STATE == UNINITIALIZED) {

   INITIALIZATION_STATE = ONGOING_INITIALIZATION;

   performInitialization();

  }

  switch(INITIALIZATION_STATE) {

    caseSUCCESSFUL_INITIALIZATION:

     return StaticLoggerBinder.getSingleton().getLoggerFactory();

    caseNOP_FALLBACK_INITIALIZATION:

     return NOP_FALLBACK_FACTORY;

    caseFAILED_INITIALIZATION:

      thrownew IllegalStateException(UNSUCCESSFUL_INIT_MSG);

    caseONGOING_INITIALIZATION:

      //support re-entrant behavior.

      //See also http://bugzilla.slf4j.org/show_bug.cgi?id=106

     return TEMP_FACTORY;

 }

  throw newIllegalStateException("Unreachable code");

}

追蹤到最後,發現LoggerFactory.getLogger()首先獲取一個ILoggerFactory介面,然後使用該介面獲取具體的Logger。獲取ILoggerFactory的時候用到了一個StaticLoggerBinder類,仔細研究我們會發現StaticLoggerBinder這個類並不是slf4j-api這個包中的類,而是slf4j-log4j包中的類,這個類就是一箇中間類,它用來將抽象的slf4j變成具體的log4j,也就是說具體要使用什麼樣的日誌實現方案,就得靠這個StaticLoggerBinder類。再看看slf4j-log4j包中的這個StaticLoggerBinder類建立ILoggerFactory長什麼樣子:

private final ILoggerFactory loggerFactory;

private StaticLoggerBinder() {

 loggerFactory = new Log4jLoggerFactory();

  try {

    Levellevel = Level.TRACE;

  } catch(NoSuchFieldError nsfe) {

    Util

       .report("This version of SLF4J requires log4j version 1.2.12 orlater. See also http://www.slf4j.org/codes.html#log4j_version");

  }

}

public ILoggerFactory getLoggerFactory() {

  returnloggerFactory;

}

可以看到slf4j-log4j中的StaticLoggerBinder類建立的ILoggerFactory其實是一個 org.slf4j.impl.Log4jLoggerFactory ,這個類的getLogger函式是這樣的:

public Logger getLogger(String name) {

  Loggerslf4jLogger = loggerMap.get(name);

  if(slf4jLogger != null) {

    returnslf4jLogger;

  } else {

   org.apache.log4j.Logger log4jLogger;

   if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))

     log4jLogger = LogManager.getRootLogger();

    else

     log4jLogger = LogManager.getLogger(name);

    LoggernewInstance = new Log4jLoggerAdapter(log4jLogger);

    LoggeroldInstance = loggerMap.putIfAbsent(name, newInstance);

    returnoldInstance == null ? newInstance : oldInstance;

  }

}

就在其中建立了真正的 org.apache.log4j.Logger ,也就是我們需要的具體的日誌實現方案的Logger類。就這樣,整個繫結過程就完成了。

SLF4J是為各種loging APIs提供一個簡單統一的介面,從而使得終端使用者能夠在部署的時候配置自己希望的loging APIs實現。準確的說,slf4j並不是一種具體的日誌系統,而是一個使用者日誌系統的facade,允許使用者在部署最終應用時方便的變更其日誌系統。

在系統開發中,統一按照slf4j的API進行開發,在部署時,選擇不同的日誌系統包,即可自動轉換到不同的日誌系統上。比如:選擇JDK自帶的日誌系統,則只需要將slf4j-api-1.5.10.jar和slf4j-jdk14-1.5.10.jar放置到classpath中即可,如果中途無法忍受JDK自帶的日誌系統了,想換成log4j的日誌系統,僅需要用slf4j-log4j12-1.5.10.jar替換slf4j-jdk14-1.5.10.jar即可(當然也需要log4j的jar及配置檔案)

SLF4J獲得logger物件:

private staticfinal Logger logger = LoggerFactory.getLogger(Test.class);

LOG4J獲得logger物件:

private staticLogger logger = Logger.getLogger(Test.class);

總結:

1. 大部分人在程式裡面會去寫logger.error(exception),其實這個時候log4j會去把這個exception tostring。真正的寫法應該是logger(message.exception);而slf4j就不會使得程式設計師犯這個錯誤。

2. log4j間接的在鼓勵程式設計師使用string相加的寫法,而slf4j就不會有這個問題。

3. 你可以使用logger.error("{}is+serviceid",serviceid);

4. 使用slf4j可以方便的使用其提供的各種具體的實現的jar。(類似commons-logger)

5. 從commons--logger和log4j merge非常方便,slf4j也提供了一個swing的tools來幫助大家完成這個merge。

slf4j的用法:

1.   從org.slf4j包匯入Logger和LoggerFactory

import org.slf4j.Logger;  

import org.slf4j.LoggerFactory;  

2. 宣告日誌類private final Logger logger = LoggerFactory.getLogger(LoggingSample.class);  

3. 簡單用法

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public classHelloWorld{
  public staticvoid main(String[] args){
    Logger logger = LoggerFactory.getLogger(HelloWorld.class);
    logger.info("Hello World");
  }
}

4.輸出帶引數的日誌資訊,使用{}佔位符,方法中傳入引數

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 public class Wombat {
   final Logger logger = LoggerFactory.getLogger(Wombat.class);
   Integer t;
   Integer oldT;
   public void setTemperature(Integer temperature) {
     oldT = t;       
     t = temperature;
     logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);
     if(temperature.intValue() > 50) {
       logger.info("Temperature has risen above 50 degrees.");
     }
   }
} 


相關推薦

slf4j.Logger全面講解e.getMessage()為何

測試: @Test publicvoid testDelegateHandleRequestFour2() { Filefile = new File("E:\\study\\text.txt"); FileReaderfr =

Java 判斷實體物件所有屬性是否

1、判斷實體物件是否為空 2、判斷物件所有屬性是否為空 3、特別注意,實體類中如果有基本資料型別,會影響判斷 package com.liuxd.object; import org.apache.commons.lang3.StringUtils; import java.lang

SQL註入原理講解防範

ant htm part 無效 快樂 日常 field users lib 原文地址:http://www.cnblogs.com/rush/archive/2011/12/31/2309203.html 1.1.1 摘要 日前,國內最大的程序員社區CSDN網站

nginxlocation重要語法講解實踐檢驗

linuxnginx常見日誌收集及分析工具有rsyslog,awstats,flume,elk,storm等1 nginx location作用: location指令的作用是可以根據用戶請求的URL來執行不同的應用,就是根據用戶請求的網站地址URL匹配,匹配成功即進行相關的操作。2 loc

NAT穿透的詳細講解分析

設置 網通 我會 什麽 報告 pub 後端 火墻 聯系 原文地址:http://bbs.pediy.com/thread-131961.htm 一、什麽是NAT?為什麽要使用NAT?NAT是將私有地址轉換為合法IP地址的技術,通俗的講就是將內網與內網通信時怎麽將內網私有IP

Oozie與Coordinator調度講解系統時區配置與定時觸發兩種配置方式

-- track eno star es2017 alt coo 之前 res 1:修改本地linux時區 查看時區 - 號代表西 + 號 代表東 北京時間是東八區 設置時區的配置文件所在位置 1 cd /usr/share/zoneinfo/

Android XListView實現原理講解分析

就是 指定 不同 true -h -name 修改 一個 部分 XListview是一個非常受歡迎的下拉刷新控件,但是已經停止維護了。之前寫過一篇XListview的使用介紹,用起來非常簡單,這兩天放假無聊,研究了下XListview的實現原理,學到了很多,今天分享給大家。

修改org.slf4j.Logger時,修改默認配置文件位置

path trac reset tst try tex exit except new File logbackFile = new File(ConstantsTools.PATH_LOG_CONFIG);if (logbackFile.exists()) { Lo

activeMQ 講解實戰

安全 持久化數據 sts 路徑 code rtu 默認值 字符 更新 #### 軟件架構項目中需要用到activeMQ 下載地址:http://activemq.apache.org/download.html #### 安裝教程需要安裝jdk環境activeMQ免安裝下載

【Hadoop 分布式部署 八:分布式協作框架Zookeeper架構功能講解 本地模式安裝部署和命令使用 】

.gz 權限 實現 creat info 應用 data 就是 數據結構 What is Zookeeper     是一個開源的分布式的,為分布式應用提供協作服務的Apache項目     提供一個簡單的原語集合,以便與分布式應用可以在他之上構建更高層次的同步服務

e.getMessage() e.printStackTrace() 和e.printStackTrace() 小結

void equal ktr catch int 執行 [] stat trac 1 e.getMessage() ; 只會獲得異常的名稱。比如說NullPoint 空指針,就告訴你說是空指針 2.e.toString(): 獲得異常種類和錯誤信息 3.e.prin

MongoDB復制集搭建簡單講解驗證

oca serve aac 復制 color water 介紹 集成 mongod 一.MongoDB復制集搭建介紹 二.復制集搭建搭建環境:Centos 7mongodb-linux-x86_64-3.2.12.tgz 1.解壓安裝mongodb到/usr/local/m

常見數論的講解程式碼

文章目錄 整除 同餘 質數 Eratosthenes 篩法(埃氏篩法) 線性篩法 唯一分解定理 威爾遜定理 費馬小定理 GCD 拓展歐幾里得定理

AlexNet 講解pytorch實現 ----1 AlexNet主要技術突破點

一. AlexNet網路結構 2012年,該網路ILSVRC-2012影象分類的冠軍,top-5的識別錯誤率為15.3%, 比第二名高出10個百分點。 下面是論文中的網路結構: 原始網路將模型分為兩部分,分開在兩個GPU上訓練,與下面合併的網路結構等價:

Django後臺管理系統講解使用

大家在建立Django專案後,在根路由urls.py檔案中,會看到一行程式碼 from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls),]上面看到匯入的admin模組,就是本節所要說的主要內容。 主

全面虛擬鍵適配說明

小米:https://dev.mi.com/console/doc/detail?pId=1160 官方:https://developer.android.com/guide/practices/screens_support#NewQualifiers 1. 前言 自2016年小

全面講解分析基於區鏈塊的實現貨幣中心化的商城報單系統

1、前言: 系統是基於區鏈塊分散式智慧合約技術,實現貨幣的去中心化、點對點無損無痕流通,讓流通產生價值,也可以通證(雙倍積分釋放)提現,對接交易所可用錢包轉出。年賺百萬,只要輕鬆轉動通證。 2、名稱說明: 商城】1、贈送積分套餐購物板塊 2、商城商家版(餘額和通證可以購物) 【註冊】

RecyclerView 全面使用分析 - 基礎篇(一)

一、RecyclerView 介紹 在 RecyclerView 出來之前,大家都在使用 ListView、GridView,當然 RecyclerView 出來之後,基本上都轉向了 RecyclerView,從名字上可以看出,它能夠實現view 的複用,同樣 ListView

手把手教你ExtJS從入門到放棄——篇四(Ext.window元件API詳細講解demo演示)

1.開啟API找到Ext--》window --》window 2.灰色齒輪代表是個元件,xtype是別名,就像前面MessageBox的別名是Msg一樣,使用別名是一樣的效果,點進原始碼可以看到是進行了引用的賦值 3.第一個元件:Ext.window.Windo

getCause()、e.getMessage()產生的結果

(1)e.getMessage()  e.getMessage(); 只會獲得具體的異常名稱. 比如說NullPoint 空指標,就告訴你說是空指標...  (2)e.getCause() (3)e.getCause().getMessage();