Automation
Acronis 命令後查詢備份狀態
我想在備份成功完成時執行一項操作(但不是在失敗時)。
- 有沒有辦法將備份狀態傳遞給備份後命令?
- 或者我可以從備份後查詢的環境變數?
- 或者一種查詢作業狀態的簡單方法(可能正在執行多個作業)。
- 考慮登錄事件日誌並使用LogParser搜尋成功消息。
我目前正在使用電子郵件通知,將電子郵件發送到機器人,機器人從主題中解析出備份狀態,然後在備份成功時執行命令。
產品:Acronis Backup & Recovery 10
據我所知,沒有一個簡單的方法。
和你一樣,我目前收到一封任務後狀態電子郵件;但是,我想將該資訊的子集放入儀表板系統中。我剛剛編寫了一個 python (3.4) 腳本來從 Acronis 日誌中提取資訊並寫入日誌文件。我也增加了有條件地執行命令的能力。(我在批處理文件中完成了這部分,但是可以修改 python 腳本以執行命令……從而消除對批處理文件的需要。)
通過一些輕微的修改/定制,這應該適合你。
概念
- Acronis 命令後操作啟動批處理文件
- …啟動 python 腳本
- …解析 Acronis 日誌,檢測成功或失敗(除其他外),並返回錯誤程式碼
- …由批處理文件擷取
- …然後根據成功或失敗有條件地執行操作
注意事項
- python 腳本將讀取最後修改的日誌文件,因此並發 Acronis 操作可能很冒險。
- python 腳本僅讀取文件名以星期幾開頭的日誌文件。(即它將忽略任何“console_xxxxx.log”$$ and similar $$日誌。但這正是我們想要的。)
- 我是一名開發人員,但這是我第一次嘗試 python,所以它可能不是很漂亮。
要求
- Python 3.4 安裝在環境 PATH 中,並與 .py 文件相關聯
untangle
python包已安裝(pip install untangle
)腳步
- 創建以下批處理文件並將其另存為
acronis-last-log.cmd
. 更改適用的命令以有條件地執行操作。@echo off REM Filename: acronis-last-log.cmd acronis-last-log.py if ERRORLEVEL 1 ( echo This statement is executed whenever the Acronis task FAILS echo Insert any action here within the if-clause ) else ( echo This statement is executed whenever the Acronis task SUCCEEDS echo Insert any action here within the else-clause )
- 創建以下python腳本並將其另存為
acronis-last-log.py
並將其放在與批處理文件相同的文件夾中。確保訪問該CONFIGURATION VARIABLES
部分以更改任何路徑或選項。注意:這會創建一個基於任務名的日誌文件,每次執行 Acronis 任務時都會覆蓋它自己。要禁用日誌文件,請註釋掉with open(...) as outFile
和print(..., file=outFile)
行,確保根據需要調整任何程式碼縮進。要更改日誌路徑,請編輯outputPath
變數。# Filename: # acronis-last-log.py # # Description: # Process an Acronis log file and print out relevant output in a formatted string. # # Rules: # 1. if any log entry is greater than ACRONIS_LOG_INFO, report that the task has failed. # - This is how the Acronis emails work. Warnings will cause the "failed" summary import glob import os import sys import textwrap import time import untangle # to install: pip install untangle ########## CONSTANTS DECONSTRUCTED FROM ACRONIS LOGS ########################### # log module that provides the overall task status ACRONIS_STATUS_MODULE = 316 # Acronis log error levels ("levels") # (0 and 1 are dummy entries that don't seem to exist within the logs) ACRONIS_LOG_DUMMY0 = 0 ACRONIS_LOG_DUMMY1 = 1 ACRONIS_LOG_INFO = 2 ACRONIS_LOG_WARNING = 3 ACRONIS_LOG_ERROR = 4 # Error level descriptions # descriptions for printing, indexed by the above constants # padded to 7 characters long for alignment ERROR_LEVEL_DESCRIPTIONS = ["DUMMY0 ", "DUMMY1 ", "INFO ", "WARNING", "ERROR "] ########## CONFIGURATION VARIABLES ############################################# # showSubMessages # show auxiliary messages that meet the error level threshold (set below) # True: show subMessages # False: only show the overall exit error level (module 316) showSubMessages = True # logPath # path to Acronis log files (default: C:\ProgramData\Acronis\TrueImageHome\Logs) logPath = r'C:\ProgramData\Acronis\TrueImageHome\Logs' # outputPath # path to where this script will output outputPath = r'.' # debug # turn debugging on? (default: False) debug = False # minLevelToDisplay # minimum error level to display (default: ACRONIS_LOG_WARNING) minLevelToDisplay = ACRONIS_LOG_WARNING # maxLevelToDisplay # maximum error level to display (default: ACRONIS_LOG_ERROR) maxLevelToDisplay = ACRONIS_LOG_ERROR ########## HELPER FUNCTIONS #################################################### def logDescription(errorLevel): """Return a log description based on Acronis error level.""" return ERROR_LEVEL_DESCRIPTIONS[errorLevel] ########## FUNCTIONS ########################################################### def process(logFile): """Process an Acronis log file and print out relevant output in a formatted string. with !showSubMessages, just a single line is printed: yyyy-mm-dd hh:mm:ss ERRORLEVEL [AcronisTask] Summary e.g. 2014-12-25 14:16:40 WARNING [MyBackupTask] execution failed with showSubMessages, multiple will be printed: yyyy-mm-dd hh:mm:ss ERRORLEVEL [AcronisTask] Summary ERRORLEVEL SubMessage 1 ERRORLEVEL SubMessage 2 ERRORLEVEL SubMessage n e.g. 2014-12-25 14:16:40 ERROR [MyBackupTask] execution failed ERROR The quotas are violated. ERROR Cannot perform this operation in quiet mode. (0x103F1) Tag = 0x1D8EAB676A3F6BAA Target drive is running out of space. (0x4001D) Tag = 0x1D8EAB676A3F6BAB WARNING Terminated by user. WARNING Batch operation has been terminated by user. Note: the first ERRORLEVEL printed (the one between the timestamp and [AcronisTask]) will be the highest error level in the log """ # store the highest error level highestLevel = ACRONIS_LOG_DUMMY0 subMessages = [] success = False try: xmlDocument = untangle.parse(logFile) # read task_name taskName = xmlDocument.log['task_name'] # open output file with open(outputPath + r"\acronis-" + taskName + ".log", 'w') as outFile: if debug: print("Debug mode enabled. Processing", logFile) print("Debug mode enabled. Processing", logFile, file=outFile) # for each log event for event in xmlDocument.log.event: # read attributes eventId = int(event['id']) eventLevel = int(event['level']) eventModule = int(event['module']) eventCode = int(event['code']) eventTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(event['time']))) eventMessage = event['message'] # strip unicode characters out (yes, it happens for some INFO messages annotating user responses) eventMessage = eventMessage.encode('ascii', 'ignore').decode('ascii', 'ignore') # set highestLevel if eventLevel > highestLevel: highestLevel = eventLevel # add subMessages, if they fit into the level threshold if (eventLevel >= minLevelToDisplay) and \ (eventLevel <= maxLevelToDisplay): subMessages.append([logDescription(eventLevel), eventMessage]) # create summary message for top line summary = "execution failed" # determine success if highestLevel <= ACRONIS_LOG_INFO: summary = "completed successfully" success = True # print the summary message if (highestLevel >= minLevelToDisplay) and \ (highestLevel <= maxLevelToDisplay): print(eventTime, logDescription(highestLevel), "[" + taskName + "]", summary) print(eventTime, logDescription(highestLevel), "[" + taskName + "]", summary, file=outFile) # print subMessages, maybe if showSubMessages: for message in subMessages: # do some fancy textwrapping here, because sometimes there are really long messages that wrap in the wrong places # and a hanging indent is prettier print(' '*(len(eventTime)+1) + message[0], textwrap.fill(message[1], 160, subsequent_indent=' '*30)) #30 = len("YYYY-MM-DD HH:MM:SS ERRCODE ") + 2 for indenting print(' '*(len(eventTime)+1) + message[0], textwrap.fill(message[1], 160, subsequent_indent=' '*30), file=outFile) #30 = len("YYYY-MM-DD HH:MM:SS ERRCODE ") + 2 for indenting except: if debug: # probably want to catch the error in debug... raise else: print("Generic Error with file <" + logFile + ">.") # return success flag return success ########## ENTRY POINT ######################################################### if __name__ == "__main__": # only grab files named with a day of week # so, ignore non-compliant (won't parse) logs # - console*, # - monitor.log, # - afcdpsrv.log # - NSB*.log (non-stop backup) logFiles = [f for f in glob.iglob(logPath + "\*.log") \ if "Sunday" in f or \ "Monday" in f or \ "Tuesday" in f or \ "Wednesday" in f or \ "Thursday" in f or \ "Friday" in f or \ "Saturday" in f] # sort by modified date (descending) logFiles.sort(key=os.path.getmtime, reverse=True) # get the most recent newestFile = logFiles[0] # process newest file success = process(newestFile) # for testing purposes... # process all log files #for logFile in logFiles: # process(logFile) # return with exit code 0 if success (no warnings or errors), otherwise 1 sys.exit(0 if success else 1)
- 使用以下對話框設置配置 Acronis 以將批處理文件 (
acronis.cmd
) 作為命令後操作執行:
- 命令:
C:/path/to/acronis.cmd
- 工作目錄:(
C:/path/to
批處理文件的位置)- 參數:(留空)
- $$ $$在命令執行完成之前不要執行操作
- $$ x $$如果使用者命令失敗則中止操作
**編輯:選中“不執行操作…”複選框可能會產生 XML 解析錯誤,因為日誌文件可能尚未刷新。