Automation

Acronis 命令後查詢備份狀態

  • January 2, 2015

我想在備份成功完成時執行一項操作(但不是在失敗時)。

  • 有沒有辦法將備份狀態傳遞給備份後命令?
  • 或者我可以從備份後查詢的環境變數?
  • 或者一種查詢作業狀態的簡單方法(可能正在執行多個作業)。
  • 考慮登錄事件日誌並使用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 文件相關聯
  • untanglepython包已安裝(pip install untangle

腳步

  1. 創建以下批處理文件並將其另存為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
)
  1. 創建以下python腳本並將其另存為acronis-last-log.py並將其放在與批處理文件相同的文件夾中。確保訪問該CONFIGURATION VARIABLES部分以更改任何路徑或選項。注意:這會創建一個基於任務名的日誌文件,每次執行 Acronis 任務時都會覆蓋它自己。要禁用日誌文件,請註釋掉with open(...) as outFileprint(..., 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)
  1. 使用以下對話框設置配置 Acronis 以將批處理文件 ( acronis.cmd) 作為命令後操作執行:
  • 命令:C:/path/to/acronis.cmd
  • 工作目錄:(C:/path/to批處理文件的位置)
  • 參數:(留空)
  • $$ $$在命令執行完成之前不要執行操作
  • $$ x $$如果使用者命令失敗則中止操作

**編輯:選中“不執行操作…”複選框可能會產生 XML 解析錯誤,因為日誌文件可能尚未刷新。

引用自:https://serverfault.com/questions/646051