MercuryDPM  Trunk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Logger.cc
Go to the documentation of this file.
1 //Copyright (c) 2013-2020, The MercuryDPM Developers Team. All rights reserved.
2 //For the list of developers, see <http://www.MercuryDPM.org/Team>.
3 //
4 //Redistribution and use in source and binary forms, with or without
5 //modification, are permitted provided that the following conditions are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // * Neither the name MercuryDPM nor the
12 // names of its contributors may be used to endorse or promote products
13 // derived from this software without specific prior written permission.
14 //
15 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 //DISCLAIMED. IN NO EVENT SHALL THE MERCURYDPM DEVELOPERS TEAM BE LIABLE FOR ANY
19 //DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 //(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 //ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #include "Logger.h"
27 
28 #ifdef MERCURY_STACKTRACE_SHOW
29 //To create stacktraces, we need the
30 // backtrace(3)
31 //function calls.. (really, we don't want to do this by hand)
32 #include <execinfo.h>
33 
34 #ifdef MERCURY_STACKTRACE_DEMANGLE
35 //However, we would end up with mangled function names...
36 //So, instead we'll use the abi::__cxa_demangle function call..
37 #include <cxxabi.h>
38 //Oh, and we really want to get the function names as well..
39 #include <dlfcn.h>
40 #endif
41 
42 #endif
43 
44 #include <cstdlib>
45 #include <iostream>
46 #include <csignal>
47 
59 
60 
64 /* Actual definition of the default logger. */
65 Logger<MERCURY_LOGLEVEL> logger("MercuryKernel");
66 /* Actual definition of the default logger. */
67 Logger<CG_LOGLEVEL> cgLogger("MercuryCG");
68 
76 static void printInfo(std::string module, std::string msg, Flusher doFlush)
77 {
78 #ifdef MERCURY_USE_MPI
79  //Check if MPI is initialised
80  initialiseMPI();
81  MPIContainer& communicator = MPIContainer::Instance();
82  std::cout << "[Process: " << communicator.getProcessorID() << "]: " << msg;
83  if (doFlush == Flusher::FLUSH)
84  {
85  std::cout << std::endl;
86  }
87 #else
88  std::cout << msg;
89  if (doFlush == Flusher::FLUSH)
90  {
91  std::cout << std::endl;
92  }
93 #endif
94 }
95 
103 static void printMessage(std::string module, std::string msg, Flusher doFlush)
104 {
105 #ifdef MERCURY_USE_MPI
106  //Check if MPI is initialised
107  initialiseMPI();
108  MPIContainer& communicator = MPIContainer::Instance();
109  std::cout << "\033[1;33mModule " << module << ":\033[0m\n" << "[Processor: " << communicator.getProcessorID() << "]" << msg;
110  if (doFlush == Flusher::FLUSH)
111  {
112  std::cout << std::endl;
113  }
114 #else
115  std::cout << "\033[1;33mMessage " << module << ":\033[0m\n" << msg;
116  if (doFlush == Flusher::FLUSH)
117  {
118  std::cout << std::endl;
119  }
120 #endif
121 }
122 
130 [[noreturn]] static void printError(std::string module, std::string msg, Flusher doFlush)
131 {
132 #ifdef MERCURY_USE_MPI
133  //Check if MPI is initialised
134  initialiseMPI();
135  MPIContainer& communicator = MPIContainer::Instance();
136  std::cout << "\033[1;33mError " << module << ":\033[0m\n" << "[Processor: " << communicator.getProcessorID() << "]" << msg << std::endl;
137 #else
138  std::cout << "\033[1;31mAn error has occured"
139  << "\n\033[1;31mModule :" << module
140  << "\n\033[1;31mMessage :" << msg << std::endl;
141 #endif
142 #ifdef MERCURY_STACKTRACE_SHOW
143  std::cerr << "\n-----------------[Stack Trace]-----------------\n";
144 
145  void* stackBuffer[64]; //This should be enough for all purposes..
146  //First, we retrieve the addresses of the entire stack...
147  int nStackFrames = backtrace(stackBuffer, 64);
148 #ifndef MERCURY_STACKTRACE_DEMANGLE
149  //We don't have the demangling infra, so just use backtrace_symbols.
150  char** functionNames = backtrace_symbols(stackBuffer, nStackFrames);
151  for( int i = 0; i < nStackFrames; i++ )
152  {
153  std::cerr << '\t' << functionNames[i] << '\n';
154  }
155  std::cerr << "Exiting.\n" << std::endl;
156 
157  //DO NOT USE DELETE HERE. THIS SHOULD BE free()'d!
158  // -- dducks
159  free(functionNames);
160 #else
161  //We request the symbol information ourselves, in order to be able to demangle it.
162  //And request the function names using dladdr.
163  Dl_info infoStruct;
164  for (int i = 4; i < nStackFrames; i++)
165  {
166  if (dladdr(stackBuffer[i], &infoStruct))
167  { // We succesfully loaded the address...
168  int demangleStatus;
169  char* fnDemangled = abi::__cxa_demangle(infoStruct.dli_sname, NULL, NULL, &demangleStatus);
170  if (infoStruct.dli_sname == nullptr)
171  continue;
172 
173  //We even succesfully demangled the symbol...
174  if (demangleStatus == 0)
175  {
176  std::cerr << fnDemangled << " +" << (void*) ((char*) stackBuffer[i] - (char*) infoStruct.dli_saddr) << "\t(" << infoStruct.dli_fname << ")\n";
177  free(fnDemangled);
178  }
179  else
180  { //Well, we tried. Lets output at least our raw symbol name.
181  std::cerr << infoStruct.dli_sname << " +" << (void*) ((char*) stackBuffer[i] - (char*) infoStruct.dli_saddr) << "\t(" << infoStruct.dli_fname << ")\n";
182  }
183  }
184  else
185  { //Name lookup failed.
186  std::cerr << stackBuffer[i] << ": ?????" << std::endl;
187  }
188  }
189 #endif
190 #endif
191  //send a signal first, in case a debugger can catch it
192  std::raise(SIGTERM);
193  //call exit() for the specific loglevel
194  std::exit(static_cast<int>(Log::ERROR));
195 }
196 
204 // Default implementation for logging errors / fatals
205 // [[noreturn]] indicates this function may not return
206 [[noreturn]] static void printFatalError(const std::string& module, const std::string& msg, Flusher doFlush)
207 {
208 #ifdef MERCURY_USE_MPI
209  //Check if MPI is initialised
210  initialiseMPI();
211  MPIContainer& communicator = MPIContainer::Instance();
212  std::cout << "\033[1;33mError " << module << ":\033[0m\n" << "[Processor: " << communicator.getProcessorID() << "]" << msg << std::endl;
213 #else
214  std::cout << "\033[1;31mA fatal error has occured"
215  << "\n\033[1;31mModule :" << module
216  << "\n\033[1;31mMessage :" << msg << std::endl;
217 #endif
218 #ifdef MERCURY_STACKTRACE_SHOW
219  std::cerr << "\n-----------------[Stack Trace]-----------------\n";
220 
221  void* stackBuffer[64]; //This should be enough for all purposes..
222  //First, we retrieve the addresses of the entire stack...
223  int nStackFrames = backtrace(stackBuffer, 64);
224 #ifndef MERCURY_STACKTRACE_DEMANGLE
225  //We don't have the demangling infra, so just use backtrace_symbols.
226  char** functionNames = backtrace_symbols(stackBuffer, nStackFrames);
227  for( int i = 0; i < nStackFrames; i++ )
228  {
229  std::cerr << '\t' << functionNames[i] << '\n';
230  }
231  std::cerr << "Exiting.\n" << std::endl;
232 
233  //DO NOT USE DELETE HERE. THIS SHOULD BE free()'d!
234  // -- dducks
235  free(functionNames);
236 #else
237  //We request the symbol information ourselves, in order to be able to demangle it.
238  //And request the function names using dladdr.
239  Dl_info infoStruct;
240  for (int i = 4; i < nStackFrames; i++)
241  {
242  if (dladdr(stackBuffer[i], &infoStruct))
243  { // We succesfully loaded the address...
244  int demangleStatus;
245  char* fnDemangled = abi::__cxa_demangle(infoStruct.dli_sname, NULL, NULL, &demangleStatus);
246  if (infoStruct.dli_sname == nullptr)
247  continue;
248 
249  //We even succesfully demangled the symbol...
250  if (demangleStatus == 0)
251  {
252  std::cerr << fnDemangled << " +" << (void*) ((char*) stackBuffer[i] - (char*) infoStruct.dli_saddr) << "\t(" << infoStruct.dli_fname << ")\n";
253  free(fnDemangled);
254  }
255  else
256  { //Well, we tried. Lets output at least our raw symbol name.
257  std::cerr << infoStruct.dli_sname << " +" << (void*) ((char*) stackBuffer[i] - (char*) infoStruct.dli_saddr) << "\t(" << infoStruct.dli_fname << ")\n";
258  }
259  }
260  else
261  { //Name lookup failed.
262  std::cerr << stackBuffer[i] << ": ?????" << std::endl;
263  }
264  }
265 #endif
266 #endif
267  //send a signal first, in case a debugger can catch it
268  std::raise(SIGTERM);
269  //call exit for the specific loglevel
270  std::exit(static_cast<int>(Log::FATAL));
271 }
272 
273 // Default output methods.
275  printError, //onError
276  printMessage, //onWarn
277  printInfo, //onInfo
278  printInfo, //onVerbose
279  printMessage //onDebug
280 };
281 
282 //And we assign them.
the Logger class is the main class of the logger implementation. It holds all the functions which inv...
Definition: Logger.h:183
This class contains all information and functions required for communication between processors...
Definition: MpiContainer.h:129
static void printInfo(std::string module, std::string msg, Flusher doFlush)
Prints messages of loglevel INFO.
Definition: Logger.cc:76
static void printMessage(std::string module, std::string msg, Flusher doFlush)
Prints messages of loglevel WARN.
Definition: Logger.cc:103
static MPIContainer & Instance()
fetch the instance to be used for communication
Definition: MpiContainer.h:134
LL< Log::DEBUG > DEBUG
Debug information.
Definition: Logger.cc:58
Logger< MERCURY_LOGLEVEL > logger("MercuryKernel")
Definition of different loggers with certain modules. A user can define its own custom logger here...
LL< Log::INFO > INFO
Info log level.
Definition: Logger.cc:55
const std::complex< Mdouble > i
Definition: ExtendedMath.h:51
LoggerOutput loggerOutputDefaultImpl
Definition: Logger.cc:274
LL< Log::ERROR > ERROR
Error log level.
Definition: Logger.cc:53
void initialiseMPI()
Inialises the MPI library.
static void printFatalError(const std::string &module, const std::string &msg, Flusher doFlush)
Prints messages of loglevel FATAL.
Definition: Logger.cc:206
std::size_t getProcessorID()
Reduces a scalar on all processors to one scalar on a target processor.
LL< Log::WARN > WARN
Warning log level.
Definition: Logger.cc:54
Default functions for output generation.
Definition: Logger.h:160
LL< Log::DEFAULT > DEFAULT
Default log level.
Definition: Logger.cc:56
LL< Log::FATAL > FATAL
Definition of the different loglevels by its wrapper class LL. These are used as tags in template met...
Definition: Logger.cc:52
LL< Log::VERBOSE > VERBOSE
Verbose information.
Definition: Logger.cc:57
LoggerOutput * loggerOutput
Declaration of the output functions.
Definition: Logger.cc:283
static void printError(std::string module, std::string msg, Flusher doFlush)
Prints messages of loglevel ERROR.
Definition: Logger.cc:130
Flusher
The Logger class provides ability to write log messages in your own customized format.
Definition: Logger.h:118
Logger< CG_LOGLEVEL > cgLogger("MercuryCG")
Tag for template metaprogramming.
Definition: Logger.h:198