OOFEM  2.4
OOFEM.org - Object Oriented Finite Element Solver
logger.C
Go to the documentation of this file.
1 /*
2  *
3  * ##### ##### ###### ###### ### ###
4  * ## ## ## ## ## ## ## ### ##
5  * ## ## ## ## #### #### ## # ##
6  * ## ## ## ## ## ## ## ##
7  * ## ## ## ## ## ## ## ##
8  * ##### ##### ## ###### ## ##
9  *
10  *
11  * OOFEM : Object Oriented Finite Element Code
12  *
13  * Copyright (C) 1993 - 2013 Borek Patzak
14  *
15  *
16  *
17  * Czech Technical University, Faculty of Civil Engineering,
18  * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19  *
20  * This library is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2.1 of the License, or (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * Lesser General Public License for more details.
29  *
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the Free Software
32  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33  */
34 
35 #include "logger.h"
36 #include "error.h"
37 
38 #include <cstdarg>
39 #ifdef __PARALLEL_MODE
40  #include <mpi.h>
41 #endif
42 
43 
44 #if defined ( __GNUC__ ) && defined ( HAVE_EXECINFO_H )
45  #include <cxxabi.h>
46  #include <execinfo.h>
47  #include <cstdio>
48  #include <cstdlib>
49 // Taken from https://idlebox.net/2008/0901-stacktrace-demangled/ which indicated free usage.
51 static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
52 {
53  int addrlen = 0;
54  fprintf(out, "stack trace:\n");
55 
56  // storage array for stack trace address data
57  void *addrlist [ max_frames + 1 ];
58 
59  // retrieve current stack addresses
60  addrlen = backtrace( addrlist, sizeof( addrlist ) / sizeof( void * ) );
61  if ( addrlen == 0 ) {
62  fprintf(out, " <empty, possibly corrupt>\n");
63  return;
64  }
65 
66  // resolve addresses into strings containing "filename(function+address)",
67  // this array must be free()-ed
68  char **symbollist;
69  symbollist = backtrace_symbols(addrlist, addrlen);
70  // allocate string which will be filled with the demangled function name
71  size_t funcnamesize = 256;
72  char *funcname = ( char * ) malloc(funcnamesize);
73 
74  // iterate over the returned symbol lines. skip the first, it is the
75  // address of this function.
76  for ( int i = 2; i < addrlen; i++ ) {
77  char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
78 
79  // find parentheses and +address offset surrounding the mangled name:
80  // ./module(function+0x15c) [0x8048a6d]
81  for ( char *p = symbollist [ i ]; * p; ++p ) {
82  if ( * p == '(' ) {
83  begin_name = p;
84  } else if ( * p == '+' ) {
85  begin_offset = p;
86  } else if ( * p == ')' && begin_offset ) {
87  end_offset = p;
88  break;
89  }
90  }
91 
92  if ( begin_name && begin_offset && end_offset &&
93  begin_name < begin_offset ) {
94  * begin_name++ = '\0';
95  * begin_offset++ = '\0';
96  * end_offset = '\0';
97 
98  // mangled name is now in [begin_name, begin_offset) and caller
99  // offset in [begin_offset, end_offset). now apply
100  // __cxa_demangle():
101 
102  int status;
103  char *ret = abi :: __cxa_demangle(begin_name,
104  funcname, & funcnamesize, & status);
105  if ( status == 0 ) {
106  funcname = ret; // use possibly realloc()-ed string
107  fprintf(out, " %s : %s+%s\n",
108  symbollist [ i ], funcname, begin_offset);
109  } else {
110  // demangling failed. Output function name as a C function with
111  // no arguments.
112  fprintf(out, " %s : %s()+%s\n",
113  symbollist [ i ], begin_name, begin_offset);
114  }
115  } else {
116  // couldn't parse the line? print the whole line.
117  fprintf(out, " %s\n", symbollist [ i ]);
118  }
119  }
120 
121  free(funcname);
122  free(symbollist);
123 }
124 #else
125 static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
126 {
127  fprintf(out, "No backtrace available\n");
128 }
129 #endif
130 
131 namespace oofem {
132 #define LOG_ERR_HEADER "_______________________________________________________"
133 #define LOG_ERR_TAIL "_______________________________________________________\a\n"
134 
135 // Default log output
137 
139  logStream(stdout),
140  errStream(stderr),
141  closeFlag(false),
142  errCloseFlag(false),
143  logLevel(level),
144  numberOfWrn(0),
145  numberOfErr(0)
146 #ifdef __PARALLEL_MODE
147  ,comm(MPI_COMM_SELF)
148 #endif
149 {}
150 
152 {
153  if ( this->closeFlag ) {
154  fclose(this->logStream);
155  }
156  if ( this->errCloseFlag ) {
157  fclose(this->errStream);
158  }
159 }
160 
161 void
162 Logger :: appendLogTo(const std :: string &fname)
163 {
164  FILE *stream = NULL;
165  if ( this->closeFlag ) {
166  stream = freopen(fname.c_str(), "a", this->logStream);
167  } else {
168  stream = fopen(fname.c_str(), "a");
169  }
170 
171  if ( stream == NULL ) {
172  OOFEM_WARNING( "file opening error (%s)", fname.c_str() );
173  } else {
174  this->logStream = stream;
175  }
176 
177  this->closeFlag = true;
178 }
179 
180 void
181 Logger :: appendErrorTo(const std :: string &fname)
182 {
183  FILE *stream = NULL;
184  if ( this->errCloseFlag ) {
185  stream = freopen(fname.c_str(), "a", this->errStream);
186  } else {
187  stream = fopen(fname.c_str(), "a");
188  }
189 
190  if ( stream == NULL ) {
191  OOFEM_WARNING( "file opening error (%s)", fname.c_str() );
192  } else {
193  this->errStream = stream;
194  }
195 
196  this->errCloseFlag = true;
197 }
198 
199 void
201 {
202  if ( this->closeFlag ) {
203  fclose (this->logStream);
204  }
205 
206  if ( stream == NULL ) {
207  OOFEM_ERROR( "Logger::appendLogTo : null stream given" );
208  } else {
209  this->logStream = stream;
210  }
211 
212  this->closeFlag = false;
213 }
214 
215 void
217 {
218  if ( this->errCloseFlag ) {
219  fclose (this->errStream);
220  }
221 
222  if ( stream == NULL ) {
223  OOFEM_ERROR( "Logger::appendLogTo : null stream given" );
224  } else {
225  this->errStream = stream;
226  }
227 
228  this->errCloseFlag = false;
229 }
230 
231 
232 
233 void
234 Logger :: writeLogMsg(logLevelType level, const char *format, ...)
235 {
236  int rank = 0;
237 
238 #ifdef __PARALLEL_MODE
239  MPI_Comm_rank(this->comm, & rank);
240 #endif
241  (void)rank;//prevent a warning about unused variable
242  FILE *stream = this->logStream;
243  if ( level == LOG_LEVEL_FATAL || level == LOG_LEVEL_ERROR ) {
244  numberOfErr++;
245  stream = this->errStream;
246  } else if ( level == LOG_LEVEL_WARNING ) {
247  numberOfWrn++;
248  stream = this->errStream;
249  }
250 
251 
252  // if ( rank == 0 ) {
253  if (1) {
254  va_list args;
255 
256  if ( level <= this->logLevel ) {
257  va_start(args, format);
258  vfprintf(stream, format, args);
259  va_end(args);
260  }
261  }
262 }
263 
264 void
265 Logger :: writeELogMsg(logLevelType level, const char *_func, const char *_file, int _line, const char *format, ...)
266 {
267  va_list args;
268 
269  FILE *stream = this->logStream;
270  if ( level == LOG_LEVEL_FATAL || level == LOG_LEVEL_ERROR ) {
271  numberOfErr++;
272  stream = this->errStream;
273  } else if ( level == LOG_LEVEL_WARNING ) {
274  numberOfWrn++;
275  stream = this->errStream;
276  }
277 
278  if ( level <= this->logLevel ) {
279  if ( _file ) {
280  fprintf(stream, "%s\n%s: (%s:%d)\n", LOG_ERR_HEADER, giveLevelName(level), _file, _line);
281  } else {
282  fprintf(stream, "%s\n%s:\n", LOG_ERR_HEADER, giveLevelName(level) );
283  }
284  if ( _func ) {
285  fprintf(stream, "In %s:\n", _func );
286  }
287 
288  va_start(args, format);
289  vfprintf(stream, format, args);
290  va_end(args);
291  fprintf(stream, "\n%s", LOG_ERR_TAIL);
292  }
293 
294  if ( level == LOG_LEVEL_FATAL || level == LOG_LEVEL_ERROR ) {
295  print_stacktrace(this->errStream, 10);
296  }
297 }
298 
299 const char *
301 {
302  switch ( l ) {
303  //case LOG_LEVEL_FATAL:
304  case LOG_LEVEL_ERROR:
305  return "Error";
306 
307  case LOG_LEVEL_WARNING:
308  return "Warning";
309 
310  default:
311  return "Info";
312  }
313 }
314 
315 void
317 {
318  if ( ( level >= ( int ) LOG_LEVEL_FATAL ) && ( level <= ( int ) LOG_LEVEL_DEBUG ) ) {
319  this->logLevel = ( logLevelType ) level;
320  }
321 }
322 
323 #ifdef __PARALLEL_MODE
324 void
326 {
327  this->comm = comm;
328 }
329 #endif
330 
331 void
333 {
334  int rank = 0;
335 
336 #ifdef __PARALLEL_MODE
337  MPI_Comm_rank(this->comm, & rank);
338 #endif
339 
340  int totalNumberOfErr = numberOfErr, totalNumberOfWrn = numberOfWrn;
341 #ifdef __PARALLEL_MODE
342  MPI_Reduce(& numberOfErr, & totalNumberOfErr, 1, MPI_INT, MPI_SUM, 0, this->comm);
343  MPI_Reduce(& numberOfWrn, & totalNumberOfWrn, 1, MPI_INT, MPI_SUM, 0, this->comm);
344 #endif
345  if ( rank == 0 ) {
346  // force output
347  fprintf(logStream, "Total %d error(s) and %d warning(s) reported\n", totalNumberOfErr, totalNumberOfWrn);
348  }
349 }
350 
351 } // end namespace oofem
bool errCloseFlag
Definition: logger.h:72
FILE * errStream
Definition: logger.h:70
int numberOfErr
Definition: logger.h:76
void setLogLevel(logLevelType level)
Sets log level to given one. Only log messages with level less or equal given threshold will be print...
Definition: logger.h:105
FILE * logStream
Stream used for logging.
Definition: logger.h:70
bool closeFlag
flag indicating whether to close mylogStream.
Definition: logger.h:72
void writeELogMsg(logLevelType level, const char *_func, const char *_file, int _line, const char *format,...)
Writes extended log message with file and line info.
Definition: logger.C:265
void writeLogMsg(logLevelType level, const char *format,...)
Writes the normal log message.
Definition: logger.C:234
void printStatistics()
Prints number of errors and warning logged.
Definition: logger.C:332
#define OOFEM_ERROR(...)
Definition: error.h:61
MPI_Comm comm
Parallell comm.
Definition: logger.h:79
Logger oofem_logger(Logger::LOG_LEVEL_INFO)
Definition: logger.h:115
Logger(logLevelType level)
Definition: logger.C:138
const char * giveLevelName(logLevelType l) const
Definition: logger.C:300
void appendErrorTo(const std::string &fname)
Redirects error output to given file name (with path).
Definition: logger.C:181
#define LOG_ERR_TAIL
Definition: logger.C:133
void appendLogTo(const std::string &fname)
Redirects log output to given file name (with path).
Definition: logger.C:162
static void print_stacktrace(FILE *out=stderr, unsigned int max_frames=63)
Definition: logger.C:125
logLevelType logLevel
Current log level, messages with higher level are not reported.
Definition: logger.h:74
logLevelType
Type defining basic log levels.
Definition: logger.h:60
int numberOfWrn
Counter of all warning and error messages.
Definition: logger.h:76
the oofem namespace is to define a context or scope in which all oofem names are defined.
#define LOG_ERR_HEADER
Definition: logger.C:132
#define OOFEM_WARNING(...)
Definition: error.h:62
void setComm(MPI_Comm comm)
Parallell comm.
Definition: logger.C:325

This page is part of the OOFEM documentation. Copyright (c) 2011 Borek Patzak
Project e-mail: info@oofem.org
Generated at Tue Jan 2 2018 20:07:29 for OOFEM by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2011