注:maxcompute原名odps,是阿裡雲自研的大資料計算平台,文中出現的maxcompute與odps都指代同一平台,不做區分
與maxcompute jdbc相關的日志有兩種,一種是由jdbc内部代碼直接輸出的日志,第二種是jdbc抛出異常後,由調用jdbc api的宿主應用捕獲後輸出的。由于第二類日志取決于宿主應用如何處理異常及如何配置日志體系,是以本文主要讨論的對象是第一種日志。
在2.0-beta之前,maxcompute jdbc的日志隻會輸出到指令行終端(标準輸出流),它底層使用的是jdk自帶的 java.util.logging 的 consolehandler。是以除非你是在指令行啟動宿主應用的(相對的另一種方式是在可視化界面裡輕按兩下可執行檔案來啟動宿主應用,并沒有控制台界面),不然日志資訊并不好找。這就給使用者診斷問題和排查錯誤帶來了不便。
為什麼slf4j日志實作架構之間會産生沖突?
slf4j 是為了統一不同日志架構的行為和api而産生的一套日志門面架構,它隻提供api,但并不提供具體的日志解決方案實作。是以通常需要配合另一種具體的日志實作架構一起使用,比如 logback 、 log4j 。而假設maxcompute jdbc選擇的是 slf4j + logback ,而宿主應用選擇的是 slf4j + log4j ,那麼運作時就會出現沖突。因為通常使用者在程式設計時會調用 slf4j 的<code>loggerfactory.getlogger</code>來擷取日志執行個體,而在該方法首次被調用時會綁定一個具體的 slf4j 的實作,該行為依賴一個叫做<code>org.slf4j.impl.staticloggerbinder</code>的類。而該類在所有 slf4j 的日志實作架構中都會存在,是以當多套 slf4j 日志實作同時存在于classpath的時候,完全依賴于運作時classloader先加載了哪套實作的<code>org.slf4j.impl.staticloggerbinder</code>,加載了誰就使用誰的實作以及配置,而這是帶有不确定性的,這也是常見的一種jar包沖突問題。是以如果maxcompute jdbc帶入了與宿主應用不同的 slf4j 日志實作,那麼可能會造成宿主應用在運作時擷取到另一套實作的日志執行個體,進而讓宿主應用原有的日志配置失效。
據不完全歸納,我暫且将maxcompute jdbc的使用者大緻分為兩類,分别是取數者和開發者。
取數者
這類使用者通常是某類資料查詢或分析工具的使用者,他們需要在取數工具中添加maxcompute的jdbc driver,然後配置jdbc url等若幹參數,進而利用該工具完成對maxcompute的sql查詢。
開發者
這類使用者通常是資料産品的開發者,他們通過調用sdk或jdbc的api來編寫查詢邏輯的相關代碼,進而開發出适合目标使用者使用的軟體産品。
将 sql workbench/j 下載下傳到本地後,你會得到一個可執行檔案,輕按兩下後在彈出界面中點選 manager driver 加載我們的 jdbc jar 包。
此處請注意,由于 sql workbench/j 自身沒有引入 slf4j 的任何日志實作,是以我們可以通過添加 logback 的jar包來啟用maxcompute jdbc預設的logback實作。

然後建立一個 connection profile 。請注意在 url 部分填入的jdbc url中較之前多了一個名為 log_conf_file的參數:
該參數可用于指定一個本地的 logback 配置檔案作為用于maxcompute jdbc的日志配置。請注意,該參數是一個指定配置檔案的參數,而非指定日志輸出位置的參數。是以請確定該參數對應的目錄下該檔案是存在且應用有權限通路的,并且配置檔案需要符合logback配置檔案的格式。如果不傳遞該參數,日志将隻輸出到控制台。而以之前輕按兩下方式打開的 sql workbench/j 是沒有控制台界面的。如果需要将日志輸出到特定目錄的日志檔案中,隻需在配置檔案中為其添加相應的fileappender即可。詳見第3部分的配置說明。
對于開發者而言,應該對java的日志架構體系并不陌生,且所開發的應用可能已經使用了 slf4j 及其實作。是以首先需要明确這一點,如果已經使用了 slf4j 及其實作,那麼就沒有必要再使用jdbc自帶的配置功能,可以直接在現有應用的log配置中添加對包<code>com.aliyun.odps.jdbc</code>的日志配置。
如果你沒有使用任何的 slf4j 實作,那麼請在添加maxcompute jdbc的jar包的同時,同時向你的classpath添加logback-core-1.1.7.jar和logback-classic-1.1.7.jar兩個jar包。如果你使用的是maven,可以添加如下依賴:
你可以采用兩種方式來指定配置檔案,一種是直接将logback.xml放入classpath之中。
還有一種方式是以程式設計的方式,在如下的config中加入了 log_conf_file 屬性的配置或是在jdbc url串中帶上 log_conf_file 參數來指定(見之前sql workbench/j的示例圖)。當你同時在url和config中配置該項時,以config的值作為優先項使用。
配置說明
接着我們來看看 logback.xml 的内容:
其中<code><configuration></code>是配置檔案的根标簽,所有子标簽必須包含在根标簽之中。其中子标簽分為<code><appender></code>、<code><encoder></code>、<code><logger></code> 和 <code><root></code>。
logback 的日志執行個體是有繼承關系的。其中 <code><root></code> 就是所有日志執行個體的父執行個體,而其餘 <code><logger></code> 都是子執行個體,預設都繼承父執行個體的配置。而所有的 <code><logger></code> 又根據其 <code>name</code> 屬性的字首來繼續維持繼承關系,假設這段配置中定義了 <code>com.aliyun.odps</code> 和 <code>com.aliyun.odps.jdbc</code> 兩個日志執行個體,那後者就是前者的子執行個體。由于我們目前隻有 <code>com.aliyun.odps.jdbc</code> 這個包中有輸出日志的代碼,是以我們隻配置了一個日志執行個體,它覆寫了 <code><root></code> 的 <code>error</code> 日志級别,改為了 <code>debug</code> 級别。
其中日志的輸出級别及其嚴重等級關系為:
<code>trace < debug < info < warn < error < off</code>
即從左往右的嚴重等級依次遞增,日志數量則依次遞減。嚴重等級越小的日志級别将輸出所有大于等于它級别的日志。舉個例子,如果你選擇<code>debug</code>級别,那除<code>trace</code>之外的所有日志都将輸出。其中<code>off</code>表示不輸出日志。
而<code><appender></code>用于指定日志的輸出目标,目前的示例中配置了 <code>file</code> 和 <code>stdout</code> 兩個appender,表明分别将日志輸出到檔案和标準輸出流,其中<code>file</code>的appender中又通過 <code><file></code> 指明了日志檔案的存儲路徑。
最後我們可以看到日志執行個體會引用appender,而appender又會引用encoder,進而構造了整個日志配置的體系。
通過以上配置,我們可以在路徑/users/emerson/odps.log下(也就是你的home目錄下,上述配置示例中針對linux和windows的home目錄做了相容)得到格式如下的輸出日志: