rvm 1.08

reporter.cc

Go to the documentation of this file.
00001 #include "config.h"
00002 
00003 #include <iostream>
00004 #include <string>
00005 #include <vector>
00006 #include <algorithm>
00007 
00008 #include "asserts.h"
00009 #include "error.h"
00010 #include "estring.h"
00011 #include "fs.h"
00012 #include "rconfig.h"
00013 #include "timer.h"
00014 #include "logger.h"
00015 #include "estat.h"
00016 #include "vaulter.h"
00017 #include "strfmt.h"
00018 #include "archiver.h"
00019 #include "table.h"
00020 
00021 #include "reporter.h"
00022 
00023 //-----------------------------------------------------------------------------
00024 
00025 /** C'tor */
00026 vault_stats_report::vault_stats_report()
00027 {
00028         clear();
00029 }
00030 
00031 /** C'tor */
00032 vault_stats_report::vault_stats_report(const vault_stats_report& a_class)
00033 {
00034         clear();
00035         assign(a_class);
00036 }
00037 
00038 /** C'tor */
00039 vault_stats_report::vault_stats_report(
00040         const std::string& a_message,
00041         const filesystem& a_class
00042         )
00043 {
00044         clear();
00045         assign(a_message,a_class);
00046 }
00047 
00048 /** D'tor */
00049 vault_stats_report::~vault_stats_report()
00050 {
00051 }
00052 
00053 /** Clear all values */
00054 void vault_stats_report::clear(void)
00055 {
00056         m_total_blocks = 0;
00057         m_free_blocks = 0;
00058         m_total_inodes = 0;
00059         m_free_inodes = 0;
00060 }
00061 
00062 /** Assignment */
00063 void vault_stats_report::assign(
00064         const vault_stats_report& a_class
00065         )
00066 {
00067         assign(
00068                 a_class.message(),
00069                 a_class.time(),
00070                 a_class.total_blocks(),
00071                 a_class.free_blocks(),
00072                 a_class.total_inodes(),
00073                 a_class.free_inodes()
00074                 );
00075 }
00076 
00077 /** Assignment */
00078 void vault_stats_report::assign(
00079         const std::string& a_message,
00080         const filesystem& a_class
00081         )
00082 {
00083         assign(
00084                 a_message,
00085                 current_time(),
00086                 a_class.total_blocks(),
00087                 a_class.free_blocks(),
00088                 a_class.total_inodes(),
00089                 a_class.free_inodes()
00090                 );
00091 }
00092 
00093 /** Assignment */
00094 void vault_stats_report::assign(
00095         const std::string& a_message,
00096         const std::string& a_time,
00097         const uint64 a_total_blocks,
00098         const uint64 a_free_blocks,
00099         const uint64 a_total_inodes,
00100         const uint64 a_free_inodes
00101         )
00102 {
00103         TRY_nomem(m_message = a_message);
00104         m_total_blocks = a_total_blocks;
00105         m_free_blocks = a_free_blocks;
00106         m_total_inodes = a_total_inodes;
00107         m_free_inodes = a_free_inodes;
00108 
00109         TRY_nomem(m_time = a_time);
00110 }
00111 
00112 /** Return a string timestamp */
00113 const std::string& vault_stats_report::time(void) const
00114 {
00115         return(m_time);
00116 }
00117 
00118 /** Return the message */
00119 const std::string& vault_stats_report::message(void) const
00120 {
00121         return(m_message);
00122 }
00123 
00124 /** Return the total number of blocks in the vault */
00125 const uint64 vault_stats_report::total_blocks(void) const
00126 {
00127         return(m_total_blocks);
00128 }
00129 
00130 /** Return the number of free blocks in the vault */
00131 const uint64 vault_stats_report::free_blocks(void) const
00132 {
00133         return(m_free_blocks);
00134 }
00135 
00136 /** Return the total number of inodes in the vault */
00137 const uint64 vault_stats_report::total_inodes(void) const
00138 {
00139         return(m_total_inodes);
00140 }
00141 
00142 /** Return the number of free inodes in the vault */
00143 const uint64 vault_stats_report::free_inodes(void) const
00144 {
00145         return(m_free_inodes);
00146 }
00147 
00148 /** Assignment operator */
00149 vault_stats_report& 
00150 vault_stats_report::operator=(const vault_stats_report& a_class)
00151 {
00152         assign(a_class);
00153         return(*this);
00154 }
00155 
00156 //-----------------------------------------------------------------------------
00157 
00158 /** C'tor */
00159 vault_report::vault_report()
00160 {
00161         clear();
00162 }
00163 
00164 /** D'tor */
00165 vault_report::~vault_report()
00166 {
00167 }
00168 
00169 /** Clear all values */
00170 void vault_report::clear(void)
00171 {
00172         m_reports.clear();
00173 }
00174 
00175 /** Add a vault report to the list */
00176 void vault_report::add_report(
00177         const vault_stats_report& a_class
00178         )
00179 {
00180         TRY_nomem(m_reports.push_back(a_class));
00181 }
00182 
00183 /** Format and print the vault report to the given stream */
00184 void vault_report::write_report(std::ostream& out)
00185 {
00186         table tab, tab2;
00187         estring estr;
00188         std::vector<vault_stats_report>::const_iterator vi;
00189         uint64 ui64b, ui64e, ui64t;
00190 
00191         estr = "Vault Statistics";
00192         estr.align(estring::center);
00193         tab << estr << table_endl;
00194 
00195         estr = "";
00196         estr.fillchar('-');
00197         estr.align(estring::left);
00198         tab << estr << table_endl;
00199 
00200         // Header
00201         tab2
00202                 << "Time"
00203                 << " "
00204                 << "Message"
00205                 << " "
00206                 << "Free Blocks"
00207                 << " "
00208                 << "Free Inodes"
00209                 << " "
00210                 << table_endl;
00211         
00212         // Separators
00213         estr.align(estring::left);
00214         estr.fillchar('-');
00215         estr = "";
00216         tab2
00217                 << estr
00218                 << " "
00219                 << estr
00220                 << " "
00221                 << estr
00222                 << " "
00223                 << estr
00224                 << table_endl;
00225 
00226         // Vault messages/statistics
00227         estr.fillchar(' ');
00228         for (vi = m_reports.begin(); vi != m_reports.end(); ++vi) {
00229                 tab2
00230                         << vi->time()
00231                         << " ";
00232 
00233                 estr.align(estring::right);
00234                 estr = vi->message();
00235                 tab2 << estr;
00236 
00237                 tab2 << " ";
00238 
00239                 estr.align(estring::center);
00240 
00241                 estr = "  ";
00242                 estr += percent_string(vi->free_blocks(), vi->total_blocks());
00243                 tab2 << estr;
00244 
00245                 tab2 << " ";
00246 
00247                 estr = "  ";
00248                 estr += percent_string(vi->free_inodes(), vi->total_inodes());
00249                 tab2 << estr;
00250 
00251                 tab2 << table_endl;
00252         }
00253 
00254         // Separators
00255         estr.align(estring::left);
00256         estr.fillchar('-');
00257         estr = "";
00258         tab2
00259                 << " "
00260                 << " "
00261                 << " "
00262                 << " "
00263                 << estr
00264                 << " "
00265                 << estr
00266                 << table_endl;
00267         
00268         // Final
00269         estr.align(estring::right);
00270         estr.fillchar(' ');
00271         estr = "Total Difference:";
00272         // estr.align(estring::center);
00273         // estr.fillchar(' ');
00274         tab2
00275                 << " "
00276                 << " "
00277                 << estr
00278                 << " ";
00279         
00280         estr.align(estring::center);
00281         ASSERT(m_reports.size() > 0);
00282         ui64b = m_reports[0].free_blocks();
00283         ui64e = m_reports[m_reports.size()-1].free_blocks();
00284         ui64t = m_reports[0].total_blocks();
00285         if (ui64b > ui64e) {
00286                 estr = "-";
00287                 estr += percent_string(ui64b - ui64e, ui64t);
00288         }
00289         else {
00290                 estr = "+";
00291                 estr += percent_string(ui64e - ui64b, ui64t);
00292         }
00293         tab2 << estr;
00294 
00295         tab2 << " ";
00296 
00297         ui64b = m_reports[0].free_inodes();
00298         ui64e = m_reports[m_reports.size()-1].free_inodes();
00299         ui64t = m_reports[0].total_inodes();
00300         if (ui64b > ui64e) {
00301                 estr = "-";
00302                 estr += percent_string(ui64b - ui64e, ui64t);
00303         }
00304         else {
00305                 estr = "+";
00306                 estr += percent_string(ui64e - ui64b, ui64t);
00307         }
00308         tab2 << estr;
00309 
00310         tab2 << table_endl;
00311 
00312         tab << tab2;
00313 
00314         out << tab;
00315 }
00316 
00317 /** Generate a synopsis report */
00318 void vault_report::format_synopsis(table& a_table)
00319 {
00320         estring estr;
00321 
00322         estr.align(estring::right);
00323         estr = "Timestamp:";
00324         a_table << estr << " " << config.timestamp().str() << table_endl;
00325 
00326         estr = "Vault Selected:";
00327         a_table << estr << " " << vaulter.vault() << table_endl;
00328 }
00329 
00330 //-----------------------------------------------------------------------------
00331 
00332 /** C'tor */
00333 job_path_report::job_path_report()
00334 {
00335         clear();
00336 }
00337 
00338 /** C'tor */
00339 job_path_report::job_path_report(const job_path_report& a_class)
00340 {
00341         clear();
00342         assign(a_class);
00343 }
00344 
00345 /** C'tor */
00346 job_path_report::job_path_report(
00347         const std::string a_source,
00348         const timer a_time,
00349         const uint16 a_exit_code,
00350         const uint16 a_signal_num,
00351         const rsync_behavior::value_type a_behavior,
00352         const std::string a_error_message
00353         )
00354 {
00355         clear();
00356         assign(
00357                 a_source,
00358                 a_time,
00359                 a_exit_code,
00360                 a_signal_num,
00361                 a_behavior,
00362                 a_error_message
00363                 );
00364 }
00365 
00366 /** D'tor */
00367 job_path_report::~job_path_report()
00368 {
00369 }
00370 
00371 /** Clear all values */
00372 void job_path_report::clear(void)
00373 {
00374         m_source.erase();
00375         m_time.clear();
00376         m_exit_code = 0;
00377         m_signal_num = 0;
00378         m_error_msg.erase();
00379         m_behavior = rsync_behavior::retry;
00380 }
00381 
00382 /** Assignment */
00383 void job_path_report::assign(const job_path_report& a_class)
00384 {
00385         assign(
00386                 a_class.m_source, 
00387                 a_class.m_time,
00388                 a_class.m_exit_code,
00389                 a_class.m_signal_num,
00390                 a_class.m_behavior,
00391                 a_class.m_error_msg
00392                 );
00393 }
00394 
00395 /** Assignment */
00396 void job_path_report::assign(
00397         const std::string a_source,
00398         const timer a_time,
00399         const uint16 a_exit_code,
00400         const uint16 a_signal_num,
00401         const rsync_behavior::value_type a_behavior,
00402         const std::string a_error_message
00403         )
00404 {
00405         TRY_nomem(m_source = a_source);
00406         TRY_nomem(m_error_msg = a_error_message);
00407         TRY_nomem(m_time = a_time);
00408         m_exit_code = a_exit_code;
00409         m_signal_num = a_signal_num;
00410         m_behavior = a_behavior;
00411 }
00412 
00413 /** Return true if rsync succeeded archiving this path */
00414 const bool job_path_report::status(void) const
00415 {
00416 // std::cerr << "[DEBUG]: job_path_report::status()" << std::endl;
00417 // std::cerr << "[DEBUG]:   m_source = " << m_source << std::endl;
00418 // std::cerr << "[DEBUG]:   m_exit_code = " << m_exit_code << std::endl;
00419 // std::cerr << "[DEBUG]:   m_signal_num = " << m_signal_num << std::endl;
00420 // std::cerr << "[DEBUG]:   m_error_msg = " << m_error_msg << std::endl;
00421 // std::cerr << "[DEBUG]:   m_behavior = " << m_behavior << std::endl;
00422 // std::cerr << "[DEBUG]:   rsync_behavior::ok = " << rsync_behavior::ok << std::endl;
00423         if (
00424                 /*
00425                 ((m_exit_code == 0) && (m_signal_num == 0))
00426                 || (m_behavior == rsync_behavior::ok)
00427                 */
00428                 ((m_exit_code == 0) || (m_behavior == rsync_behavior::ok))
00429                 && (m_signal_num == 0)
00430                 ) {
00431 // std::cerr << "[DEBUG]:   job_path_report::status() = true" << std::endl;
00432                 return(true);
00433         }
00434 // std::cerr << "[DEBUG]:   job_path_report::status() = false" << std::endl;
00435         return(false);
00436 }
00437 
00438 /** Set the path archived for this report */
00439 void job_path_report::source(const std::string& a_class)
00440 {
00441         TRY_nomem(m_source = a_class);
00442 }
00443 
00444 /** Return a string of the path archived */
00445 const std::string& job_path_report::source(void) const
00446 {
00447         return(m_source);
00448 }
00449 
00450 /** Set the timer values for this report */
00451 void job_path_report::time(const timer& a_class)
00452 {
00453         TRY_nomem(m_time = a_class);
00454 }
00455 
00456 /** Return the timer object for this report */
00457 const timer& job_path_report::time(void) const
00458 {
00459         return(m_time);
00460 }
00461 
00462 /** Set rsync's return exit code when archiving this path */
00463 void job_path_report::exit_code(const int a_exit_code)
00464 {
00465         m_exit_code = a_exit_code;
00466 }
00467 
00468 /** Return rsync's exit code */
00469 const int job_path_report::exit_code(void) const
00470 {
00471         return(m_exit_code);
00472 }
00473 
00474 /** Set rsync's signal number from archiving this path */
00475 void job_path_report::signal_num(const int a_signal_num)
00476 {
00477         m_signal_num = a_signal_num;
00478 }
00479 
00480 /** Return rsync's signal number */
00481 const int job_path_report::signal_num(void) const
00482 {
00483         return(m_signal_num);
00484 }
00485 
00486 /** Set a descriptive error message for this report */
00487 void job_path_report::error_msg(const std::string& a_class)
00488 {
00489         TRY_nomem(m_error_msg = a_class);
00490 }
00491 
00492 /** Return the error message */
00493 const std::string& job_path_report::error_msg(void) const
00494 {
00495         return(m_error_msg);
00496 }
00497 
00498 /** Assignment operator */
00499 job_path_report& job_path_report::operator=(const job_path_report& a_class)
00500 {
00501         assign(a_class);
00502         return(*this);
00503 }
00504 
00505 //-----------------------------------------------------------------------------
00506 
00507 /** Report type tags */
00508 const char *reportio::tags[] = {
00509         "[RSYNC]: ",
00510         "[REPORT]: ",
00511         0
00512 };
00513 
00514 /** Write a report line for output from rsync to parent on child's std::cout 
00515  */
00516 void reportio::write_rsync_out(const std::string& a_str)
00517 {
00518         std::cout.flush();
00519         std::cout << tags[rsync] << a_str << std::endl;
00520         std::cout.flush();
00521 }
00522 
00523 /** Write a report line for output from rsync to parent on child's std::cerr
00524  */
00525 void reportio::write_rsync_err(const std::string& a_str)
00526 {
00527         std::cerr.flush();
00528         std::cerr << tags[rsync] << a_str << std::endl;
00529         std::cerr.flush();
00530 }
00531 
00532 /** Generate and submit a report to the parent process on child's std::cout
00533  */
00534 void reportio::write_report(
00535                 const std::string a_source,
00536                 const timer& a_timer,
00537                 const int a_exit_code,
00538                 const int a_signal_num,
00539                 const rsync_behavior::value_type& a_behavior,
00540                 const std::string& a_error_msg
00541         )
00542 {
00543         estring str;
00544 
00545         str += estring(a_source.size());
00546         str += " ";
00547         str += a_source;
00548         str += " ";
00549         str += estring(static_cast<uint64>(a_timer.start_value()));
00550         str += " ";
00551         str += estring(static_cast<uint64>(a_timer.stop_value()));
00552         str += " ";
00553         str += estring(a_exit_code);
00554         str += " ";
00555         str += estring(a_signal_num);
00556         str += " ";
00557         str += estring(static_cast<uint64>(a_behavior));
00558         str += " ";
00559         str += estring(a_error_msg.size());
00560         str += " ";
00561         str += a_error_msg;
00562         str += " ";
00563 
00564         std::cout.flush();
00565         std::cout << tags[report] << str << std::endl;
00566         std::cout.flush();
00567 }
00568 
00569 /** Parse a received report from a child process and return a job_path_report
00570  */
00571 job_path_report reportio::parse(const std::string& a_str)
00572 {
00573         estring es;
00574         job_path_report jpr;
00575         estring estr;
00576         estring::size_type idx;
00577         estring::size_type size;
00578         estring tmp;
00579         estring source;
00580         timer::value_type start_time;
00581         timer::value_type stop_time;
00582         int exit_code;
00583         int signal_num;
00584         estring error_msg;
00585         rsync_behavior::behavior_type behavior;
00586 
00587         TRY_nomem(estr = a_str);
00588         idx = estr.find(tags[report]);
00589         if (idx == std::string::npos) {
00590                 estring es;
00591 
00592                 es = "Invalid job report: \"";
00593                 es += a_str;
00594                 es += "\"";
00595 
00596                 throw(INTERNAL_ERROR(0,es));
00597         }
00598         
00599         // TODO: A lot of assumptions are being made here, put in some checking code
00600 
00601         estr.erase(0,idx+strlen(tags[report]));
00602 
00603         idx = estr.find(' ');
00604         tmp = estr.substr(0,idx);
00605         estr.erase(0,idx+1);
00606         size = tmp;
00607         source = estr.substr(0,size);
00608         estr.erase(0,size+1);
00609 
00610         idx = estr.find(' ');
00611         tmp = estr.substr(0,idx);
00612         estr.erase(0,idx+1);
00613         start_time = static_cast<uint64>(tmp);
00614 
00615         idx = estr.find(' ');
00616         tmp = estr.substr(0,idx);
00617         estr.erase(0,idx+1);
00618         stop_time = static_cast<uint64>(tmp);
00619 
00620         idx = estr.find(' ');
00621         tmp = estr.substr(0,idx);
00622         estr.erase(0,idx+1);
00623         exit_code = tmp;
00624 
00625         idx = estr.find(' ');
00626         tmp = estr.substr(0,idx);
00627         estr.erase(0,idx+1);
00628         signal_num = tmp;
00629 
00630         idx = estr.find(' ');
00631         tmp = estr.substr(0,idx);
00632         estr.erase(0,idx+1);
00633         behavior = 
00634                 static_cast<rsync_behavior::value_type>(
00635                         static_cast<uint64>(tmp)
00636                         );
00637 
00638         idx = estr.find(' ');
00639         tmp = estr.substr(0,idx);
00640         estr.erase(0,idx+1);
00641         size = tmp;
00642         error_msg = estr.substr(0,size);
00643         estr.erase(0,size+1);
00644 
00645         jpr.assign(
00646                 source,
00647                 timer(start_time,stop_time),
00648                 exit_code,
00649                 signal_num,
00650                 behavior,
00651                 error_msg
00652         );
00653 
00654         return(jpr);
00655 }
00656 
00657 /** Return true if the given string looks like a valid report */
00658 bool reportio::is_report(const std::string& a_class)
00659 {
00660         estring::size_type idx;
00661 
00662         idx = a_class.find(tags[report]);
00663         if (idx == std::string::npos) {
00664                 return(false);
00665         }
00666         return(true);
00667 }
00668 
00669 //-----------------------------------------------------------------------------
00670 
00671 /** C'tor */
00672 single_job_report::single_job_report()
00673 {
00674         clear();
00675 }
00676 
00677 /** D'tor */
00678 single_job_report::~single_job_report()
00679 {
00680 }
00681 
00682 /** Clear all values  */
00683 void single_job_report::clear(void)
00684 {
00685         m_reports.clear();
00686         m_id.erase();
00687 }
00688 
00689 /** Add a path report for this job */
00690 void single_job_report::add_report(const job_path_report& a_class)
00691 {
00692         TRY_nomem(m_reports.push_back(a_class));
00693 }
00694 
00695 /** Return a const vector of all path reports */
00696 const std::vector<job_path_report>& single_job_report::reports(void) const
00697 {
00698         return(m_reports);
00699 }
00700 
00701 /** Set a descriptive ID for this job report */
00702 void single_job_report::id(const std::string& a_str)
00703 {
00704         TRY_nomem(m_id = a_str);
00705 }
00706 
00707 /** Return the descriptive id for this job report */
00708 const std::string& single_job_report::id(void) const
00709 {
00710         return(m_id);
00711 }
00712 
00713 /** If all path reports say that rsync was successful, then return true, else
00714  * return false */
00715 const bool single_job_report::status(void) const
00716 {
00717         bool value = true;
00718         std::vector<job_path_report>::const_iterator jpri;
00719 
00720         for (jpri = m_reports.begin(); jpri != m_reports.end(); ++jpri) {
00721                 if (!jpri->status())
00722                         value = false;
00723         }
00724 
00725         return(value);
00726 }
00727 
00728 //-----------------------------------------------------------------------------
00729 
00730 /** C'tor */
00731 jobs_report::jobs_report()
00732 {
00733         clear();
00734 }
00735 
00736 /** D'tor */
00737 jobs_report::~jobs_report()
00738 {
00739 }
00740 
00741 /** Clear all values */
00742 void jobs_report::clear(void)
00743 {
00744         m_jobs.clear();
00745 }
00746 
00747 /** Add a job report to the list */
00748 void jobs_report::add_report(const single_job_report& a_class)
00749 {
00750         TRY_nomem(m_jobs.push_back(a_class));
00751 }
00752 
00753 /** Return a const vector of all job reports */
00754 const std::vector<single_job_report>& jobs_report::reports(void) const
00755 {
00756         return(m_jobs);
00757 }
00758 
00759 /** Format job reports and output to the given stream */
00760 void jobs_report::write_report(std::ostream& a_out)
00761 {
00762         std::vector<single_job_report>::const_iterator ji;
00763         std::vector<job_path_report>::const_iterator jpi;
00764         estring estr;
00765         estring estr2;
00766         estring hsep;
00767         estring vsep;
00768         estring vsep2;
00769 
00770         hsep.fillchar('-');
00771         vsep = " | ";
00772         vsep2 = "|";
00773         
00774         for (ji = m_jobs.begin(); ji != m_jobs.end(); ++ji) {
00775                 table t1, t2;
00776                 bool first_line = true;
00777 
00778                 if (ji != m_jobs.begin())
00779                         a_out << std::endl;
00780 
00781                 estr.align(estring::left);
00782                 estr = "Job: ";
00783                 estr += ji->id();
00784                 t1 << estr;
00785                 t1 << table_endl;
00786 
00787                 t1 << hsep;
00788                 t1 << table_endl;
00789 
00790                 t2 << "Job" << vsep << "Path" << " " << " " 
00791                         << table_endl;
00792                 t2 << "Status" << vsep << "Status" << " " << "Source" 
00793                         << table_endl;
00794                 t2 << hsep << vsep << hsep << " " << hsep << table_endl;
00795 
00796                 for (jpi = ji->reports().begin(); jpi != ji->reports().end(); ++jpi) {
00797                         if (jpi != ji->reports().begin())
00798                                 t2 << table_endl;
00799 
00800                         if (first_line) {
00801                                 if (ji->status())
00802                                         t2 << "OK";
00803                                 else
00804                                         t2 << "ERROR";
00805                                 first_line = false;
00806                         }
00807                         else {
00808                                 t2 << " " << vsep << " " << " " << table_endl << " ";
00809                         }
00810 
00811                         t2 << table_repeat << vsep;
00812 
00813                         if (jpi->status())
00814                                 t2 << "OK";
00815                         else
00816                                 t2 << "ERROR";
00817 
00818                         t2 << " ";
00819 
00820                         t2 << jpi->source();
00821 
00822                         t2 << table_endl;
00823 
00824                         t2 << " " << table_repeat << vsep << " " << " ";
00825 
00826                         table t3, t4;
00827 
00828                         t3 << "+" << hsep << hsep << table_endl;
00829                         t3 << table_repeat << vsep2 << " ";
00830 
00831                         estr.align(estring::right);
00832                         estr2.align(estring::right);
00833 
00834                         estr = "Start:";
00835                         estr2 = jpi->time().started_at();
00836                         estr2 += "  ";
00837                         t4 << " " << estr << " " << estr2 << table_endl;
00838 
00839                         estr = "Finish:";
00840                         estr2 = jpi->time().stopped_at();
00841                         estr2 += "  ";
00842                         t4 << " " << estr << " " << estr2 << table_endl;
00843 
00844                         estr = "Duration:";
00845                         estr2 = jpi->time().duration();
00846                         t4 << " " << estr << " " << estr2 << table_endl;
00847 
00848                         t3 << t4 << table_endl;
00849 
00850                         estr2.align(estring::left);
00851                         if (!jpi->status()) {
00852                                 table t5;
00853 
00854                                 t3 << vsep2 << " " << " " << table_endl;
00855                                 t3 << table_repeat << vsep2 << " ";
00856 
00857                                 estr = "Exit Code:";
00858                                 estr2 = estring(jpi->exit_code());
00859                                 if (jpi->exit_code() != 0) {
00860                                         estr2 += " ";
00861                                         estr2 += rsync_estat_str.exit(jpi->exit_code());
00862                                 }
00863                                 t5 << " " << estr << " " << estr2 << table_endl;
00864 
00865                                 estr = "Signal Num:";
00866                                 estr2 = estring(jpi->signal_num());
00867                                 if (jpi->signal_num() != 0) {
00868                                         estr2 += " ";
00869                                         estr2 += rsync_estat_str.signal(jpi->signal_num());
00870                                 }
00871                                 t5 << " " << estr << " " << estr2 << table_endl;
00872 
00873                                 if (jpi->error_msg().size() > 0) {
00874                                         estr = "Error Msg:";
00875                                         estr2 = jpi->error_msg();
00876                                         t5 << " " << estr << " " << estr2 << table_endl;
00877                                 }
00878 
00879                                 t3 << t5;
00880                         }
00881 
00882                         // TODO: File statistics should go here
00883 
00884                         t2 << t3;
00885                 }
00886 
00887                 t1 << t2;
00888 
00889                 a_out << t1;
00890         }
00891 }
00892 
00893 /** Generate a synopsis report */
00894 void jobs_report::format_synopsis(table& a_table)
00895 {
00896         estring estr, estr2;
00897         std::vector<single_job_report>::const_iterator sjri;
00898         uint16 jobs_good = 0;
00899         uint16 jobs_bad = 0;
00900         uint16 jobs_total = 0;
00901 
00902         estr.align(estring::right);
00903 
00904         for (sjri = m_jobs.begin(); sjri != m_jobs.end(); ++sjri) {
00905                 if (sjri->status())
00906                         ++jobs_good;
00907                 else
00908                         ++jobs_bad;
00909                 ++jobs_total;
00910         }
00911 
00912         estr = "Successful Jobs:";
00913         estr2 = estring(jobs_good);
00914         estr2 += " out of ";
00915         estr2 += estring(m_jobs.size());
00916         estr2 += " (";
00917         estr2 += percent_string(jobs_good, jobs_total);
00918         estr2 += ")";
00919 
00920         a_table << estr << " " << estr2 << table_endl;
00921 }
00922 
00923 //-----------------------------------------------------------------------------
00924 
00925 /** C'tor */
00926 report_manager::report_manager()
00927 {
00928         m_initialized = false;
00929 }
00930 
00931 /** D'tor */
00932 report_manager::~report_manager()
00933 {
00934 }
00935 
00936 /** Initialize */
00937 void report_manager::init(void)
00938 {
00939         if (!config.initialized()) {
00940                 throw(INTERNAL_ERROR(0,"Configuration manager is not initialized"));
00941         }
00942         m_initialized = true;
00943 }
00944 
00945 /** Return whether or not this object has been inintialized */
00946 const bool report_manager::initialized(void) const
00947 {
00948         return(m_initialized);
00949 }
00950 
00951 /** Clear all values */
00952 void report_manager::clear(void)
00953 {
00954         m_total_time.clear();
00955         m_vault.clear();
00956         m_jobs.clear();
00957 }
00958 
00959 /** Report the overall RVM time */
00960 void report_manager::set_total_time(const timer& a_class)
00961 {
00962         if (!initialized())
00963                 throw(INTERNAL_ERROR(0,"Report manager is not initialized"));
00964 
00965         m_total_time = a_class;
00966 }
00967 
00968 /** Return the vault reporter object */
00969 vault_report& report_manager::vault(void)
00970 {
00971         return(m_vault);
00972 }
00973 
00974 /** Return the jobs reporter object */
00975 jobs_report& report_manager::jobs(void)
00976 {
00977         return(m_jobs);
00978 }
00979 
00980 /** Print report to standard output */
00981 void report_manager::print_report(void)
00982 {
00983         estring lstr;
00984 
00985         if (!initialized())
00986                 throw(INTERNAL_ERROR(0,"Report manager is not initialized"));
00987 
00988         lstr = "Reporter - Printing report to stdout...\n";
00989         logger.write(lstr);
00990 
00991         write_report(std::cout);
00992 
00993         lstr = "Reporter - Done\n";
00994         logger.write(lstr);
00995 }
00996 
00997 /** Save report to a file */
00998 void report_manager::file_report(void)
00999 {
01000         std::ofstream out;
01001         std::string filename;
01002         std::string es;
01003         estring lstr;
01004         bool done = false;
01005         int count = 0;
01006 
01007         if (!initialized())
01008                 throw(INTERNAL_ERROR(0,"Report manager is not initialized"));
01009         
01010         while (!done) {
01011                 TRY_nomem(filename = config.log_dir());
01012                 TRY_nomem(filename += "/");
01013                 TRY_nomem(filename += config.timestamp().str());
01014                 TRY_nomem(filename += ".report");
01015                 if (count != 0) {
01016                         TRY_nomem(filename += ".");
01017                         TRY_nomem(filename += estring(count));
01018                 }
01019                 if (exists(filename))
01020                         ++count;
01021                 else
01022                         done = true;
01023         }
01024         out.open(filename.c_str());
01025         if (!out.is_open()) {
01026                 TRY_nomem(es = "Could not open report file: \"");
01027                 TRY_nomem(es += filename);
01028                 TRY_nomem(es += "\"");
01029                 throw(ERROR(errno,es));
01030         }
01031 
01032         lstr = "Reporter - Writing report to file...\n";
01033         logger.write(lstr);
01034         write_report(out);
01035 
01036         out.close();
01037 
01038         lstr = "Reporter - Done\n";
01039         logger.write(lstr);
01040 }
01041 
01042 /** Write report to the given stream */
01043 void report_manager::write_report(std::ostream& a_out)
01044 {
01045         estring estr;
01046         estring es;
01047 
01048         mf_write_header(a_out);
01049 
01050         a_out << std::endl;
01051 
01052         mf_write_synopsis(a_out);
01053 
01054         a_out << std::endl;
01055 
01056         m_jobs.write_report(a_out);
01057         
01058         a_out << std::endl;
01059 
01060         m_vault.write_report(a_out);
01061 
01062         a_out << std::endl;
01063 }
01064 
01065 /** Generate a synopsis report */
01066 void report_manager::format_synopsis(table& a_table)
01067 {
01068         estring estr;
01069         estring estr2;
01070 
01071         estr.align(estring::right);
01072         estr2.align(estring::right);
01073 
01074         estr = "Start Time:";
01075         estr2 = m_total_time.started_at();
01076         estr2 += "  ";
01077 
01078         a_table << estr << " " << estr2 << table_endl;
01079 
01080         estr = "Finish Time:";
01081         estr2 = m_total_time.stopped_at();
01082         estr2 += "  ";
01083 
01084         a_table << estr << " " << estr2 << table_endl;
01085 
01086         estr = "Duration:";
01087         estr2 = m_total_time.duration();
01088 
01089         a_table << estr << " " << estr2 << table_endl;
01090 }
01091 
01092 void report_manager::mf_write_header(std::ostream& a_out)
01093 {
01094         table t;
01095         estring estr;
01096 
01097         estr = "Rsync Vault Manager - ";
01098         estr += VERSION;
01099 
01100         t << estr << table_endl;
01101 
01102         estr = "";
01103         estr.fillchar('=');
01104         t << estr;
01105 
01106         a_out << t;
01107 }
01108 
01109 void report_manager::mf_write_synopsis(std::ostream& a_out)
01110 {
01111         table t;
01112         estring estr;
01113 
01114         format_synopsis(t);
01115         vault().format_synopsis(t);
01116         jobs().format_synopsis(t);
01117 
01118         a_out << t;
01119 }
01120 
01121 //-----------------------------------------------------------------------------
01122 
01123 /** The global report manager */
01124 report_manager reporter;
01125 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines