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 
48 /*
49  * We need these to actually exists. These are used as tags in the template metaprogramming for
50  * the Logger class.
51  */
59 
60 /* Actual definition of the default logger. */
61 Logger<MERCURY_LOGLEVEL> logger("MercuryKernel");
62 /* Actual definition of the default logger. */
63 Logger<CG_LOGLEVEL> cgLogger("MercuryCG");
64 
65 
66 // Default implementation for logging basic information
67 static void printInfo(std::string module, std::string msg)
68 {
69 #ifdef MERCURY_USE_MPI
70  //Check if MPI is initialised
71  initialiseMPI();
72  MPIContainer& communicator = MPIContainer::Instance();
73  std::cout << "[Process: " << communicator.getProcessorID() << "]: " << msg << std::endl;
74 #else
75  std::cout << msg << std::endl;
76 #endif
77 }
78 
79 // Default implementation for logging warnings / messages
80 static void printMessage(std::string module, std::string msg)
81 {
82 #ifdef MERCURY_USE_MPI
83  //Check if MPI is initialised
84  initialiseMPI();
85  MPIContainer& communicator = MPIContainer::Instance();
86  std::cout << "\033[1;33mModule " << module << ":\033[0m\n" << "[Processor: " << communicator.getProcessorID() << "]" << msg << std::endl;
87 #else
88  std::cout << "\033[1;33mMessage " << module << ":\033[0m\n" << msg << std::endl;
89 #endif
90 }
91 
92 // Default implementation for logging errors / fatals
93 // [[noreturn]] indicates this function may not return
94 [[noreturn]] static void printError(std::string module, std::string msg)
95 {
96 #ifdef MERCURY_USE_MPI
97  //Check if MPI is initialised
98  initialiseMPI();
99  MPIContainer& communicator = MPIContainer::Instance();
100  std::cout << "\033[1;33mError " << module << ":\033[0m\n" << "[Processor: " << communicator.getProcessorID() << "]" << msg << std::endl;
101 #else
102  std::cout << "\033[1;31mError " << module << ":\033[0m\n" << msg << std::endl;
103 #endif
104 #ifdef MERCURY_STACKTRACE_SHOW
105  std::cerr << "\n-----------------[Stack Trace]-----------------\n";
106 
107  void* stackBuffer[64]; //This should be enough for all purposes..
108  //First, we retrieve the addresses of the entire stack...
109  int nStackFrames = backtrace(stackBuffer, 64);
110 #ifndef MERCURY_STACKTRACE_DEMANGLE
111  //We don't have the demangling infra, so just use backtrace_symbols.
112  char** functionNames = backtrace_symbols(stackBuffer, nStackFrames);
113  for( int i = 0; i < nStackFrames; i++ )
114  {
115  std::cerr << '\t' << functionNames[i] << '\n';
116  }
117  std::cerr << "Exiting.\n" << std::endl;
118 
119  //DO NOT USE DELETE HERE. THIS SHOULD BE free()'d!
120  // -- dducks
121  free(functionNames);
122 #else
123  //We request the symbol information ourselves, in order to be able to demangle it.
124  //And request the function names using dladdr.
125  Dl_info infoStruct;
126  for (int i = 4; i < nStackFrames; i++)
127  {
128  if (dladdr(stackBuffer[i], &infoStruct))
129  { // We succesfully loaded the address...
130  int demangleStatus;
131  char* fnDemangled = abi::__cxa_demangle(infoStruct.dli_sname, NULL, NULL, &demangleStatus);
132  if (infoStruct.dli_sname == nullptr)
133  continue;
134 
135  //We even succesfully demangled the symbol...
136  if (demangleStatus == 0)
137  {
138  std::cerr << fnDemangled << " +" << (void*) ((char*) stackBuffer[i] - (char*) infoStruct.dli_saddr) << "\t(" << infoStruct.dli_fname << ")\n";
139  free(fnDemangled);
140  }
141  else
142  { //Well, we tried. Lets output at least our raw symbol name.
143  std::cerr << infoStruct.dli_sname << " +" << (void*) ((char*) stackBuffer[i] - (char*) infoStruct.dli_saddr) << "\t(" << infoStruct.dli_fname << ")\n";
144  }
145  }
146  else
147  { //Name lookup failed.
148  std::cerr << stackBuffer[i] << ": ?????" << std::endl;
149  }
150  }
151 #endif
152 #endif
153  //send a signal first, in case a debugger can catch it
154  std::raise(SIGTERM);
155  std::exit(2);
156 }
157 
158 // Default output methods.
160  printError, //onError
161  printMessage, //onWarn
162  printInfo, //onInfo
163  printInfo, //onVerbose
164  printMessage //onDebug
165 };
166 
167 //And we assign them.
See.
Definition: Logger.h:215
This class contains all information and functions required for communication between processors...
Definition: MpiContainer.h:125
static MPIContainer & Instance()
fetch the instance to be used for communication
Definition: MpiContainer.h:130
static void printError(std::string module, std::string msg)
Definition: Logger.cc:94
LL< Log::DEBUG > DEBUG
Debug information.
Definition: Logger.cc:58
Logger< MERCURY_LOGLEVEL > logger("MercuryKernel")
LL< Log::INFO > INFO
Info log level.
Definition: Logger.cc:55
const std::complex< Mdouble > i
Definition: ExtendedMath.h:50
static void printInfo(std::string module, std::string msg)
Definition: Logger.cc:67
LoggerOutput loggerOutputDefaultImpl
Definition: Logger.cc:159
LL< Log::ERROR > ERROR
Error log level.
Definition: Logger.cc:53
void initialiseMPI()
Inialises the MPI library.
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
static void printMessage(std::string module, std::string msg)
Definition: Logger.cc:80
Default functions for output generation.
Definition: Logger.h:192
LL< Log::DEFAULT > DEFAULT
Default log level.
Definition: Logger.cc:56
LL< Log::FATAL > FATAL
Fatal log level.
Definition: Logger.cc:52
LL< Log::VERBOSE > VERBOSE
Verbose information.
Definition: Logger.cc:57
LoggerOutput * loggerOutput
Declaration of the output functions. If the output needs to be redirected, please swap the loggerOutp...
Definition: Logger.cc:168
Logger< CG_LOGLEVEL > cgLogger("MercuryCG")
Tag for template metaprogramming.
Definition: Logger.h:227