我想在备份成功完成时执行一项操作(但不在备份失败时执行)。
- 有没有办法将备份状态传递到备份后命令?
- 或者我可以从后备份中查询环境变量?
- 或者查询作业状态的简单方法(可能正在运行多个作业)。
- 考虑登录事件日志并使用日志解析器搜索成功消息。
我目前正在使用电子邮件通知,将电子邮件发送给机器人,该机器人从主题中解析出备份状态,然后如果备份成功则运行命令。
产品:Acronis Backup & Recovery 10
答案1
据我所见,没有简单的方法。
像您一样,我目前会收到一封任务后状态电子邮件;但是,我想将该信息的子集放入仪表板系统中。我刚刚编写了一个 Python (3.4) 脚本,用于从 Acronis 日志中提取信息并写入日志文件。我还添加了有条件执行命令的功能。(我在批处理文件中完成了这部分工作,但可以修改 Python 脚本以执行命令……从而无需使用批处理文件。)
经过一些轻微的修改/定制,它应该适合您。
概念
- Acronis 命令后操作启动批处理文件
- ...启动一个 Python 脚本
- ...解析 Acronis 日志,检测成功或失败(以及其他事项),并返回错误代码
- ...由批处理文件捕获
- ...然后根据成功或失败有条件地执行操作
注意事项
- python 脚本将读取最后修改的日志文件,因此并发的 Acronis 操作可能会有危险。
- python 脚本仅读取文件名以星期几开头的日志文件。(即它将忽略任何“console_xxxxx.log” [和类似的] 日志。但这正是我们想要的。)
- 我是一名职业开发人员,但这是我第一次尝试使用 Python,所以它可能不是很漂亮。
要求
- Python 3.4 已安装在环境 PATH 中,并与 .py 文件关联
- python
untangle
包已安装(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 解析错误,因为日志文件可能尚未刷新。
答案2
警告这日志解析器解决方案容易受到误报的影响(例如,如果一项作业运行两次,而另一项作业没有运行,那么您将获得与两项作业都成功相同的结果)。
Acronis 10 似乎没有向 Windows 日志发布足够的详细信息,以便能够唯一地标识成功甚至启动的作业。
检查-acronis-备份.bat
"C:\Program Files (x86)\Log Parser 2.2\LogParser.exe" -i:evt file:check-acronis-backup.sql > check-acronis-backup.out
type check-acronis-backup.out
grep "Elements output: 2" check-acronis-backup.out
if %ERRORLEVEL%==0 goto ReportSuccess
GOTO End
:ReportSuccess
call report-success acronis
:End
检查-acronis-备份.sql
SELECT
TOP 10 SourceName, TimeGenerated, EventCategory, Message
FROM Application
WHERE TimeGenerated > TO_TIMESTAMP(SUB(TO_INT(SYSTEM_TIMESTAMP()), 90000)) --90000 = 60*60*25
AND SourceName = 'Acronis Backup Recovery 10'
AND EventCategory = 144
AND Message like '%Task _Full backup_ completed successfully.%'