前言
公司的DataX已經用了2年多了,性能以及基本功能上沒有太大問題。但是有一個問題一直困擾着我,就是DataX的錯誤告警。DataX的日誌問題,一直令人頭疼。隨着job的逐漸增多,一個調度程序或者腳本打印出來的日誌實在太多,假如中途有哪個job執行報錯,根本無法排查,雖然DataX自身會記錄每個job執行的日誌,在log目錄下,命名規則:腳本名稱+執行時間,但是文件數目過多排查起來還是挺困難的。
設計思路
有了需求,就可以開始設計,給DataX添加告警功能有兩種辦法,修改源碼和捕獲日誌,當時爲了不侵入源碼,採用了捕獲日誌的方式。
代碼改動
修改DataX啓動類,即bin/datax.py,將datax.py打印出來的日誌放入pipe(管道)緩存中,根據最後執行返回的code判斷任務成功還是失敗,失敗則需要調用告警功能。具體修改後的代碼如下:
if __name__ == "__main__":
printCopyright()
parser = getOptionParser()
options, args = parser.parse_args(sys.argv[1:])
if options.reader is not None and options.writer is not None:
generateJobConfigTemplate(options.reader,options.writer)
sys.exit(RET_STATE['OK'])
if len(args) != 1:
parser.print_help()
sys.exit(RET_STATE['FAIL'])
startCommand = buildStartCommand(options, args)
# print startCommand
child_process = subprocess.Popen(startCommand, shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
register_signal()
start=time.time()
errmsg=[]
while child_process.poll() == None:
line=child_process.stdout.readline()
print(line), # 使用,是爲了使打印出來的日誌不換行
errmsg.append(line)
if time.time() - start >= 1800: # 超時時間30分鐘
# 可以添加一些超時的信息
break
if child_process.returncode != 0:
# 執行具體的告警操作,可以從啓動參數中獲取到具體的腳本名稱
# 解析errmsg或者直接輸出
sys.exit(child_process.returncode)
總結
- 上述代碼只是在datax.py裏面新增一些退出前的操作,並不影響主要邏輯,可以放心修改。
- 這裏面有個比較坑的是,即使異常信息,但是在stderr(標準錯誤)中還是無法捕獲。因此,所有的信息都只能從stdout(標準輸出)中讀取,然後解析或者直接輸出到告警模塊。
- 我個人在項目中只是簡單的加了個郵件告警,內容爲該次job任務的所有日誌信息,方便從日誌中分析是什麼原因造成的錯誤。
- 另外,使用DataX採集阿里雲ADB(AnalyticDB 3.0)有極小的概率會出現死循環的現象(就是一直在讀取寫入重複的數據),使用mysql或者RDS不會有類似情況發生,可能是我的DataX版本過低,畢竟2年前還沒有ADB 3.0呢,可能最新版的已經修復了這個問題。