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