error.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2014 OpenFOAM Foundation
9  Copyright (C) 2015-2025 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 Note
28  Included by global/globals.C
29 
30 \*---------------------------------------------------------------------------*/
31 
32 #include "error.H"
33 #include "fileName.H"
34 #include "dictionary.H"
35 #include "JobInfo.H"
36 #include "UPstream.H"
37 #include "StringStream.H"
38 #include "foamVersion.H"
39 #include "OSspecific.H"
40 #include "Enum.H"
41 #include "Switch.H"
42 
43 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 
45 const Foam::Enum
46 <
48 >
50 ({
51  { handlerTypes::DEFAULT, "default" },
52  { handlerTypes::IGNORE, "ignore" },
53  { handlerTypes::WARN, "warn" },
54  { handlerTypes::STRICT, "strict" },
55 });
56 
57 
58 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
59 
60 bool Foam::error::master(const int communicator)
61 {
62  // Trap negative value for comm as 'default'. This avoids direct use
63  // of UPstream::worldComm which may have not yet been initialised
64 
65  return
66  (
68  ? (communicator < 0 ? UPstream::master() : UPstream::master(communicator))
69  : true
70  );
71 }
72 
73 
75 {
76  // No warning for 0 (unversioned) or -ve values (silent versioning)
77  return ((version > 0) && (version < foamVersion::api));
78 }
79 
80 
81 bool Foam::error::warnAboutAge(const char* what, const int version)
82 {
83  // No warning for 0 (unversioned) or -ve values (silent versioning).
84  // Also no warning for (version >= foamVersion::api), which
85  // can be used to denote future expiry dates of transition features.
86 
87  const bool old = ((version > 0) && (version < foamVersion::api));
88 
89  if (old)
90  {
91  const int months =
92  (
93  // YYMM -> months
94  (12 * (foamVersion::api/100) + (foamVersion::api % 100))
95  - (12 * (version/100) + (version % 100))
96  );
97 
98  if (version < 1000)
99  {
100  // For things that predate YYMM versioning (eg, 240 for version 2.4)
101  std::cerr
102  << " This " << what << " is very old.\n"
103  << std::endl;
104  }
105  else
106  {
107  std::cerr
108  << " This " << what << " is " << months << " months old.\n"
109  << std::endl;
110  }
111  }
112 
113  return old;
114 }
115 
116 
118 {
119  // FOAM_ABORT env set and contains bool-type value
120  return static_cast<bool>(Switch::find(Foam::getEnv("FOAM_ABORT")));
121 }
122 
123 
124 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
125 
126 Foam::error::error(const char* title)
127 :
128  std::exception(),
129  messageStream(title, messageStream::FATAL),
130  functionName_("unknown"),
131  sourceFileName_("unknown"),
132  sourceFileLineNumber_(0),
133  throwing_(false),
134  messageStreamPtr_(nullptr)
135 {}
136 
137 
138 Foam::error::error(const dictionary& errDict)
139 :
140  std::exception(),
141  messageStream(errDict),
142  functionName_(errDict.get<string>("functionName")),
143  sourceFileName_(errDict.get<string>("sourceFileName")),
144  sourceFileLineNumber_(errDict.get<label>("sourceFileLineNumber")),
145  throwing_(false),
146  messageStreamPtr_(nullptr)
147 {}
148 
149 
150 Foam::error::error(const error& err)
151 :
152  std::exception(),
153  messageStream(err),
154  functionName_(err.functionName_),
155  sourceFileName_(err.sourceFileName_),
156  sourceFileLineNumber_(err.sourceFileLineNumber_),
157  throwing_(err.throwing_),
158  messageStreamPtr_(nullptr)
159 {
160  // FIXME: OStringStream copy construct does not adjust tellp and
161  // thus the count is wrong! (#3281)
162  // // if (err.messageStreamPtr_ && (err.messageStreamPtr_->count() > 0))
163  if (err.messageStreamPtr_)
164  {
166  }
167 }
168 
169 
170 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
171 
173 {}
174 
175 
176 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
177 
178 Foam::OSstream& Foam::error::operator()
179 (
180  string functionName,
181  const char* sourceFileName,
182  const int sourceFileLineNumber
183 )
184 {
185  functionName_ = std::move(functionName);
186  sourceFileName_.clear();
187 
188  if (sourceFileName) // nullptr check
189  {
190  sourceFileName_.assign(sourceFileName);
191  }
192 
193  sourceFileLineNumber_ = sourceFileLineNumber;
194 
195  return this->stream();
196 }
197 
198 
199 Foam::OSstream& Foam::error::operator()
200 (
201  const char* functionName,
202  const char* sourceFileName,
203  const int sourceFileLineNumber
204 )
205 {
206  functionName_.clear();
207  sourceFileName_.clear();
208 
209  if (functionName) // nullptr check
210  {
211  functionName_.assign(functionName);
212  }
213  if (sourceFileName) // nullptr check
214  {
215  sourceFileName_.assign(sourceFileName);
216  }
217  sourceFileLineNumber_ = sourceFileLineNumber;
218 
219  return this->stream();
220 }
221 
222 
223 Foam::error::operator Foam::dictionary() const
224 {
225  dictionary errDict;
226 
227  string oneLineMessage(message());
228  oneLineMessage.replaceAll("\n", " ");
229 
230  errDict.add("type", word("Foam::error"));
231  errDict.add("message", oneLineMessage);
232  errDict.add("function", functionName());
233  errDict.add("sourceFile", sourceFileName());
234  errDict.add("sourceFileLineNumber", sourceFileLineNumber());
235 
236  return errDict;
237 }
238 
239 
240 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
241 
242 void Foam::error::exiting(const int errNo, const bool isAbort)
243 {
244  if (throwing_)
245  {
246  if (!isAbort)
247  {
248  // Make a copy of the error to throw
249  error errorException(*this);
250 
251  // Reset the message buffer for the next error message
252  error::clear();
253 
254  throw errorException;
255  return;
256  }
257  }
258  else if (JobInfo::constructed)
259  {
260  jobInfo.add("FatalError", operator dictionary());
261  JobInfo::shutdown(isAbort || error::useAbort());
262  }
264  simpleExit(errNo, isAbort);
265 }
266 
267 
268 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
269 
270 void Foam::error::simpleExit(const int errNo, const bool isAbort)
271 {
272  if (error::useAbort())
273  {
274  Perr<< nl << *this << nl
275  << "\nFOAM aborting (FOAM_ABORT set)\n" << endl;
277  std::abort();
278  }
279  else if (UPstream::parRun())
280  {
281  if (isAbort)
282  {
283  Perr<< nl << *this << nl
284  << "\nFOAM parallel run aborting\n" << endl;
286  UPstream::abort();
287  }
288  else
289  {
290  Perr<< nl << *this << nl
291  << "\nFOAM parallel run exiting\n" << endl;
292  UPstream::exit(errNo);
293  }
294  }
295  else
296  {
297  if (isAbort)
298  {
299  Perr<< nl << *this << nl
300  << "\nFOAM aborting\n" << endl;
302 
303  #ifdef _WIN32
304  std::exit(1); // Prefer exit() to avoid unnecessary warnings
305  #else
306  std::abort();
307  #endif
308  }
309  else
310  {
311  Perr<< nl << *this << nl
312  << "\nFOAM exiting\n" << endl;
313  std::exit(errNo);
314  }
315  }
316 }
317 
318 
319 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
320 
322 {
323  if (!messageStreamPtr_)
324  {
325  messageStreamPtr_ = std::make_unique<OStringStream>();
326  }
327  else if (!messageStreamPtr_->good())
328  {
329  Perr<< nl
330  << "error::stream() : error stream has failed"
331  << endl;
332  abort();
333  }
334 
335  return *messageStreamPtr_;
336 }
337 
338 
340 {
341  if (messageStreamPtr_)
342  {
343  return messageStreamPtr_->str();
344  }
345 
346  return string();
347 }
348 
349 
350 void Foam::error::clear() const
351 {
352  if (messageStreamPtr_)
353  {
354  messageStreamPtr_->reset();
355  }
356 }
357 
359 void Foam::error::exit(const int errNo)
360 {
361  exiting(errNo, false);
362 }
363 
365 void Foam::error::abort()
366 {
367  exiting(1, true);
368 }
369 
370 
371 void Foam::error::write(Ostream& os, const bool withTitle) const
372 {
373  if (os.bad())
374  {
375  return;
376  }
377 
378  os << nl;
379  if (withTitle && !title().empty())
380  {
381  os << title().c_str()
382  << "(openfoam-" << foamVersion::api;
383 
384  if (foamVersion::patched())
385  {
386  // Patch-level, when defined
387  os << " patch=" << foamVersion::patch.c_str();
388  }
389  os << ')' << nl;
390  }
391  os << message().c_str();
392 
393 
394  const auto lineNo = sourceFileLineNumber();
395 
396  if (messageStream::level >= 2 && lineNo && !functionName().empty())
397  {
398  os << nl << nl
399  << " From " << functionName().c_str() << nl;
400 
401  if (!sourceFileName().empty())
402  {
403  os << " in file " << sourceFileName().c_str();
404 
405  if (lineNo > 0)
406  {
407  os << " at line " << lineNo << '.';
408  }
409  }
410  }
411 }
412 
413 
414 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
415 
416 Foam::Ostream& Foam::operator<<(Ostream& os, const error& err)
417 {
418  err.write(os);
419  return os;
420 }
421 
422 
423 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
424 // Global error definitions
425 
426 Foam::error Foam::FatalError("--> FOAM FATAL ERROR: ");
427 
428 
429 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
prefixOSstream Perr
OSstream wrapped stderr (std::cerr) with parallel prefix.
Generic output stream using a standard (STL) stream.
Definition: OSstream.H:50
void clear() const
Clear any accumulated error messages.
Definition: error.C:343
bool bad() const noexcept
True if stream is corrupted.
Definition: IOstream.H:305
std::unique_ptr< OStringStream > messageStreamPtr_
Definition: error.H:91
handlerTypes
Handling of errors. The exact handling depends on the local context.
Definition: error.H:109
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
Input/output from string buffers.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
static void shutdown()
Simple shutdown (finalize) of JobInfo.
Definition: JobInfo.C:94
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1586
virtual ~error() noexcept
Destructor.
Definition: error.C:165
static bool master(const int communicator=-1)
Like Pstream::master but with a Pstream::parRun guard in case Pstream has not yet been initialised...
Definition: error.C:53
bool patched()
Test if the patch string appears to be in use, which is when it is defined (non-zero).
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:625
Handle output messages in a simple, consistent stream-based manner.
Definition: messageStream.H:70
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: POSIX.C:341
void exit(const int errNo=1)
Exit : can be called for any error to exit program.
Definition: error.C:352
static bool warnAboutAge(const int version) noexcept
Test if an age warning should be emitted.
Definition: error.C:67
Class to handle errors and exceptions in a simple, consistent stream-based manner.
Definition: error.H:70
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
static void exit(int errNo=1)
Shutdown (finalize) MPI as required and exit program with errNo.
Definition: UPstream.C:61
static bool useAbort()
True if FOAM_ABORT is on.
Definition: error.C:110
string message() const
The accumulated error message.
Definition: error.C:332
void abort()
Abort : used to stop code for fatal errors.
Definition: error.C:358
virtual void write(Ostream &os, const bool withTitle=true) const
Print error message.
Definition: error.C:364
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
const int api
OpenFOAM api number (integer) corresponding to the value of OPENFOAM at the time of compilation...
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
const direction noexcept
Definition: scalarImpl.H:255
OBJstream os(runTime.globalPath()/outputName)
Ostream & operator<<(Ostream &, const boundaryPatch &p)
Write boundaryPatch as dictionary entries (without surrounding braces)
Definition: boundaryPatch.C:77
const std::string version
OpenFOAM version (name or stringified number) as a std::string.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: error.H:64
OSstream & stream()
Return OSstream for output operations.
Definition: error.C:314
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1619
const std::string patch
OpenFOAM patch number as a std::string.
JobInfo jobInfo
Definition: JobInfo.C:45
static void printStack(Ostream &os, int size=-1)
Helper function to print a stack, with optional upper limit.
static void abort(int errNo=1)
Call MPI_Abort with no other checks or cleanup.
Definition: UPstream.C:68
A class for handling character strings derived from std::string.
Definition: string.H:72
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
Definition: StringStream.H:208
static Switch find(const std::string &str)
Find switchType for the given string, returning as a Switch that can be tested for good() or bad()...
Definition: Switch.C:147
static int level
The output level (verbosity) of messages.
static bool constructed
Global value for constructed job info.
Definition: JobInfo.H:115
error(const char *title)
Construct from title string.
Definition: error.C:119
static const Enum< handlerTypes > handlerNames
Names of the error handler types.
Definition: error.H:120
void simpleExit(const int errNo, const bool isAbort)
Exit or abort, without throwing or job control handling.
Definition: error.C:263