1

I would like to perform an action when the backup completes successfully (but not when it fails).

  • Is there a way to pass the backup status into a post-backup command?
  • Or an environment variable I can query from the post-backup?
  • Or an easy way to query the status of the job (multiple jobs could be running).
  • Considering login to the event log and using LogParser to search for the success message.

I am currently using the email notification, sending the email to a bot, which parses out the backup status from the subject, then runs a command if the backup was successful.

Product: Acronis Backup & Recovery 10

Andy Joiner
  • 1,273
  • 1
  • 10
  • 24

2 Answers2

2

From what I've seen, there isn't an easy way.

Like you, I currently get a post-task status email; however, I'd like to get a subset of that information into a dashboard system. I just wrote a python (3.4) script to extract info from the Acronis logs and write to a log file. I've added in the ability to conditionally execute commands too. (I did this part in a batch file, but the python script could be modified to execute commands...thereby removing the need for the batch file.)

With some slight modification/customization, this should work for you.

Concept

  • An Acronis post-command action launches a batch file
  • ...which launches a python script
  • ...which parses the Acronis log, detects success or failure (among other things), and returns an error code
  • ...which is captured by the batch file
  • ...which then conditionally performs an action based on success or failure

Caveats

  • The python script will read the last-modified log file, so concurrent Acronis operations might be dicey.
  • The python script only reads log files which have filenames beginning with days of the week. (i.e. it will ignore any "console_xxxxx.log" [and similar] logs. But this is what we want.)
  • I'm a developer by trade, but this is my first attempt at python, so it might not be very pretty.

Requirements

  • Python 3.4 is installed, in the environmental PATH, and associated to .py files
  • The untangle python package is installed (pip install untangle)

Steps

  1. Create the following batch file and save it as acronis-last-log.cmd. Change the applicable commands to conditionally perform actions.

    @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
    )
    
  2. Create the following python script and save it as acronis-last-log.py and put it in the same folder as the batch file. Make sure to visit the CONFIGURATION VARIABLES section to change any paths or options. Note: This does create a taskname-based log file which overwrites itself each time the Acronis task is executed. To disable the log file, comment out the with open(...) as outFile and print(..., file=outFile) lines, making sure to adjust any code indentations as needed. To change the log path, edit the outputPath variable.

    # 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)
    
  3. Configure Acronis to run a batch file (acronis.cmd) as a post-command action with the below dialog settings:

    • Command: C:/path/to/acronis.cmd
    • Working Directory: C:/path/to (location of the batch file)
    • Arguments: (leave blank)
    • [ ] Do not perform operations until the command's exection is complete
    • [x] Abort the operation if the user command fails

Edit: leaving the 'Do not perform operations...' checkbox checked might yield XML parsing errors, as the log file might not have flushed yet.

Cyber
  • 36
  • 3
1
  1. See Cyber's comprehensive answer - this the route I would recommend.

  2. Before Cyber's post, I did have some success with LogParser, as I wanted to track 2 backup jobs.

Caveat This LogParser solution is susceptible to false positives (e.g. if one job ran twice, and the other didn't run, then you would get the same results as both jobs succeeding).

Acronis 10 does not seem to post enough detail to the windows logs to be able to uniquely identify jobs succeeding or even starting.

check-acronis-backup.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

check-acronis-backup.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.%'
Andy Joiner
  • 1,273
  • 1
  • 10
  • 24