Reference documentation for deal.II version 9.1.0-pre
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.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/job_identifier.h>
17 #include <deal.II/base/logstream.h>
18 #include <deal.II/base/thread_management.h>
19 
20 #include <fstream>
21 #include <iomanip>
22 #include <iostream>
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 } // namespace
33 
34 
35 // The standard log object of deal.II:
36 LogStream deallog;
37 
38 
39 
40 LogStream::Prefix::Prefix(const std::string &text)
41  : stream(&deallog)
42 {
43  stream->push(text);
44 }
45 
46 
47 
48 LogStream::Prefix::Prefix(const std::string &text, LogStream &s)
49  : stream(&s)
50 {
51  stream->push(text);
52 }
53 
54 
55 
57 {
58  // destructors may not throw exceptions. if the pop() function
59  // actually does throw one, then ignore it
60  try
61  {
62  stream->pop();
63  }
64  catch (...)
65  {
66  AssertNothrow(false,
67  ExcMessage(
68  "An exception occurred in LogStream::Prefix::~Prefix."));
69  }
70 }
71 
72 
73 
75  : std_out(&std::cout)
76  , file(nullptr)
77  , std_depth(0)
78  , file_depth(10000)
79  , print_thread_id(false)
80  , at_newline(true)
81 {
82  get_prefixes().push("DEAL:");
83 }
84 
85 
86 
88 {
89  // if there was anything left in the stream that is current to this
90  // thread, make sure we flush it before it gets lost
91  {
92  if (get_stream().str().length() > 0)
93  {
94  // except the situation is not quite that simple. if this object is
95  // the 'deallog' object, then it is destroyed upon exit of the
96  // program. since it's defined in a shared library that depends on
97  // libstdc++.so, destruction happens before destruction of
98  // std::cout/cerr, but after all file variables defined in user
99  // programs have been destroyed. in other words, if we get here and
100  // the object being destroyed is 'deallog' and if 'deallog' is
101  // associated with a file stream, then we're in trouble: we'll try
102  // to write to a file that doesn't exist any more, and we're likely
103  // going to crash (this is tested by base/log_crash_01). rather
104  // than letting it come to this, print a message to the screen
105  // (note that we can't issue an assertion here either since Assert
106  // may want to write to 'deallog' itself, and AssertThrow will
107  // throw an exception that can't be caught)
108  if ((this == &deallog) && file)
109  *std_out << ("You still have content that was written to 'deallog' "
110  "but not flushed to the screen or a file while the "
111  "program is being terminated. This would lead to a "
112  "segmentation fault. Make sure you flush the "
113  "content of the 'deallog' object using 'std::endl' "
114  "before the end of the program.")
115  << std::endl;
116  else
117  *this << std::endl;
118  }
119  }
120 }
121 
122 
123 LogStream &
124 LogStream::operator<<(std::ostream &(*p)(std::ostream &))
125 {
126  std::ostringstream &stream = get_stream();
127 
128  // Print to the internal stringstream:
129  stream << p;
130 
131 
132  // This is a bloody hack until LogStream got reimplemented as a proper
133  // child of std::streambuf (or similar).
134  //
135  // The problem is that at this point we would like to know whether an
136  // std::flush or std::endl has called us, however, there is no way to
137  // detect this in a sane manner.
138  //
139  // The obvious idea to compare function pointers,
140  // std::ostream & (* const p_flush) (std::ostream &) = &std::flush;
141  // p == p_flush ? ...,
142  // is wrong as there doesn't has to be a _single_ std::flush instance...
143  // there could be multiple of it. And in fact, LLVM's libc++ implements
144  // std::flush and std::endl in a way that every shared library and
145  // executable has its local copy... fun...
146  //
147  // - Maier, 2013
148 
149  class QueryStreambuf : public std::streambuf
150  {
151  // Implement a minimalistic stream buffer that only stores the fact
152  // whether overflow or sync was called
153  public:
154  QueryStreambuf()
155  : flushed_(false)
156  , newline_written_(false)
157  {}
158  bool
159  flushed()
160  {
161  return flushed_;
162  }
163  bool
164  newline_written()
165  {
166  return newline_written_;
167  }
168 
169  private:
170  int_type
171  overflow(int_type ch) override
172  {
173  newline_written_ = true;
174  return ch;
175  }
176  int
177  sync() override
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, const bool print_job_id)
218 {
219  Threads::Mutex::ScopedLock lock(log_lock);
220  file = &o;
221  o.setf(std::ios::showpoint | std::ios::left);
222  if (print_job_id)
223  o << dealjobid();
224 }
225 
226 
227 void
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 
312 void
314 {
315  if (get_prefixes().size() > 0)
316  get_prefixes().pop();
317 }
318 
319 
320 
321 std::ios::fmtflags
322 LogStream::flags(const std::ios::fmtflags f)
323 {
324  return get_stream().flags(f);
325 }
326 
327 
328 
329 std::streamsize
330 LogStream::precision(const std::streamsize prec)
331 {
332  return get_stream().precision(prec);
333 }
334 
335 
336 
337 std::streamsize
338 LogStream::width(const std::streamsize wide)
339 {
340  return get_stream().width(wide);
341 }
342 
343 
344 
345 unsigned int
346 LogStream::depth_console(const unsigned int n)
347 {
348  Threads::Mutex::ScopedLock lock(log_lock);
349  const unsigned int h = std_depth;
350  std_depth = n;
351  return h;
352 }
353 
354 
355 
356 unsigned int
357 LogStream::depth_file(const unsigned int n)
358 {
359  Threads::Mutex::ScopedLock lock(log_lock);
360  const unsigned int h = file_depth;
361  file_depth = n;
362  return h;
363 }
364 
365 
366 
367 bool
368 LogStream::log_thread_id(const bool flag)
369 {
370  Threads::Mutex::ScopedLock lock(log_lock);
371  const bool h = print_thread_id;
372  print_thread_id = flag;
373  return h;
374 }
375 
376 
377 
378 std::stack<std::string> &
380 {
381 #ifdef DEAL_II_WITH_THREADS
382  bool exists = false;
383  std::stack<std::string> &local_prefixes = prefixes.get(exists);
384 
385  // If this is a new locally stored stack, copy the "blessed" prefixes
386  // from the initial thread that created logstream.
387  if (!exists)
388  {
389  const tbb::enumerable_thread_specific<std::stack<std::string>> &impl =
391 
392  // The thread that created this LogStream object should be the first
393  // in tbb's enumerable_thread_specific container.
394  const tbb::enumerable_thread_specific<
395  std::stack<std::string>>::const_iterator first_elem = impl.begin();
396 
397  if (first_elem != impl.end())
398  {
399  local_prefixes = *first_elem;
400  }
401  }
402 
403  return local_prefixes;
404 
405 #else
406  return prefixes.get();
407 #endif
408 }
409 
410 
411 
412 void
414 {
415  const std::string &head = get_prefix();
416  const unsigned int thread = Threads::this_thread_id();
417 
418  if (get_prefixes().size() <= std_depth)
419  {
420  if (print_thread_id)
421  *std_out << '[' << thread << ']';
422 
423  if (head.size() > 0)
424  *std_out << head << ':';
425  }
426 
427  if (file && (get_prefixes().size() <= file_depth))
428  {
429  if (print_thread_id)
430  *file << '[' << thread << ']';
431 
432  if (head.size() > 0)
433  *file << head << ':';
434  }
435 }
436 
437 DEAL_II_NAMESPACE_CLOSE
void pop()
Definition: logstream.cc:313
#define AssertNothrow(cond, exc)
Definition: exceptions.h:1278
std::streamsize precision(const std::streamsize prec)
Definition: logstream.cc:330
unsigned int this_thread_id()
const std::string & get_prefix() const
Definition: logstream.cc:286
std::ostream * std_out
Definition: logstream.h:320
Threads::ThreadLocalStorage< std::stack< std::string > > prefixes
Definition: logstream.h:313
bool print_thread_id
Definition: logstream.h:346
~LogStream() override
Definition: logstream.cc:87
unsigned int depth_file(const unsigned int n)
Definition: logstream.cc:357
STL namespace.
unsigned int std_depth
Definition: logstream.h:336
bool has_file() const
Definition: logstream.cc:278
std::streamsize width(const std::streamsize wide)
Definition: logstream.cc:338
bool log_thread_id(const bool flag)
Definition: logstream.cc:368
std::ostream & get_file_stream()
Definition: logstream.cc:267
std::stack< std::string > & get_prefixes() const
Definition: logstream.cc:379
std::ios::fmtflags flags(const std::ios::fmtflags f)
Definition: logstream.cc:322
static::ExceptionBase & ExcMessage(std::string arg1)
#define Assert(cond, exc)
Definition: exceptions.h:1227
tbb::enumerable_thread_specific< T > & get_implementation()
unsigned int depth_console(const unsigned int n)
Definition: logstream.cc:346
void print_line_head()
Definition: logstream.cc:413
std::ostream * file
Definition: logstream.h:328
SmartPointer< LogStream, LogStream::Prefix > stream
Definition: logstream.h:127
void attach(std::ostream &o, const bool print_job_id=true)
Definition: logstream.cc:217
Prefix(const std::string &text)
Definition: logstream.cc:40
std::ostream & get_console()
Definition: logstream.cc:236
bool at_newline
Definition: logstream.h:351
Threads::ThreadLocalStorage< std::shared_ptr< std::ostringstream > > outstreams
Definition: logstream.h:370
void push(const std::string &text)
Definition: logstream.cc:299
LogStream & operator<<(std::ostream &(*p)(std::ostream &))
Definition: logstream.cc:124
void detach()
Definition: logstream.cc:228
std::ostringstream & get_stream()
Definition: logstream.cc:244
unsigned int file_depth
Definition: logstream.h:341