Sierra Toolkit  Version of the Day
OutputLog.cpp
1 /*------------------------------------------------------------------------*/
2 /* Copyright 2010 Sandia Corporation. */
3 /* Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive */
4 /* license for use of this work by or on behalf of the U.S. Government. */
5 /* Export of this program may require a license from the */
6 /* United States Government. */
7 /*------------------------------------------------------------------------*/
8 
9 #include <iostream>
11 #include <stk_util/util/TeeStreambuf.hpp>
12 #include <stk_util/util/IndentStreambuf.hpp>
13 
14 
15 #include <map>
16 #include <list>
17 #include <string>
18 #include <iostream>
19 #include <sstream>
20 #include <fstream>
21 #include <stdexcept>
22 #include <cctype>
23 
24 namespace stk_classic {
25 
26 namespace {
27 
28 struct LogStream
29 {
30  LogStream(const std::string &path, std::ostream *output_stream, std::ofstream *file_stream)
31  : m_path(path),
32  m_ostream(output_stream),
33  m_ofstream(file_stream)
34  {}
35 
36  ~LogStream();
37 
38  std::string m_path;
39  std::ostream * m_ostream;
40  std::ofstream * m_ofstream;
41 
42  private:
43  LogStream(const LogStream &);
44  void operator = (const LogStream &);
45 };
46 
47 #ifdef __INTEL_COMPILER
48 #pragma warning(push)
49 #pragma warning(disable: 444)
50 #endif
51 struct LogStreamMap : public std::map<std::string, LogStream *>
52 {
53  LogStreamMap()
54  {}
55 
56  ~LogStreamMap() {
57  while (!empty()) {
58  LogStream *log_stream = (*begin()).second;
59  erase(begin());
60  delete log_stream;
61  }
62  }
63 };
64 #ifdef __INTEL_COMPILER
65 #pragma warning(pop)
66 #endif
67 
68 struct OStreamTeeStreambuf
69 {
70  OStreamTeeStreambuf(std::ostream &output_stream)
71  : m_ostream(&output_stream),
72  m_origRdbuf(output_stream.rdbuf()),
73  m_teeStreambuf(new tee_streambuf(&output_stream))
74  {
75  m_ostream->rdbuf(m_teeStreambuf);
76  }
77 
78  ~OStreamTeeStreambuf();
79 
80  std::ostream * m_ostream;
81  std::streambuf * m_origRdbuf;
82  tee_streambuf * m_teeStreambuf;
83 
84  private:
85  OStreamTeeStreambuf(const OStreamTeeStreambuf &);
86  void operator = (const OStreamTeeStreambuf &);
87 };
88 
89 #ifdef __INTEL_COMPILER
90 #pragma warning(push)
91 #pragma warning(disable: 444)
92 #endif
93 struct OStreamTeeStreambufMap : public std::map<std::string, OStreamTeeStreambuf *>
94 {
95  OStreamTeeStreambufMap()
96  {}
97 
98  ~OStreamTeeStreambufMap() {
99  while (!empty()) {
100  OStreamTeeStreambuf *tee_streambuf = (*begin()).second;
101  erase(begin());
102  delete tee_streambuf;
103  }
104  }
105 };
106 #ifdef __INTEL_COMPILER
107 #pragma warning(pop)
108 #endif
109 
110 LogStreamMap &
111 get_file_stream_map()
112 {
113  static LogStreamMap s_logFileStreamMap;
114 
115  return s_logFileStreamMap;
116 }
117 
118 
119 OStreamTeeStreambufMap &
120 get_ostream_tee_streambuf_map()
121 {
122  static OStreamTeeStreambufMap s_ostreamTeeStreambufMap;
123 
124  return s_ostreamTeeStreambufMap;
125 }
126 
127 
128 LogStream::~LogStream()
129 {
130  m_ostream->flush();
131 
132  // If the output stream was created internally (via bind_output_stream), be sure to remove it from
133  // all OStreamTeeStreamBuf's
134  if (m_ofstream) {
135  OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
136 
137  for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it)
138  (*it).second->m_teeStreambuf->remove(m_ofstream);
139 
140  delete m_ofstream;
141  }
142 }
143 
144 
145 OStreamTeeStreambuf::~OStreamTeeStreambuf()
146 {
147  if (m_ostream) {
148  m_ostream->flush();
149  m_ostream->rdbuf(m_origRdbuf);
150  }
151 
152  // Be sure to remove this from all OStreamTeeStreamBuf's
153  OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
154 
155  for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it)
156  (*it).second->m_teeStreambuf->remove(m_ostream);
157 
158  delete m_teeStreambuf;
159 }
160 
161 } // namespace <empty>
162 
163 
164 void
166  const std::string & name,
167  const std::string & path)
168 {
169  LogStreamMap &file_stream_map = get_file_stream_map();
170 
171  close_log_file(name);
172 
173  std::ofstream *file_stream = new std::ofstream(path.c_str());
174 
175  if(!file_stream->good()) {
176 
177  std::ostringstream s;
178  s << "Cannot open output log file '" << path << "' directory does not exist or is write protected.";
179 
180  throw std::runtime_error(s.str());
181 
182  }
183 
184 
185  file_stream_map[name] = new LogStream(path, file_stream, file_stream);
186 }
187 
188 
189 void
191  const std::string & name)
192 {
193  LogStreamMap &file_stream_map = get_file_stream_map();
194 
195  LogStreamMap::iterator it = file_stream_map.find(name);
196 
197  if (it != file_stream_map.end()) {
198  delete (*it).second;
199  file_stream_map.erase(it);
200  }
201 }
202 
203 
204 void
206  std::ostream & os,
207  const std::string & name)
208 {
209  LogStreamMap &file_stream_map = get_file_stream_map();
210 
211  LogStreamMap::iterator it = file_stream_map.find(name);
212 
213  if (it != file_stream_map.end()) {
214  std::ostringstream s;
215  s << "Log ostream " << name << " has already been registered";
216 
217  //Do we really want to throw if a stream is registered multiple times?
218  //I don't think so... commenting this out.
219  //throw std::runtime_error(s.str());
220  }
221  else {
222  file_stream_map[name] = new LogStream(name, &os, 0);
223  }
224 }
225 
226 
227 void
229  std::ostream & os)
230 {
231  LogStreamMap &file_stream_map = get_file_stream_map();
232 
233  for (LogStreamMap::iterator it = file_stream_map.begin(); it != file_stream_map.end(); ++it) {
234  if ((*it).second->m_ostream == &os) {
235  delete (*it).second;
236  file_stream_map.erase(it);
237  break;
238  }
239  }
240 
241  OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
242 
243  for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it)
244  (*it).second->m_teeStreambuf->remove(&os);
245 }
246 
247 
248 const std::string &
250  const std::string & name)
251 {
252  static std::string not_found = "";
253 
254  LogStreamMap &file_stream_map = get_file_stream_map();
255 
256  LogStreamMap::iterator it = file_stream_map.find(name);
257 
258  return it == file_stream_map.end() ? not_found : (*it).second->m_path;
259 }
260 
261 
262 std::ostream *
264  const std::string & name)
265 {
266  LogStreamMap &file_stream_map = get_file_stream_map();
267 
268  LogStreamMap::iterator it = file_stream_map.find(name);
269 
270  return it == file_stream_map.end() ? 0 : (*it).second->m_ostream;
271 }
272 
273 
274 void
276  std::ostream & os,
277  const std::string & name)
278 {
279  OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
280 
281  unregister_ostream(os);
282 
283  OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name);
284 
285  if (it != ostream_tee_streambuf_map.end()) {
286 // delete (*it).second;
287 // ostream_tee_streambuf_map.erase(it);
288 // }
289  std::ostringstream s;
290  s << "Output stream " << name << " has already been registered";
291 
292  throw std::runtime_error(s.str());
293  }
294 
295  ostream_tee_streambuf_map[name] = new OStreamTeeStreambuf(os);
296 }
297 
298 
299 void
301  std::ostream & os)
302 {
303  OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
304 
305  for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it)
306  (*it).second->m_teeStreambuf->remove(&os);
307 
308  for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) {
309  if ((*it).second->m_ostream == &os) {
310  delete (*it).second;
311  ostream_tee_streambuf_map.erase(it);
312  break;
313  }
314  }
315 
316 }
317 
318 
319 std::ostream *
321  const std::string & name)
322 {
323  OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
324 
325  OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name);
326 
327  return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_ostream;
328 }
329 
330 
332 get_ostream_tee_streambuf(
333  const std::string & name)
334 {
335  OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
336 
337  OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name);
338 
339  return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_teeStreambuf;
340 }
341 
342 
343 std::ostream *
345  const std::string & name)
346 {
347  OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map();
348 
349  OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name);
350 
351  return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_ostream;
352 }
353 
354 
355 bool
357  const std::string & name)
358 {
359  return get_ostream_ostream(name) != 0;
360 }
361 
362 
363 namespace {
364 
365 struct Command
366 {
367  virtual ~Command()
368  {}
369 
370  virtual void execute() = 0;
371 };
372 
373 #ifdef __INTEL_COMPILER
374 #pragma warning(push)
375 #pragma warning(disable: 444)
376 #endif
377 struct CommandList : public std::list<Command *>
378 {
379  CommandList()
380  : std::list<Command *>()
381  {}
382 
383  ~CommandList()
384  {
385  for (std::list<Command *>::iterator it = begin(); it != end(); ++it)
386  delete (*it);
387  }
388 };
389 #ifdef __INTEL_COMPILER
390 #pragma warning(pop)
391 #endif
392 
393 namespace {
394 
396 parse_tee_streambuf(
397  const std::string & tee_ostream_name)
398 {
399  tee_streambuf *osb = get_ostream_tee_streambuf(tee_ostream_name);
400 
401  if (!osb) {
402  std::ostringstream s;
403 
404  s << "Output stream " << tee_ostream_name << " has not been registered for output logging";
405  throw std::runtime_error(s.str());
406  }
407 
408  return *osb;
409 }
410 
411 
412 std::ostream *
413 parse_ostream(
414  const std::string & ostream_name)
415 {
416  std::ostream *os = get_log_ostream(ostream_name);
417 
418  if (!os)
419  os = get_ostream_tee_ostream(ostream_name);
420 
421  if (!os) {
422  std::ostringstream s;
423 
424  s << "Log file '" << ostream_name << "' has not been registered";
425  throw std::runtime_error(s.str());
426  }
427 
428  return os;
429 }
430 
431 
432 struct OpenLog : public Command
433 {
434  OpenLog(
435  const std::string &name,
436  const std::string &path)
437  : m_name(name),
438  m_path(path)
439  {}
440 
441  virtual ~OpenLog()
442  {}
443 
444  virtual void execute() {
445  create_log_file(m_name, m_path);
446  }
447 
448  std::string m_name;
449  std::string m_path;
450 };
451 
452 
453 struct CloseLog : public Command
454 {
455  CloseLog(
456  const std::string &name)
457  : m_name(name)
458  {}
459 
460  virtual ~CloseLog()
461  {}
462 
463  virtual void execute() {
464  close_log_file(m_name);
465  }
466 
467  std::string m_name;
468 };
469 
470 
471 struct ClearTeeOStream : public Command
472 {
473  ClearTeeOStream(
474  const std::string & tee_ostream_name)
475  : m_teeOStreamName(tee_ostream_name)
476  {}
477 
478  virtual ~ClearTeeOStream()
479  {}
480 
481  virtual void execute() {
482  parse_tee_streambuf(m_teeOStreamName).clear();
483  }
484 
485  std::string m_teeOStreamName;
486 };
487 
488 
489 struct AddTeeOStream : public Command
490 {
491  AddTeeOStream(
492  const std::string & tee_ostream_name,
493  const std::string & ostream_name)
494  : m_teeOStreamName(tee_ostream_name),
495  m_ostreamName(ostream_name)
496  {}
497 
498  virtual ~AddTeeOStream()
499  {}
500 
501  virtual void execute() {
502  if (m_ostreamName != "null")
503  parse_tee_streambuf(m_teeOStreamName).add(parse_ostream(m_ostreamName));
504  }
505 
506  std::string m_teeOStreamName;
507  std::string m_ostreamName;
508 };
509 
510 
511 struct RemoveTeeOStream : public Command
512 {
513  RemoveTeeOStream(
514  const std::string & tee_ostream_name,
515  const std::string & ostream_name)
516  : m_teeOStreamName(tee_ostream_name),
517  m_ostreamName(ostream_name)
518  {}
519 
520  virtual ~RemoveTeeOStream()
521  {}
522 
523  virtual void execute() {
524  parse_tee_streambuf(m_teeOStreamName).remove(parse_ostream(m_ostreamName));
525  }
526 
527  std::string m_teeOStreamName;
528  std::string m_ostreamName;
529 };
530 
531 } // namespace <empty>
532 
533 
534 /*
535  * Startup: out > cout pout > cout dout > cout
536  * Normal: out > log-path+pout pout > null dout > out
537  * Diagnostic: out > out-path+pout pout > pout-path dout > out
538  *
539  * Modify: out > +pout
540  * out > -pout
541  */
542 void
543 parse_output_description(
544  const std::string & output_description,
545  CommandList & command_list)
546 {
547  typedef std::pair<const char *, const char *> Token;
548  typedef std::list<Token> TokenList;
549 
550  command_list.clear();
551 
552  TokenList tokens;
553 
554  for (const char *c = output_description.c_str(); *c; ) {
555  if (std::isspace(*c))
556  ++c;
557 
558  else if (*c == '>' || *c == '+' || *c == '-' || *c == '=') {
559  tokens.push_back(Token(c, c + 1));
560  ++c;
561  }
562 
563  else if (*c == '\"') {
564  const char *d = c + 1;
565  while (*d && *d != '\"')
566  ++d;
567  tokens.push_back(Token(c + 1, d));
568  c = d + 1;
569  }
570 
571  else {
572  const char *d = c;
573  while (std::isgraph(*d) && *d != '+' && *d != '-' &&*d != '=' && *d != '>')
574  ++d;
575  tokens.push_back(Token(c, d));
576  c = d;
577  }
578  }
579 
580  for (TokenList::iterator it = tokens.begin(); it != tokens.end(); ) {
581  std::string name((*it).first, (*it).second);
582 
583  ++it; if (it == tokens.end()) break;
584  std::string operation((*it).first, (*it).second);
585 
586  if (operation == "=") {
587  ++it; if (it == tokens.end()) break;
588  std::string path((*it).first, (*it).second);
589  if (!path.empty())
590  command_list.push_back(new OpenLog(name, path));
591  else
592  command_list.push_back(new CloseLog(name));
593  ++it; if (it == tokens.end()) break;
594  }
595 
596  else if (operation == ">") {
597  parse_tee_streambuf(name);
598 
599  ++it; if (it == tokens.end()) break;
600  std::string token(std::string((*it).first, (*it).second));
601  if (token != "+" && token != "-") {
602  std::string ostream_name(std::string((*it).first, (*it).second));
603 
604  command_list.push_back(new ClearTeeOStream(name));
605  command_list.push_back(new AddTeeOStream(name, ostream_name));
606  ++it; if (it == tokens.end()) break;
607  }
608 
609  while (it != tokens.end()) {
610  token = std::string((*it).first, (*it).second);
611  if (token == "+") {
612  ++it; if (it == tokens.end()) break;
613  std::string ostream_name(std::string((*it).first, (*it).second));
614 
615  command_list.push_back(new AddTeeOStream(name, ostream_name));
616  ++it; if (it == tokens.end()) break;
617  }
618 
619  else if (token == "-") {
620  ++it; if (it == tokens.end()) break;
621  std::string ostream_name(std::string((*it).first, (*it).second));
622 
623  command_list.push_back(new RemoveTeeOStream(name, ostream_name));
624  ++it; if (it == tokens.end()) break;
625  }
626  else
627  break;
628  }
629  }
630  }
631 }
632 
633 void
634 execute(
635  const CommandList & command_list)
636 {
637  for (CommandList::const_iterator it = command_list.begin(); it != command_list.end(); ++it)
638  (*it)->execute();
639 }
640 
641 } // namespace <empty>
642 
643 void
645  const std::string & output_description)
646 {
647  stk_classic::CommandList command_list;
648 
649  parse_output_description(output_description, command_list);
650  execute(command_list);
651 }
652 
653 } // namespace stk_classic
654 
655 namespace sierra {
656 
657 std::ostream &
658 out() {
659  static std::ostream s_out(std::cout.rdbuf());
660 
661  return s_out;
662 }
663 
664 
665 std::ostream &
666 pout() {
667  static std::ostream s_pout(std::cout.rdbuf());
668 
669  return s_pout;
670 }
671 
672 
673 std::ostream &
674 dout() {
675  static std::ostream s_dout(std::cout.rdbuf());
676 
677  return s_dout;
678 }
679 
680 
681 std::ostream &
682 tout() {
683  static std::ostream s_tout(std::cout.rdbuf());
684 
685  return s_tout;
686 }
687 
688 
689 std::ostream &
690 dwout() {
691  static stk_classic::indent_streambuf s_dwoutStreambuf(std::cout.rdbuf());
692  static std::ostream s_dwout(&s_dwoutStreambuf);
693 
694  return s_dwout;
695 }
696 
697 } // namespace sierra
698 
699 
700 
std::ostream & dout()
Diagnostic output stream.
Definition: OutputLog.cpp:674
std::ostream & dwout()
Diagnostic writer stream.
Definition: OutputLog.cpp:690
Definition: Env.cpp:53
const std::string & get_log_path(const std::string &name)
Function get_log_path returns the file path of the log file with the specified name from the log file...
Definition: OutputLog.cpp:249
std::ostream & pout()
Per-processor output stream (See RuntimeDeferredx)
Definition: OutputLog.cpp:666
std::ostream & out()
Normal output stream.
Definition: OutputLog.cpp:658
stk_classic::basic_tee_streambuf< char, std::char_traits< char > > tee_streambuf
Tee stream buffer for char.
Definition: OutputLog.hpp:20
void create_log_file(const std::string &name, const std::string &path)
Function create_log_file opens a log file at the specified path and adds it to the registry of log fi...
Definition: OutputLog.cpp:165
Class basic_indent_streambuf implements a output streambuf that performs indentation, blank line removal and outline bracing, sending the result character stream to another output stream buffer.
void close_log_file(const std::string &name)
Function close_log_file close the log file with the specified name and removes it from the registry o...
Definition: OutputLog.cpp:190
std::ostream * get_ostream_ostream(const std::string &name)
Function get_ostream_streambuf locates the output stream registered with the specified name...
Definition: OutputLog.cpp:320
std::ostream * get_ostream_tee_ostream(const std::string &name)
Function get_ostream_tee_streambuf locates the tee streambuf registered with the specified name...
Definition: OutputLog.cpp:344
void bind_output_streams(const std::string &output_description)
Function bind_output_streams parses the output_description and opens and registers the log streams an...
Definition: OutputLog.cpp:644
bool is_registered_ostream(const std::string &name)
Function is_registered_ostream returns true if an output stream of the specified name is registered...
Definition: OutputLog.cpp:356
Sierra Toolkit.
std::ostream & tout()
Regression test textual output stream.
Definition: OutputLog.cpp:682
std::ostream * get_log_ostream(const std::string &name)
Function get_log_file_ostream return the output stream of the log file with the specified name from t...
Definition: OutputLog.cpp:263
void unregister_ostream(std::ostream &os)
Function unregister_ostream unregisters an output stream.
Definition: OutputLog.cpp:300
void unregister_log_ostream(std::ostream &os)
Function register_log_ostream takes an existing std::ostream and makes it available for output redire...
Definition: OutputLog.cpp:228
void register_log_ostream(std::ostream &os, const std::string &name)
Function register_log_ostream takes an existing std::ostream and makes it available for output redire...
Definition: OutputLog.cpp:205
void register_ostream(std::ostream &os, const std::string &name)
Function register_ostream registers an output stream with the output stream registry. The registration process creates an intermediate tee streambuf.
Definition: OutputLog.cpp:275