Reference documentation for deal.II version 9.0.0
logstream.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/logstream.h>
17 #include <deal.II/base/job_identifier.h>
18 #include <deal.II/base/thread_management.h>
19 
20 #include <iostream>
21 #include <iomanip>
22 #include <fstream>
23 #include <sstream>
24 
25 
26 DEAL_II_NAMESPACE_OPEN
27 
28 namespace
29 {
30  Threads::Mutex log_lock;
31  Threads::Mutex write_lock;
32 }
33 
34 
35 // The standard log object of deal.II:
36 LogStream deallog;
37 
38 
39 
40 
41 LogStream::Prefix::Prefix(const std::string &text)
42  :
43  stream(&deallog)
44 {
45  stream->push(text);
46 }
47 
48 
49 
50 LogStream::Prefix::Prefix(const std::string &text,
51  LogStream &s)
52  :
53  stream(&s)
54 {
55  stream->push(text);
56 }
57 
58 
59 
61 {
62  // destructors may not throw exceptions. if the pop() function
63  // actually does throw one, then ignore it
64  try
65  {
66  stream->pop();
67  }
68  catch (...)
69  {
70  AssertNothrow (false,
71  ExcMessage("An exception occurred in LogStream::Prefix::~Prefix."));
72  }
73 }
74 
75 
76 
78  :
79  std_out(&std::cout),
80  file(nullptr),
81  std_depth(0),
82  file_depth(10000),
83  print_thread_id(false),
84  at_newline(true)
85 {
86  get_prefixes().push("DEAL:");
87 }
88 
89 
90 
92 {
93  // if there was anything left in the stream that is current to this
94  // thread, make sure we flush it before it gets lost
95  {
96  if (get_stream().str().length() > 0)
97  {
98  // except the situation is not quite that simple. if this object is
99  // the 'deallog' object, then it is destroyed upon exit of the
100  // program. since it's defined in a shared library that depends on
101  // libstdc++.so, destruction happens before destruction of
102  // std::cout/cerr, but after all file variables defined in user
103  // programs have been destroyed. in other words, if we get here and
104  // the object being destroyed is 'deallog' and if 'deallog' is
105  // associated with a file stream, then we're in trouble: we'll try
106  // to write to a file that doesn't exist any more, and we're likely
107  // going to crash (this is tested by base/log_crash_01). rather
108  // than letting it come to this, print a message to the screen
109  // (note that we can't issue an assertion here either since Assert
110  // may want to write to 'deallog' itself, and AssertThrow will
111  // throw an exception that can't be caught)
112  if ((this == &deallog) && file)
113  *std_out << ("You still have content that was written to 'deallog' "
114  "but not flushed to the screen or a file while the "
115  "program is being terminated. This would lead to a "
116  "segmentation fault. Make sure you flush the "
117  "content of the 'deallog' object using 'std::endl' "
118  "before the end of the program.")
119  << std::endl;
120  else
121  *this << std::endl;
122  }
123  }
124 }
125 
126 
127 LogStream &
128 LogStream::operator<< (std::ostream& (*p) (std::ostream &))
129 {
130 
131  std::ostringstream &stream = get_stream();
132 
133  // Print to the internal stringstream:
134  stream << p;
135 
136 
137  // This is a bloody hack until LogStream got reimplemented as a proper
138  // child of std::streambuf (or similar).
139  //
140  // The problem is that at this point we would like to know whether an
141  // std::flush or std::endl has called us, however, there is no way to
142  // detect this in a sane manner.
143  //
144  // The obvious idea to compare function pointers,
145  // std::ostream & (* const p_flush) (std::ostream &) = &std::flush;
146  // p == p_flush ? ...,
147  // is wrong as there doesn't has to be a _single_ std::flush instance...
148  // there could be multiple of it. And in fact, LLVM's libc++ implements
149  // std::flush and std::endl in a way that every shared library and
150  // executable has its local copy... fun...
151  //
152  // - Maier, 2013
153 
154  class QueryStreambuf : public std::streambuf
155  {
156  // Implement a minimalistic stream buffer that only stores the fact
157  // whether overflow or sync was called
158  public:
159  QueryStreambuf()
160  : flushed_(false), newline_written_(false)
161  {
162  }
163  bool flushed()
164  {
165  return flushed_;
166  }
167  bool newline_written()
168  {
169  return newline_written_;
170  }
171  private:
172  int_type overflow(int_type ch)
173  {
174  newline_written_ = true;
175  return ch;
176  }
177  int sync()
178  {
179  flushed_ = true;
180  return 0;
181  }
182  bool flushed_;
183  bool newline_written_;
184  } query_streambuf;
185 
186  {
187  // and initialize an ostream with this streambuf:
188  std::ostream inject (&query_streambuf);
189  inject << p;
190  }
191 
192  if (query_streambuf.flushed())
193  {
194  Threads::Mutex::ScopedLock lock(write_lock);
195 
196  // Print the line head in case of a previous newline:
197  if (at_newline)
198  print_line_head();
199 
200  at_newline = query_streambuf.newline_written();
201 
202  if (get_prefixes().size() <= std_depth)
203  *std_out << stream.str();
204 
205  if (file && (get_prefixes().size() <= file_depth))
206  *file << stream.str() << std::flush;
207 
208  // Start a new string:
209  stream.str("");
210  }
211 
212  return *this;
213 }
214 
215 
216 void
217 LogStream::attach(std::ostream &o,
218  const bool print_job_id)
219 {
220  Threads::Mutex::ScopedLock lock(log_lock);
221  file = &o;
222  o.setf(std::ios::showpoint | std::ios::left);
223  if (print_job_id)
224  o << dealjobid();
225 }
226 
227 
229 {
230  Threads::Mutex::ScopedLock lock(log_lock);
231  file = nullptr;
232 }
233 
234 
235 std::ostream &
237 {
238  return *std_out;
239 }
240 
241 
242 
243 std::ostringstream &
245 {
246  // see if we have already created this stream. if not, do so and
247  // set the default flags (why we set these flags is lost to
248  // history, but this is what we need to keep several hundred tests
249  // from producing different output)
250  //
251  // note that in all of this we need not worry about thread-safety
252  // because we operate on a thread-local object and by definition
253  // there can only be one access at a time
254  if (outstreams.get().get() == nullptr)
255  {
256  outstreams.get() = std::make_shared<std::ostringstream>();
257  outstreams.get()->setf(std::ios::showpoint | std::ios::left);
258  }
259 
260  // then return the stream
261  return *outstreams.get();
262 }
263 
264 
265 
266 std::ostream &
268 {
269  Assert(file,
270  ExcMessage("You can't ask for the std::ostream object for the output "
271  "file if none had been set before."));
272  return *file;
273 }
274 
275 
276 
277 bool
279 {
280  return (file != nullptr);
281 }
282 
283 
284 
285 const std::string &
287 {
288  static std::string empty_string;
289 
290  if (get_prefixes().size() > 0)
291  return get_prefixes().top();
292  else
293  return empty_string;
294 }
295 
296 
297 
298 void
299 LogStream::push (const std::string &text)
300 {
301  std::string pre;
302  if (get_prefixes().size() > 0)
303  pre = get_prefixes().top();
304 
305  pre += text;
306  pre += std::string(":");
307  get_prefixes().push(pre);
308 }
309 
310 
311 
313 {
314  if (get_prefixes().size() > 0)
315  get_prefixes().pop();
316 }
317 
318 
319 
320 std::ios::fmtflags
321 LogStream::flags(const std::ios::fmtflags f)
322 {
323  return get_stream().flags (f);
324 }
325 
326 
327 
328 std::streamsize
329 LogStream::precision (const std::streamsize prec)
330 {
331  return get_stream().precision (prec);
332 }
333 
334 
335 
336 std::streamsize
337 LogStream::width (const std::streamsize wide)
338 {
339  return get_stream().width (wide);
340 }
341 
342 
343 
344 unsigned int
345 LogStream::depth_console (const unsigned int n)
346 {
347  Threads::Mutex::ScopedLock lock(log_lock);
348  const unsigned int h = std_depth;
349  std_depth = n;
350  return h;
351 }
352 
353 
354 
355 unsigned int
356 LogStream::depth_file (const unsigned int n)
357 {
358  Threads::Mutex::ScopedLock lock(log_lock);
359  const unsigned int h = file_depth;
360  file_depth = n;
361  return h;
362 }
363 
364 
365 
366 bool
367 LogStream::log_thread_id (const bool flag)
368 {
369  Threads::Mutex::ScopedLock lock(log_lock);
370  const bool h = print_thread_id;
371  print_thread_id = flag;
372  return h;
373 }
374 
375 
376 
377 std::stack<std::string> &
379 {
380 #ifdef DEAL_II_WITH_THREADS
381  bool exists = false;
382  std::stack<std::string> &local_prefixes = prefixes.get(exists);
383 
384  // If this is a new locally stored stack, copy the "blessed" prefixes
385  // from the initial thread that created logstream.
386  if (! exists)
387  {
388  const tbb::enumerable_thread_specific<std::stack<std::string> > &impl
390 
391  // The thread that created this LogStream object should be the first
392  // in tbb's enumerable_thread_specific container.
393  const tbb::enumerable_thread_specific<std::stack<std::string> >::const_iterator first_elem
394  = impl.begin();
395 
396  if (first_elem != impl.end())
397  {
398  local_prefixes = *first_elem;
399  }
400  }
401 
402  return local_prefixes;
403 
404 #else
405  return prefixes.get();
406 #endif
407 }
408 
409 
410 
411 void
413 {
414  const std::string &head = get_prefix();
415  const unsigned int thread = Threads::this_thread_id();
416 
417  if (get_prefixes().size() <= std_depth)
418  {
419  if (print_thread_id)
420  *std_out << '[' << thread << ']';
421 
422  if (head.size() > 0)
423  *std_out << head << ':';
424  }
425 
426  if (file && (get_prefixes().size() <= file_depth))
427  {
428  if (print_thread_id)
429  *file << '[' << thread << ']';
430 
431  if (head.size() > 0)
432  *file << head << ':';
433  }
434 }
435 
436 DEAL_II_NAMESPACE_CLOSE
void pop()
Definition: logstream.cc:312
#define AssertNothrow(cond, exc)
Definition: exceptions.h:1183
std::streamsize precision(const std::streamsize prec)
Definition: logstream.cc:329
unsigned int this_thread_id()
std::ostream * std_out
Definition: logstream.h:306
Threads::ThreadLocalStorage< std::stack< std::string > > prefixes
Definition: logstream.h:299
const std::string & get_prefix() const
Definition: logstream.cc:286
bool print_thread_id
Definition: logstream.h:332
unsigned int depth_file(const unsigned int n)
Definition: logstream.cc:356
STL namespace.
unsigned int std_depth
Definition: logstream.h:322
std::streamsize width(const std::streamsize wide)
Definition: logstream.cc:337
bool log_thread_id(const bool flag)
Definition: logstream.cc:367
std::ostream & get_file_stream()
Definition: logstream.cc:267
std::ios::fmtflags flags(const std::ios::fmtflags f)
Definition: logstream.cc:321
static ::ExceptionBase & ExcMessage(std::string arg1)
bool has_file() const
Definition: logstream.cc:278
~LogStream()
Definition: logstream.cc:91
#define Assert(cond, exc)
Definition: exceptions.h:1142
tbb::enumerable_thread_specific< T > & get_implementation()
std::stack< std::string > & get_prefixes() const
Definition: logstream.cc:378
unsigned int depth_console(const unsigned int n)
Definition: logstream.cc:345
void print_line_head()
Definition: logstream.cc:412
std::ostream * file
Definition: logstream.h:314
void attach(std::ostream &o, const bool print_job_id=true)
Definition: logstream.cc:217
Prefix(const std::string &text)
Definition: logstream.cc:41
std::ostream & get_console()
Definition: logstream.cc:236
bool at_newline
Definition: logstream.h:337
Threads::ThreadLocalStorage< std::shared_ptr< std::ostringstream > > outstreams
Definition: logstream.h:354
void push(const std::string &text)
Definition: logstream.cc:299
SmartPointer< LogStream, LogStream::Prefix > stream
Definition: logstream.h:127
LogStream & operator<<(std::ostream &(*p)(std::ostream &))
Definition: logstream.cc:128
void detach()
Definition: logstream.cc:228
std::ostringstream & get_stream()
Definition: logstream.cc:244
unsigned int file_depth
Definition: logstream.h:327