#!/bin/sh # # baculabackupreport.sh # # ------------------------------------------------------------------------------ # # waa - 20130428 - Initial release. # Generate basic Bacula backup report. # # waa - 20170501 - Change Log moved to bottom of script. # # ------------------------------------------------------------------------------ # # Copyright (c) 2013-2017, William A. Arlofski waa-at-revpol-dot-com # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # ------------------------------------------------------------------------------ # System variables # ---------------- server="@hostname@" admin="@job_email@" bcbin="/opt/bacula/bin/bconsole" sendmail="/usr/sbin/sendmail" bcconfig="/opt/bacula/etc/bconsole.conf" # Database variables # ------------------ dbtype="pgsql" # Supported options are pgsql, mysql, mariadb db="bacula" dbuser="bacula" dbbin="/usr/bin/psql" # dbpass="-pPassword" # Uncomment and set db password if one is used # Formatting variables # -------------------- html="yes" # Generate HTML emails instead of plain text emails? boldstatus="yes" # Set tag on Status field (only if html="yes") colorstatusbg="yes" # Colorize the Status cell's background? (only if html="yes") jobtableheadercolor="#b0b0b0" # Background color for the HTML table's header jobtablejobcolor="#f4f4f4" # Background color for the job rows in the HTML table runningjobcolor="#4d79ff" # Background color of the Status cell for "Running" jobs goodjobcolor="#00f000" # Background color of the Status cell for "OK" jobs warnjobcolor="#ffff00" # Background color of the Status cell for "OK" jobs (with warnings - well, actually with 'joberrors') badjobcolor="#cc3300" # Background color of the Status cell for "bad" jobs goodjobwitherrcolor="#cccc00" # Background color of the Status cell for "OK" jobs (with errors) - Not implemented due to request fontfamily="Verdana, Arial, Helvetica, sans-serif" # Set the font family to use for HTML emails fontsize="16px" # Set the font size to use for email title and print summaries fontsizejobinfo="12px" # Set the font size to use for job information inside of table fontsizesumlog="10px" # Set the font size of bad logs and job summaries printsummary="yes" # Print a short summary after the job list table? (Total Jobs, Files & Bytes) emailsummaries="no" # Email all job summaries. Be careful with this, it can generate very large emails emailbadlogs="yes" # Email logs of bad jobs or jobs with JobErrors -ne 0. Be careful, this can generate very large emails. addsubjecticon="yes" # Prepend the email Subject with UTF-8 icons (a 'checkmark', 'circle with slash', or a bold 'x') nojobsicon="=?utf-8?Q?=E2=8A=98?=" # utf-8 subject icon when no jobs have been run goodjobsicon="=?utf-8?Q?=E2=9C=94?=" # utf-8 subject icon when all jobs were "OK" badjobsicon="=?utf-8?Q?=E2=9C=96?=" # utf-8 subject icon when there are jobs with errors etc starbadjobids="yes" # Prepend an asterisk "*" to jobids of "bad" jobs sortfield="EndTime" # Which catalog db field to sort on? Multiple,fields,work,here sortorder="DESC" # Which direction to sort? emailtitle="Jobs Run On ${server} in the Past ${1} Hours" # This is prepended at the top of the email, before the jobs table # -------------------------------------------------- # Nothing should need to be modified below this line # -------------------------------------------------- hist=${1} if [ -z ${hist} ]; then echo -e "\nUSE:\n$0 \n" exit 1 fi if [ ! -e ${bcconfig} ]; then echo -e "\nThe bconsole configuration file does not seem to be '${bcconfig}'." echo -e "Please check the setting for the variable 'bcconfig'.\n" exit 1 fi if [ ! -x ${bcbin} ]; then echo -e "\nThe bconsole binary does not seem to be '${bcbin}', or it is not executable." echo -e "Please check the setting for the variable 'bcbin'.\n" exit 1 fi if [ ! -x ${dbbin} ]; then echo -e "\nThe database client binary does not seem to be '${dbbin}', or it is not executable." echo -e "Please check the setting for the variable 'dbbin'.\n" exit 1 fi if [ ! -x ${sendmail} ]; then echo -e "\nThe sendmail binary does not seem to be '${sendmail}', or it is not executable." echo -e "Please check the setting for the variable 'sendmail'.\n" exit 1 fi # Build query based on dbtype. Good thing we have "standards" Sigh... # ------------------------------------------------------------------- case ${dbtype} in mysql ) queryresult=$(echo "SELECT JobId, Name, StartTime, EndTime, Type, Level, JobStatus, JobFiles, JobBytes, \ TIMEDIFF (EndTime,StartTime) as RunTime, JobErrors \ FROM Job \ WHERE (RealEndTime >= DATE_ADD(NOW(), INTERVAL -${hist} HOUR) OR JobStatus='R') \ ORDER BY ${sortfield} ${sortorder};" \ | ${dbbin} -u ${dbuser} ${dbpass} ${db} \ | sed '/^JobId/d' ) ;; pgsql ) queryresult=$(echo "SELECT JobId, Name, StartTime, EndTime, Type, Level, JobStatus, JobFiles, JobBytes, \ AGE(EndTime, StartTime) as RunTime, JobErrors \ FROM Job \ WHERE (RealEndTime >= CURRENT_TIMESTAMP(2) - cast('${hist} HOUR' as INTERVAL) OR JobStatus='R') \ ORDER BY ${sortfield} ${sortorder};" \ | ${dbbin} -U ${dbuser} ${dbpass} ${db} -0t \ | sed -e 's/|//g' -e '/^$/d' ) ;; mariadb ) queryresult=$(echo "SELECT JobId, Name, StartTime, EndTime, Type, Level, JobStatus, JobFiles, JobBytes, \ TIMEDIFF (EndTime,StartTime) as RunTime, JobErrors \ FROM Job \ WHERE (RealEndTime >= DATE_ADD(NOW(), INTERVAL -${hist} HOUR) OR JobStatus='R') \ ORDER BY ${sortfield} ${sortorder};" \ | ${dbbin} -u ${dbuser} -p${dbpass} ${db} -s -N ) ;; * ) echo "dbtype of '${dbtype}' is invalid. Please set dbtype variable to 'mysql', 'pgsql', or 'mariadb'" exit 1 ;; esac # If we have no jobs to report on, then # we need to skip the entire awk script # and some bash stuff and jump all the # way to about line 673 # ------------------------------------- if [ -z "${queryresult}" ]; then results="0" else results="1" # Now for some fun with awk # ------------------------- IFS=" " msg=$(echo ${queryresult} | \ LC_ALL=en_US.UTF-8 \ awk \ -v html="${html}" \ -v boldstatus="${boldstatus}" \ -v colorstatusbg="${colorstatusbg}" \ -v jobtableheadercolor="${jobtableheadercolor}" \ -v jobtablejobcolor="${jobtablejobcolor}" \ -v runningjobcolor="${runningjobcolor}" \ -v goodjobcolor="${goodjobcolor}" \ -v goodjobwitherrcolor="${goodjobwitherrcolor}" \ -v warnjobcolor="${warnjobcolor}" \ -v badjobcolor="${badjobcolor}" \ -v printsummary="${printsummary}" \ -v starbadjobids="${starbadjobids}" \ 'BEGIN { awkerr = 0 } {star = " " } # List of possible jobstatus codes # -------------------------------- # Enter SQL query: SELECT * FROM status; # +-----------+---------------------------------+----------+ # | jobstatus | jobstatuslong | severity | # +-----------+---------------------------------+----------+ # | C | Created, not yet running | 15 | # | R | Running | 15 | # | B | Blocked | 15 | # | T | Completed successfully | 10 | # | E | Terminated with errors | 25 | # | e | Non-fatal error | 20 | # | f | Fatal error | 100 | # | D | Verify found differences | 15 | # | A | Canceled by user | 90 | # | F | Waiting for Client | 15 | # | S | Waiting for Storage daemon | 15 | # | m | Waiting for new media | | # | M | Waiting for media mount | 15 | # | s | Waiting for storage resource | 15 | # | j | Waiting for job resource | 15 | # | c | Waiting for client resource | 15 | # | d | Waiting on maximum jobs | 15 | # | t | Waiting on start time | 15 | # | p | Waiting on higher priority jobs | 15 | # | a | SD despooling attributes | 15 | # | i | Doing batch insert file records | 15 | # | I | Incomplete Job | 25 | # +-----------+---------------------------------+----------+ # Is this job still running? # If a job is still running, then there will be no "Stop Time" # fields, so $9 (jobstatus) will be shifted left two columns # to $7, and we will need to test and then reassign these variables # Note, this seems to be required for PostgreSQL, but MariaDB and # MySQL return all zeros for the date and time for running jobs # ----------------------------------------------------------------- { if ($7 == "R" && $8 ~ /^[0-9]+/) { $13 = $10 $11 = $9 $10 = $8 $9 = $7 $8 = $6 $7 = $5 $5 = "--=Still Running=--" $6 = "" } } # Assign words to job status code characters # ------------------------------------------ # First, check to see if we need to generate an HTML email { if (html == "yes") { # Set default opening and closing tags for status cell # ---------------------------------------------------- tdo = "" tdc = "" # Check to see if the job is "OK" then assign # the "goodjobcolor" to the cell background # ------------------------------------------- if ($9 ~ /[T]/ && $13 == 0) { if (colorstatusbg == "yes") # Assign jobs that are OK or Running the goodjobcolor # --------------------------------------------------- { tdo = "" } # Should the status be bolded? # ---------------------------- if (boldstatus == "yes") { tdo=tdo"" tdc=""tdc } status["T"]=tdo"-OK-"tdc # If it is a good job, but with errors or warnings # then we will assign the warnjobcolor # ------------------------------------------------ } else if ($9 == "T" && $13 != 0) { if (colorstatusbg == "yes") # Assign OK jobs with errors the warnjobcolor # ------------------------------------------- { tdo = "" } # Should the status be bolded? # ---------------------------- if (boldstatus == "yes") { tdo=tdo"" tdc=""tdc } # Since the "W" jobstatus never appears in the DB, we manually # assign it here so it can be recognized later on in the script # ------------------------------------------------------------- $9 = "W" status["W"]=tdo"OK/Warnings"tdc # If the job is still running we will # assign it the runningjobcolor # ----------------------------------- } else if ($9 == "R") { if (colorstatusbg == "yes") # Assign running jobs the runningjobcolor # --------------------------------------- { tdo = "" } # Should the status be bolded? # ---------------------------- if (boldstatus == "yes") { tdo=tdo"" tdc=""tdc } status["R"]=tdo"Running"tdc # If it is a bad job, then # we assign the badjobcolor # ------------------------- } else if ($9 ~ /[ABDef]/) { if (colorstatusbg == "yes") # Assign bad jobs the badjobcolor # ------------------------------- { tdo = "" } # Should the status be bolded? # ---------------------------- if (boldstatus == "yes") { tdo=tdo"" tdc=""tdc } status["A"]=tdo"Aborted"tdc status["D"]=tdo"Verify Diffs"tdc status["f"]=tdo"Failed"tdc # If it is a job with warnings or errors, assign the job the warnjobcolor # I have never seen a "W" status in the db. Jobs that are "OK -- with warnings" # still have a "T" jobstatus, but the joberrors field is incremented in the db # ----------------------------------------------------------------------------- } else if ($9 ~ /[EI]/) { if (colorstatusbg == "yes") # Assign job the warnjobcolor # --------------------------- { tdo = "" } # Should the status be bolded? # ---------------------------- if (boldstatus == "yes") { tdo=tdo"" tdc=""tdc } status["E"]=tdo"OK, w/Errors"tdc status["I"]=tdo"Incomplete"tdc } } else # $html is not "yes" so statuses will be normal text # -------------------------------------------------- { status["A"]=" Aborted " status["D"]=" Verify Diffs " status["E"]=" OK, w/Errors " status["f"]=" Failed " status["I"]=" Incomplete " status["R"]=" Running " status["T"]=" -OK- " # Since the "W" jobstatus never appears in the DB, we manually # assign it here so it can be recognized later on in the script # ------------------------------------------------------------- if ($9 == "T" && $13 != 0) { $9 = "W" status["W"]=" OK/Warnings " } } } # These status characters seem to only # be Director "in memory" statuses. They # do not get entered into the DB ever so we # cannot catch them with the db query we use # I might have to query the DIR as well as # the DB to be able to capture these # ------------------------------------------ { status["C"]=" Created " status["B"]=" Blocked " status["F"]=" Wait FD " status["S"]=" Wait SD " status["m"]=" Wait New Media" status["M"]=" Wait Mount " status["s"]=" Wait Storage" status["j"]=" Wait Job " status["c"]=" Wait Client " status["d"]=" Wait Max Jobs" status["t"]="Wait Start Time" status["p"]=" Wait Priority" status["a"]=" Despool Attrs" status["i"]=" Batch Insert " status["L"]="Spool Last Data" } # Assign words to job type code characters # ---------------------------------------- { jobtype["D"]="Admin" jobtype["B"]="Backup" jobtype["C"]="Copy" jobtype["c"]="Control" jobtype["R"]="Restore" jobtype["V"]="Verify" } # Assign words to job level code characters # ----------------------------------------- { level["F"]="Full" level["I"]="Incr" level["D"]="Diff" level["f"]="VFul" level["-"]="----" } # Assign words to Verify job level code characters # ------------------------------------------------ { level["A"]="VVol" level["C"]="VCat" level["V"]="Init" level["O"]="VV2C" level["d"]="VD2C" } # Check to see if the job did not "T"erminate OK then increment $awkerr, # and prepend the JobId with an asterisk for quick visual identification # of problem jobs. # Need to choose between a positive or negative test of the job status code # ------------------------------------------------------------------------- # Negative check - testing for non existence of all "good" status codes # $9 !~ /[TRCFSMmsjcdtpai]/ { awkerr++; $1 = "* "$1 } # Positive check - testing the existence of all "bad" status codes # good { if ($9 ~ /[ABDEIWef]/ || $13 != 0) { awkerr++; if (starbadjobids == "yes") { star = "*" } } } { if ($9 ~ /[ABDEIef]/) { awkerr++; if (starbadjobids == "yes") { star = "*" } } } # If the job is an Admin, Copy, Control, # Restore, or Migration job it will have # no real "Level", so we set it to "----" # --------------------------------------- { if ($7 ~ /[CcDRm]/) { $8 = "-" } } # Print out each job, formatted with the following fields: # JobId Name Status Errors Type Level Files Bytes StartTime EndTime RunTime # ------------------------------------------------------------------------- { if (html == "yes") { printf(" \ %s%s%s \ %s \ %s \ %'"'"'d \ %s \ %s \ %'"'"'d \ %'"'"'9.2f GB \ %s %s \ %s %s \ %s \ \n", \ jobtablejobcolor, star, $1, star, $2, status[$9], $13, jobtype[$7], level[$8], $10, $11/(1024*1024*1024), $3, $4, $5, $6, $12); } else { printf("%s %-7s %-14s %16s %'"'"'12d %8s %6s %'"'"'9d %'"'"'9.2f GB %11s %-9s %-10s %-9s %-9s\n", \ star, $1, $2, status[$9], $13, jobtype[$7], level[$8], $10, $11/(1024*1024*1024), $3, $4, $5, $6, $12); } } # Count the number of jobs # ------------------------ { totaljobs++ } # Count the number of files and bytes from all jobs # ------------------------------------------------- { files += $10 } { bytes += $11 } # Finally, print out the summaries # -------------------------------- END { if (printsummary == "yes") { if (html == "yes") { printf("") printf("
\
\ \ \ \ \
Total Jobs: %'"'"'15d
Total Files: %'"'"'15d
Total Bytes: %'"'"'15.2f GB
\
",\ totaljobs, files, bytes/(1024*1024*1024)); } else printf("\ =================================\n\ Total Jobs : %'"'"'15d\n\ Total Files : %'"'"'15d\n\ Total Bytes : %'"'"'15.2f GB\n\ =================================\n",\ totaljobs, files, bytes/(1024*1024*1024)); } exit awkerr } ') # Any failed jobs, or jobs with errors? # ------------------------------------- numbadjobs=$? # Do we email the job summaries? # ------------------------------ if [ ${emailsummaries} == "yes" ]; then # Get all of the jobids from the query results, but # skip any running jobs because they will not have # a summary in the DB until the job has terminated # ------------------------------------------------- alljobids=$(echo "${queryresult}" \ | awk '{ if ($7 != "R") printf("%s ", $1) }') # If no jobids were returned, skip creating # the header and looping through zero records # ------------------------------------------- if [ ! -z "${alljobids}" ]; then # Generate the header # ------------------- msg="${msg}"$( if [ ${html} == "yes" ]; then echo "
====================================="
                                else
                                        echo -e "\n\n\n====================================="
                fi
                        echo "Job Summaries of All Terminated Jobs:"
                        echo "====================================="
                )


                # Get the job logs from all jobs and just grep for the summary
                # ------------------------------------------------------------
                for jobid in ${alljobids}; do
                        msg="${msg}"$(
                                echo -e "\n--------------"
                                echo "JobId: ${jobid}"
                                echo "--------------"
                                echo "llist joblog jobid=${jobid}" | ${bcbin} -c ${bcconfig} | grep -A31 "^  Build OS:"
                                echo "======================================================================"
                        )
                done
                if [ ${html} == "yes" ]; then
                        msg=${msg}$(echo "
") fi fi fi # Do we email the bad job logs with the report? # --------------------------------------------- if [ ${emailbadlogs} == "yes" ]; then # Get the badjobs, or the good jobs with # JobErrors != 0 from the query results # -------------------------------------- badjobids=$(echo "${queryresult}" \ | awk '{ if ($9 ~ /[ABDEIef]/ || ($9 == "T" && $13 != 0)) printf("%s ", $1) }') # If no jobids were returned, skip creating # the header and looping through zero records # ------------------------------------------- if [ ! -z "${badjobids}" ]; then # Generate the header # ------------------- msg="${msg}"$( if [ ${html} == "yes" ]; then echo "
=========================================================="
                                else
                                        echo -e "\n\n\n=========================================================="
                fi
                        echo "Job logs of failed jobs, or good jobs with JobErrors != 0:"
                        echo "=========================================================="
                )


                # Get the bad job's log from the Director via bconsole
                # ----------------------------------------------------
                for jobid in ${badjobids}; do
                        msg="${msg}"$(
                                echo -e "\n--------------"
                                echo "JobId: ${jobid}"
                                echo "--------------"
                                echo "llist joblog jobid=${jobid}" | ${bcbin} -c ${bcconfig}
                                echo "======================================================================"
                        )
                done
                if [ ${html} == "yes" ]; then
                        msg=${msg}$(echo "
") fi fi fi # Prepend the header to the $msg output # ------------------------------------- if [ ${html} == "yes" ]; then msg="

${emailtitle}

${msg} " else msg=" ${emailtitle} ------------------------------------------ JobId Job Name Status Errors Type Level Files Bytes Start Time End Time Run Time ----- -------------- --------------- ---------- ------- ----- -------- ----------- ------------------- ------------------- -------- ${msg}" fi fi # If there were zero results returned from the # SQL the query, we skip the entire awk script, # and a lot of other bash stuff that generates # the email body and we end up here # ------------------------------------------------- if [ ${results} -eq 0 ]; then status="No Jobs Have Been Run" subjecticon="${nojobsicon}" msg="Nothing to see here..." else # Totally unnecessary, but, well... OCD... :) # -------------------------------------------- if [ ${numbadjobs} -ne 0 ]; then if [ ${numbadjobs} -eq 1 ]; then job="Job" else job="Jobs" fi status="(${numbadjobs}) ${job} with Errors" subjecticon="${badjobsicon}" else status="All Jobs OK" subjecticon="${goodjobsicon}" fi fi # More silliness # -------------- if [ ${hist} -eq 1 ]; then hour="Hour" else hour="Hours" fi # Email the report # ---------------- ( echo "To: ${admin}" echo "From: ${admin}" if [ ${addsubjecticon} == "yes" ]; then echo "Subject: ${subjecticon} ${server} - ${status} in the Past ${hist} ${hour}" else echo "Subject: ${server} - ${status} in the Past ${hist} ${hour}" fi if [ ${html} == "yes" ] && [ ${results} -ne 0 ]; then echo "Content-Type: text/html" echo "MIME-Version: 1.0" fi echo "" echo "${msg}" ) | /usr/sbin/sendmail -t # ------------- # End of script # ------------- # ---------- # Change Log # ---------- # ---------------------------- # William A. Arlofski # Reverse Polarity, LLC # helpdesk@revpol.com # http://www.revpol.com/bacula # ---------------------------- # # # 20130428 - Initial release # Generate and email a basic Bacula backup report # 1st command line parameter is expected to be a # number of hours. No real error checking is done # # 20131224 - Removed "AND JobStatus='T'" to get all backup jobs # whether running, or completed with errors etc. # - Added Several fields "StartTime", "EndTime", # "JobFiles" # - Removed "JobType" because we are only selecting # jobs of type "Backup" (AND Type='B') # - Modified header lines and printf lines for better # formatting # # 20140107 - Modified script to include more information and cleaned # up the output formatting # # 20150704 - Added ability to work with MySQL or Postgresql # # 20150723 - Modified query, removed "Type='B'" clause to catch all jobs, # including Copy jobs, Admin jobs etc. Modified header, and # output string to match new query and include job's "Type" # column. # # 20170225 - Rewrote awk script so that a status/summary could be set in # the email report's subject. eg: # Subject: "serverName - All Jobs OK in the past x hours" # Subject: "serverName - x Jobs FAILED in the past y hours" # # 20170303 - Fixed output in cases where there are jobs running and there # is no "Stop Time" for a job. # # 20170406 - Some major modifications: # - Added feature to spell out words instead of using the # single character codes for Job type, Job Status, and # Job Level - Including the different levels for Verify # jobs # - If a job terminates with an error or warning, then the # job's line in the output is prepended with an asterisk # "*" for quick visual identification # - Modified the outputs of the files and bytes fields to # include commas when the number is > 999 # - Added totals to the end of the report for Jobs, Files, # and Bytes # - Added $sortfield and $sortorder variables to allow output # to be sorted as desired # - Set the level of a job to "----" when the level is not # applicable as in Restore jobs, Admin jobs etc. # # 20170408 - Some minor cleanup, and moving things around # - Added $emailsummaries variable to append the job summaries # to the end of the report. # - Added $emailbadlogs variable to append full joblogs of jobs # which have failed or jobs with errors to the end of the report # for quick access to investigate failed jobs. # # 20170417 - Added some tests for binaries and the bconsole config file # # 20170429 - Thanks to Chris Couture for contacting me and submitting a # working query for MariaDB. I have added 'mariadb' as a new # dbtype option. # - Thanks to Chris Couture for the ideas and some code examples # to create an HTML email. # - Added $html variable to enable HTML emails. # - Added $boldstatus variable to make the Status bold # in HTML emails. # - Added $colorstatusbg variable to color the background of # the Status cell in HTML emails. # - Thanks to Chris Couture for the idea of adding RunTime # to the email output. # - Thanks to Chris Couture for the idea of using some unicode # characters (a 'checkmark'or a bold 'x') in the Subject: # to quickly see if everything ran OK. # - Added $addsubjecticon variable to enable/disable the # prepending of this icon to the Subject. # - Added $printsumary variable to give the option to print the # total Jobs, Files, and Bytes after the job listing table. # - Added $starbadjobids variable to enable/disable prepending # the bad jobids with an asterisk "*". # - Modified the way the email is built at the end. Thanks to # Chris Courture again for this nice idea. # - Added $jobtableheadercolor, $jobtablejobcolor, $goodjobcolor, # $goodjobwitherrcolor, $runningjobcolor, $warnjobcolor, and # $badjobcolor variables to colorize HTML emails # - Added $emailtitle variable for the title at the top # - Added $fontfamily, $fontsize, $fontsizejobinfo, and $fontsizesumlog # variables to allow styling of the HTML output (Thanks again Chris) # - Added $nojobsicon, $goodjobsicon, and $badjobsicon variables to # allow setting the prepended utf-8 subject icon character # - Reformatted things so that if there are no jobs returned by the # SQL query, the email message sent is nice and short # - Modified the license to allow for inclusion into Bacula Community, # and possibly the Enterprise Edition releases # # 20170430 - Modified the order of the fields to make more sense # - Re-aligned the text email so that when an asterisk is pre-pended it # does not shift the whole line # # 20170508 - Re-worked some of the logic so that good jobs (JobStatus="T") which # have errors will have their status listed as "OK/Warnings", and it # will not trigger as a "bad job" on the JobErrors, so it will not # have an asterisk prepended to the JobId in the job listing. I think # this fix is more of a temporary change in the hopes that a "W" # status to represent "good jobs with warnings" is implemented in the # db in the future. # - Added an "Errors" column to the table to show "JobErrors" from the # db. # - Some minor variable name changes and other minor changes # # 20170511 - Minor adjustments to the alignment formatting of the text email # - Minor 'case' changes to a couple levels (Init & VCat) # # ------------------------------------------------------------------------------ # I like small tabs. Use :set list in vim to see tabbing etc # vim: set tabstop=2:softtabstop=2:shiftwidth=2 #
Job ID Job Name Status Errors Type Level Files Bytes Start Time End Time Run Time