Sierra Toolkit Version of the Day
OutputLog.cpp
00001 /*------------------------------------------------------------------------*/
00002 /*                 Copyright 2010 Sandia Corporation.                     */
00003 /*  Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive   */
00004 /*  license for use of this work by or on behalf of the U.S. Government.  */
00005 /*  Export of this program may require a license from the                 */
00006 /*  United States Government.                                             */
00007 /*------------------------------------------------------------------------*/
00008 
00009 #include <stk_util/environment/OutputLog.hpp>
00010 #include <stk_util/util/TeeStreambuf.hpp>
00011 
00012 
00013 #include <map>
00014 #include <list>
00015 #include <string>
00016 #include <iostream>
00017 #include <sstream>
00018 #include <fstream>
00019 #include <stdexcept>
00020 #include <cctype>
00021 
00022 namespace stk {
00023 
00024 namespace {
00025 
00026 struct LogStream
00027 {
00028   LogStream(const std::string &path, std::ostream *output_stream, std::ofstream *file_stream)
00029     : m_path(path),
00030       m_ostream(output_stream),
00031       m_ofstream(file_stream)
00032   {}
00033 
00034   ~LogStream();
00035 
00036   std::string           m_path;
00037   std::ostream *        m_ostream;
00038   std::ofstream *       m_ofstream;
00039 
00040   private:
00041   LogStream(const LogStream &);
00042   void operator = (const LogStream &);
00043 };
00044 
00045 #ifdef __INTEL_COMPILER
00046 #pragma warning(push)
00047 #pragma warning(disable: 444)
00048 #endif
00049 struct LogStreamMap : public std::map<std::string, LogStream *>
00050 {
00051   LogStreamMap()
00052   {}
00053 
00054   ~LogStreamMap() {
00055     while (!empty()) {
00056       LogStream *log_stream = (*begin()).second;
00057       erase(begin());
00058       delete log_stream;
00059     }
00060   }
00061 };
00062 #ifdef __INTEL_COMPILER
00063 #pragma warning(pop)
00064 #endif
00065 
00066 struct OStreamTeeStreambuf
00067 {
00068   OStreamTeeStreambuf(std::ostream &output_stream)
00069     : m_ostream(&output_stream),
00070       m_origRdbuf(output_stream.rdbuf()),
00071       m_teeStreambuf(new tee_streambuf(&output_stream))
00072   {
00073     m_ostream->rdbuf(m_teeStreambuf);
00074   }
00075 
00076   ~OStreamTeeStreambuf();
00077 
00078   std::ostream *        m_ostream;
00079   std::streambuf *      m_origRdbuf;
00080   tee_streambuf *       m_teeStreambuf;
00081 
00082   private:
00083   OStreamTeeStreambuf(const OStreamTeeStreambuf &);
00084   void operator = (const OStreamTeeStreambuf &);
00085 };
00086 
00087 #ifdef __INTEL_COMPILER
00088 #pragma warning(push)
00089 #pragma warning(disable: 444)
00090 #endif
00091 struct OStreamTeeStreambufMap : public std::map<std::string, OStreamTeeStreambuf *>
00092 {
00093   OStreamTeeStreambufMap()
00094   {}
00095 
00096   ~OStreamTeeStreambufMap() {
00097     while (!empty()) {
00098       OStreamTeeStreambuf *tee_streambuf = (*begin()).second;
00099       erase(begin());
00100       delete tee_streambuf;
00101     }
00102   }
00103 };
00104 #ifdef __INTEL_COMPILER
00105 #pragma warning(pop)
00106 #endif
00107 
00108 LogStreamMap &
00109 get_file_stream_map()
00110 {
00111   static LogStreamMap s_logFileStreamMap;
00112 
00113   return s_logFileStreamMap;
00114 }
00115 
00116 
00117 OStreamTeeStreambufMap &
00118 get_ostream_tee_streambuf_map()
00119 {
00120   static OStreamTeeStreambufMap s_ostreamTeeStreambufMap;
00121 
00122   return s_ostreamTeeStreambufMap;
00123 }
00124 
00125 
00126 LogStream::~LogStream()
00127 {
00128   m_ostream->flush();
00129 
00130   // If the output stream was created internally (via bind_output_stream), be sure to remove it from
00131   // all OStreamTeeStreamBuf's
00132   if (m_ofstream) {
00133     OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
00134 
00135     for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it)
00136       (*it).second->m_teeStreambuf->remove(m_ofstream);
00137 
00138     delete m_ofstream;
00139   }
00140 }
00141 
00142 
00143 OStreamTeeStreambuf::~OStreamTeeStreambuf()
00144 {
00145   m_ostream->flush();
00146   m_ostream->rdbuf(m_origRdbuf);
00147 
00148   // Be sure to remove this from all OStreamTeeStreamBuf's
00149   OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
00150 
00151   for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it)
00152     (*it).second->m_teeStreambuf->remove(m_ostream);
00153 
00154   delete m_teeStreambuf;
00155 }
00156 
00157 } // namespace <empty>
00158 
00159 
00160 void
00161 create_log_file(
00162   const std::string &   name,
00163   const std::string &   path)
00164 {
00165   LogStreamMap &file_stream_map = get_file_stream_map();
00166 
00167   close_log_file(name);
00168 
00169   std::ofstream *file_stream = new std::ofstream(path.c_str());
00170 
00171   file_stream_map[name] = new LogStream(path, file_stream, file_stream);
00172 }
00173 
00174 
00175 void
00176 close_log_file(
00177   const std::string &   name)
00178 {
00179   LogStreamMap &file_stream_map = get_file_stream_map();
00180 
00181   LogStreamMap::iterator it = file_stream_map.find(name);
00182 
00183   if (it != file_stream_map.end()) {
00184     delete (*it).second;
00185     file_stream_map.erase(it);
00186   }
00187 }
00188 
00189 
00190 void
00191 register_log_ostream(
00192   std::ostream &        os,
00193   const std::string &   name)
00194 {
00195   LogStreamMap &file_stream_map = get_file_stream_map();
00196 
00197   LogStreamMap::iterator it = file_stream_map.find(name);
00198 
00199   if (it != file_stream_map.end()) {
00200     std::ostringstream s;
00201     s << "Log ostream " << name << " has already been registered";
00202 
00203     throw std::runtime_error(s.str());
00204   }
00205 
00206   file_stream_map[name] = new LogStream(name, &os, 0);
00207 }
00208 
00209 
00210 void
00211 unregister_log_ostream(
00212   std::ostream &        os)
00213 {
00214   LogStreamMap &file_stream_map = get_file_stream_map();
00215 
00216   for (LogStreamMap::iterator it = file_stream_map.begin(); it != file_stream_map.end(); ++it) {
00217     if ((*it).second->m_ostream == &os) {
00218       delete (*it).second;
00219       file_stream_map.erase(it);
00220       break;
00221     }
00222   }
00223 
00224   OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
00225 
00226   for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it)
00227     (*it).second->m_teeStreambuf->remove(&os);
00228 }
00229 
00230 
00231 const std::string &
00232 get_log_path(
00233   const std::string &   name)
00234 {
00235   static std::string not_found = "";
00236 
00237   LogStreamMap &file_stream_map = get_file_stream_map();
00238 
00239   LogStreamMap::iterator it = file_stream_map.find(name);
00240 
00241   return it == file_stream_map.end() ? not_found : (*it).second->m_path;
00242 }
00243 
00244 
00245 std::ostream *
00246 get_log_ostream(
00247   const std::string &   name)
00248 {
00249   LogStreamMap &file_stream_map = get_file_stream_map();
00250 
00251   LogStreamMap::iterator it = file_stream_map.find(name);
00252 
00253   return it == file_stream_map.end() ? 0 : (*it).second->m_ostream;
00254 }
00255 
00256 
00257 void
00258 register_ostream(
00259   std::ostream &        os,
00260   const std::string &   name)
00261 {
00262   OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
00263 
00264   unregister_ostream(os);
00265 
00266   OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name);
00267 
00268   if (it != ostream_tee_streambuf_map.end()) {
00269 //     delete (*it).second;
00270 //     ostream_tee_streambuf_map.erase(it);
00271 //   }
00272     std::ostringstream s;
00273     s << "Output stream " << name << " has already been registered";
00274 
00275     throw std::runtime_error(s.str());
00276   }
00277 
00278   ostream_tee_streambuf_map[name] = new OStreamTeeStreambuf(os);
00279 }
00280 
00281 
00282 void
00283 unregister_ostream(
00284   std::ostream &        os)
00285 {
00286   OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
00287 
00288   for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it)
00289     (*it).second->m_teeStreambuf->remove(&os);
00290 
00291   for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) {
00292     if ((*it).second->m_ostream == &os) {
00293       delete (*it).second;
00294       ostream_tee_streambuf_map.erase(it);
00295       break;
00296     }
00297   }
00298 
00299 }
00300 
00301 
00302 std::ostream *
00303 get_ostream_ostream(
00304   const std::string &   name)
00305 {
00306   OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
00307 
00308   OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name);
00309 
00310   return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_ostream;
00311 }
00312 
00313 
00314 tee_streambuf *
00315 get_ostream_tee_streambuf(
00316   const std::string &   name)
00317 {
00318   OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
00319 
00320   OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name);
00321 
00322   return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_teeStreambuf;
00323 }
00324 
00325 
00326 std::ostream *
00327 get_ostream_tee_ostream(
00328   const std::string &   name)
00329 {
00330   OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
00331 
00332   OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name);
00333 
00334   return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_ostream;
00335 }
00336 
00337 
00338 bool
00339 is_registered_ostream(
00340   const std::string &   name)
00341 {
00342   return get_ostream_ostream(name) != 0;
00343 }
00344 
00345 
00346 namespace {
00347 
00348 struct Command
00349 {
00350   virtual ~Command()
00351   {}
00352 
00353   virtual void execute() = 0;
00354 };
00355 
00356 #ifdef __INTEL_COMPILER
00357 #pragma warning(push)
00358 #pragma warning(disable: 444)
00359 #endif
00360 struct CommandList : public std::list<Command *>
00361 {
00362   CommandList()
00363     : std::list<Command *>()
00364   {}
00365 
00366   ~CommandList()
00367   {
00368     for (std::list<Command *>::iterator it = begin(); it != end(); ++it)
00369       delete (*it);
00370   }
00371 };
00372 #ifdef __INTEL_COMPILER
00373 #pragma warning(pop)
00374 #endif
00375 
00376 namespace {
00377 
00378 tee_streambuf &
00379 parse_tee_streambuf(
00380   const std::string &   tee_ostream_name)
00381 {
00382   tee_streambuf *osb = get_ostream_tee_streambuf(tee_ostream_name);
00383 
00384   if (!osb) {
00385     std::ostringstream s;
00386 
00387     s << "Output stream " << tee_ostream_name << " has not been registered for output logging";
00388     throw std::runtime_error(s.str());
00389   }
00390 
00391   return *osb;
00392 }
00393 
00394 
00395 std::ostream *
00396 parse_ostream(
00397   const std::string &   ostream_name)
00398 {
00399   std::ostream *os = get_log_ostream(ostream_name);
00400 
00401   if (!os)
00402     os = get_ostream_tee_ostream(ostream_name);
00403 
00404   if (!os) {
00405     std::ostringstream s;
00406 
00407     s << "Log file '" << ostream_name << "' has not been registered";
00408     throw std::runtime_error(s.str());
00409   }
00410 
00411   return os;
00412 }
00413 
00414 
00415 struct OpenLog : public Command
00416 {
00417   OpenLog(
00418     const std::string &name,
00419     const std::string &path)
00420     : m_name(name),
00421       m_path(path)
00422   {}
00423 
00424   virtual ~OpenLog()
00425   {}
00426 
00427   virtual void execute() {
00428     create_log_file(m_name, m_path);
00429   }
00430 
00431   std::string        m_name;
00432   std::string        m_path;
00433 };
00434 
00435 
00436 struct CloseLog : public Command
00437 {
00438   CloseLog(
00439     const std::string &name)
00440     : m_name(name)
00441   {}
00442 
00443   virtual ~CloseLog()
00444   {}
00445 
00446   virtual void execute() {
00447     close_log_file(m_name);
00448   }
00449 
00450   std::string        m_name;
00451 };
00452 
00453 
00454 struct ClearTeeOStream : public Command
00455 {
00456   ClearTeeOStream(
00457     const std::string & tee_ostream_name)
00458     : m_teeOStreamName(tee_ostream_name)
00459   {}
00460 
00461   virtual ~ClearTeeOStream()
00462   {}
00463 
00464   virtual void execute() {
00465     parse_tee_streambuf(m_teeOStreamName).clear();
00466   }
00467 
00468   std::string        m_teeOStreamName;
00469 };
00470 
00471 
00472 struct AddTeeOStream : public Command
00473 {
00474   AddTeeOStream(
00475     const std::string & tee_ostream_name,
00476     const std::string & ostream_name)
00477     : m_teeOStreamName(tee_ostream_name),
00478       m_ostreamName(ostream_name)
00479   {}
00480 
00481   virtual ~AddTeeOStream()
00482   {}
00483 
00484   virtual void execute() {
00485     if (m_ostreamName != "null")
00486       parse_tee_streambuf(m_teeOStreamName).add(parse_ostream(m_ostreamName));
00487   }
00488 
00489   std::string        m_teeOStreamName;
00490   std::string        m_ostreamName;
00491 };
00492 
00493 
00494 struct RemoveTeeOStream : public Command
00495 {
00496   RemoveTeeOStream(
00497     const std::string & tee_ostream_name,
00498     const std::string & ostream_name)
00499     : m_teeOStreamName(tee_ostream_name),
00500       m_ostreamName(ostream_name)
00501   {}
00502 
00503   virtual ~RemoveTeeOStream()
00504   {}
00505 
00506   virtual void execute() {
00507     parse_tee_streambuf(m_teeOStreamName).remove(parse_ostream(m_ostreamName));
00508   }
00509 
00510   std::string        m_teeOStreamName;
00511   std::string        m_ostreamName;
00512 };
00513 
00514 } // namespace <empty>
00515 
00516 
00517 /*
00518  * Startup:     out > cout pout > cout dout > cout
00519  * Normal:      out > log-path+pout pout > null dout > out
00520  * Diagnostic:  out > out-path+pout pout > pout-path dout > out
00521  *
00522  * Modify:      out > +pout
00523  *              out > -pout
00524  */
00525 void
00526 parse_output_description(
00527   const std::string &   output_description,
00528   CommandList &         command_list)
00529 {
00530   typedef std::pair<const char *, const char *>  Token;
00531   typedef std::list<Token> TokenList;
00532 
00533   command_list.clear();
00534 
00535   TokenList tokens;
00536 
00537   for (const char *c = output_description.c_str(); *c; ) {
00538     if (std::isspace(*c))
00539       ++c;
00540 
00541     else if (*c == '>' || *c == '+' || *c == '-' || *c == '=') {
00542       tokens.push_back(Token(c, c + 1));
00543       ++c;
00544     }
00545 
00546     else if (*c == '\"') {
00547       const char *d = c + 1;
00548       while (*d && *d != '\"')
00549         ++d;
00550       tokens.push_back(Token(c + 1, d));
00551       c = d + 1;
00552     }
00553 
00554     else {
00555       const char *d = c;
00556       while (std::isgraph(*d) && *d != '+' && *d != '-' &&*d != '=' && *d != '>')
00557         ++d;
00558       tokens.push_back(Token(c, d));
00559       c = d;
00560     }
00561   }
00562 
00563   for (TokenList::iterator it = tokens.begin(); it != tokens.end(); ) {
00564     std::string name((*it).first, (*it).second);
00565 
00566     ++it; if (it == tokens.end()) break;
00567     std::string operation((*it).first, (*it).second);
00568 
00569     if (operation == "=") {
00570       ++it;  if (it == tokens.end()) break;
00571       std::string path((*it).first, (*it).second);
00572       if (!path.empty())
00573         command_list.push_back(new OpenLog(name, path));
00574       else
00575         command_list.push_back(new CloseLog(name));
00576       ++it;  if (it == tokens.end()) break;
00577     }
00578 
00579     else if (operation == ">") {
00580       parse_tee_streambuf(name);
00581 
00582       ++it;  if (it == tokens.end()) break;
00583       std::string token(std::string((*it).first, (*it).second));
00584       if (token != "+" && token != "-") {
00585         std::string ostream_name(std::string((*it).first, (*it).second));
00586 
00587         command_list.push_back(new ClearTeeOStream(name));
00588         command_list.push_back(new AddTeeOStream(name, ostream_name));
00589         ++it;  if (it == tokens.end()) break;
00590       }
00591 
00592       while (it != tokens.end()) {
00593         token = std::string((*it).first, (*it).second);
00594         if (token == "+") {
00595           ++it;  if (it == tokens.end()) break;
00596           std::string ostream_name(std::string((*it).first, (*it).second));
00597 
00598           command_list.push_back(new AddTeeOStream(name, ostream_name));
00599           ++it;  if (it == tokens.end()) break;
00600         }
00601 
00602         else if (token == "-") {
00603           ++it;  if (it == tokens.end()) break;
00604           std::string ostream_name(std::string((*it).first, (*it).second));
00605 
00606           command_list.push_back(new RemoveTeeOStream(name, ostream_name));
00607           ++it;  if (it == tokens.end()) break;
00608         }
00609         else
00610           break;
00611       }
00612     }
00613   }
00614 }
00615 
00616 void
00617 execute(
00618   const CommandList &   command_list)
00619 {
00620   for (CommandList::const_iterator it = command_list.begin(); it != command_list.end(); ++it)
00621     (*it)->execute();
00622 }
00623 
00624 } // namespace <empty>
00625 
00626 void
00627 bind_output_streams(
00628   const std::string &   output_description)
00629 {
00630   stk::CommandList command_list;
00631 
00632   parse_output_description(output_description, command_list);
00633   execute(command_list);
00634 }
00635 
00636 } // namespace stk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends