rvm 1.08
|
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