xerus
a general purpose tensor library
namedLogger.h
Go to the documentation of this file.
1 // Xerus - A General Purpose Tensor Library
2 // Copyright (C) 2014-2017 Benjamin Huber and Sebastian Wolf.
3 //
4 // Xerus is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as published
6 // by the Free Software Foundation, either version 3 of the License,
7 // or (at your option) any later version.
8 //
9 // Xerus is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
13 //
14 // You should have received a copy of the GNU Affero General Public License
15 // along with Xerus. If not, see <http://www.gnu.org/licenses/>.
16 //
17 // For further information on Xerus visit https://libXerus.org
18 // or contact us at contact@libXerus.org.
19 
25 #pragma once
26 
27 #include <mutex>
28 #include <string>
29 #include <sstream>
30 
31 #include "callStack.h"
32 #include "exceptions.h"
33 
34 #ifdef XERUS_LOGFILE
35  #include <fstream>
36  #define XERUS_LOGSTREAM xerus::misc::internal::get_fileStream()
37 #else
38  #include <iostream>
39  #define XERUS_LOGSTREAM std::cerr
40 #endif
41 
42 namespace xerus {
43  namespace misc {
44  namespace internal {
49  constexpr uint64_t log_namehash(const char* x) {
50  return *x ? (uint64_t(*x) ^ xerus::misc::internal::log_namehash(x+1))*0x100000001B3ul : 0xCBF29CE484222325ul;
51  }
52 
53  void log_timestamp(std::ostream &_out, const char* _file, int _line, const char* _lvl);
54  void log_timestamp(std::ostream &_out, const char* _lvl);
55  void log_timestamp(std::ostream &_out);
56  std::ostream &get_fileStream();
57 
58  // If the LOG_BUFFER is active there is the additional option only to print the log if an error occours.
59  #ifdef XERUS_LOG_BUFFER
60  enum {
61  NOT_LOGGING = 0,
62  LOGGING_ON_ERROR = 1,
63  LOGGING_FULL = 2,
65  };
66  #else
67  enum {
71  };
72  static const auto LOGGING_ON_ERROR = NOT_LOGGING;
73  #endif
74 
75  extern std::mutex namedLoggerMutex;
76  extern std::string logFilePrefix;
77  extern bool silenced;
78  extern std::chrono::system_clock::time_point programStartTime;
79 
80  namespace buffer {
81  extern std::stringstream current;
82  extern std::stringstream old;
83 
84  void checkSwitch();
85 
86  void dump_log(std::string _comment);
87  }
88  }
89  }
90 }
91 
92 #define XERUS_STRINGIFY2( x) #x
93 #define XERUS_STRINGIFY(x) XERUS_STRINGIFY2(x)
94 
95 
100 #define XERUS_COMPILE_TIME_EVAL(e) (std::integral_constant<decltype(e), e>::value)
101 
102 
103 // in the following note that:
104 // - everything is piped into a stringstream for two reasons: 1. so that functions appearing in msg will only be executed once
105 // 2. so that buffer(pointers) can be piped as usual even though they empty the buffer while being piped
106 // - in performance critical programs logging should be disabled completely, the mutex in the following code will block the whole function. a read/write mutex could
107 // increase performance a bit (by only making sure that the delete inside checkSwitch is not called while another thread is piping something) and the mutex
108 // in the LOG_NO_BUFFER version could be disabled completely (the streams are thread"safe" (only the output will be jumbled a bit)
109 
110 #ifdef XERUS_LOG_BUFFER
111  #define XERUS_NAMED_LOGGER_LOGBUFFER(lvl) \
112  if (::xerus::misc::internal::LogFlag<xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))>::flag != xerus::misc::internal::NOT_LOGGING && !xerus::misc::internal::silenced) { \
113  ::xerus::misc::internal::log_timestamp(xerus::misc::internal::buffer::current, __FILE__, __LINE__, XERUS_STRINGIFY(lvl)); \
114  xerus::misc::internal::buffer::current << tmpStream.str(); \
115  xerus::misc::internal::buffer::checkSwitch(); \
116  if (XERUS_COMPILE_TIME_EVAL(xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))==xerus::misc::internal::log_namehash("error"))) { \
117  xerus::misc::internal::buffer::dump_log(std::string("error invoked:\n")+tmpStream.str()); \
118  } \
119  if (XERUS_COMPILE_TIME_EVAL(xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))==xerus::misc::internal::log_namehash("critical"))) { \
120  xerus::misc::internal::buffer::dump_log(std::string("critical error invoked:\n")+tmpStream.str()); \
121  } \
122  if (XERUS_COMPILE_TIME_EVAL(xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))==xerus::misc::internal::log_namehash("fatal"))) { \
123  xerus::misc::internal::buffer::dump_log(std::string("fatal error invoked:\n")+tmpStream.str()); \
124  } \
125  }
126 #else // no log buffer
127  #define XERUS_NAMED_LOGGER_LOGBUFFER(lvl)
128 #endif
129 
130 
131 
132 
139 #define XERUS_LOG(lvl, ...) \
140  if (::xerus::misc::internal::LogFlag<xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))>::flag != xerus::misc::internal::NOT_LOGGING) { \
141  std::stringstream tmpStream; \
142  tmpStream << __VA_ARGS__ << std::endl; \
143  xerus::misc::internal::namedLoggerMutex.lock(); \
144  if (::xerus::misc::internal::LogFlag<xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))>::flag == xerus::misc::internal::LOGGING_FULL && !xerus::misc::internal::silenced) { \
145  ::xerus::misc::internal::log_timestamp(XERUS_LOGSTREAM, __FILE__, __LINE__, XERUS_STRINGIFY(lvl)); \
146  XERUS_LOGSTREAM << tmpStream.str() << std::flush; \
147  } \
148  XERUS_NAMED_LOGGER_LOGBUFFER(lvl) \
149  xerus::misc::internal::namedLoggerMutex.unlock(); \
150  if (::xerus::misc::internal::LogFlag<xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))>::flag == xerus::misc::internal::LOGGING_EXCEPTION ) { \
151  XERUS_THROW(xerus::misc::generic_error() << __FILE__ << ":" << __LINE__ << ": " XERUS_STRINGIFY(lvl) " invoked:\n" << tmpStream.str() << "callstack:\n" << xerus::misc::get_call_stack()); \
152  } \
153  } else \
154  (void)0
155 
162 #define XERUS_LOG_SHORT(lvl, ...) \
163  if (::xerus::misc::internal::LogFlag<xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))>::flag != xerus::misc::internal::NOT_LOGGING) { \
164  std::stringstream tmpStream; \
165  tmpStream << __VA_ARGS__ << std::endl; \
166  xerus::misc::internal::namedLoggerMutex.lock(); \
167  if (::xerus::misc::internal::LogFlag<xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))>::flag == xerus::misc::internal::LOGGING_FULL && !xerus::misc::internal::silenced) { \
168  ::xerus::misc::internal::log_timestamp(XERUS_LOGSTREAM, XERUS_STRINGIFY(lvl)); \
169  XERUS_LOGSTREAM << tmpStream.str() << std::flush; \
170  } \
171  XERUS_NAMED_LOGGER_LOGBUFFER(lvl) \
172  xerus::misc::internal::namedLoggerMutex.unlock(); \
173  if (::xerus::misc::internal::LogFlag<xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))>::flag == xerus::misc::internal::LOGGING_EXCEPTION ) { \
174  XERUS_THROW(xerus::misc::generic_error() << XERUS_STRINGIFY(lvl) " error invoked:\n" << tmpStream.str() << "callstack:\n" << xerus::misc::get_call_stack()); \
175  } \
176  } else \
177  (void)0
178 
185 #define XERUS_LOG_ONCE(lvl, ...) \
186  {\
187  static bool logged = false;\
188  if (!logged) {\
189  XERUS_LOG(lvl, __VA_ARGS__);\
190  logged = true;\
191  }\
192  }
193 
198 #define XERUS_IS_LOGGING(lvl) \
199  (::xerus::misc::internal::LogFlag<xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))>::flag != xerus::misc::internal::NOT_LOGGING)
200 
201 
202 namespace xerus { namespace misc { namespace internal {
203  template<uint64_t lvl> struct LogFlag { static const int flag = xerus::misc::internal::LOGGING_FULL; };
204 }}}
205 
211 #define XERUS_SET_LOGGING(lvl, value) \
212  namespace xerus { namespace misc { namespace internal { \
213  template<> struct LogFlag<xerus::misc::internal::log_namehash(XERUS_STRINGIFY(lvl))>{ static const int flag = value; }; \
214  }}}
215 
216 
217 
218 // Default log levels
219 #define XERUS_SET_DEFAULT_LOG_LEVELS \
220  XERUS_SET_LOGGING(fatal, xerus::misc::internal::LOGGING_EXCEPTION)\
221  XERUS_SET_LOGGING(critical, xerus::misc::internal::LOGGING_EXCEPTION)\
222  XERUS_SET_LOGGING(error, xerus::misc::internal::LOGGING_EXCEPTION)\
223  XERUS_SET_LOGGING(warning, xerus::misc::internal::LOGGING_FULL)\
224  XERUS_SET_LOGGING(info, xerus::misc::internal::LOGGING_FULL)\
225  XERUS_SET_LOGGING(debug, xerus::misc::internal::LOGGING_ON_ERROR)
226 
227 #ifdef XERUS_LOG_ERROR
228 #undef XERUS_SET_DEFAULT_LOG_LEVELS
229 #define XERUS_SET_DEFAULT_LOG_LEVELS \
230  XERUS_SET_LOGGING(fatal, xerus::misc::internal::LOGGING_EXCEPTION)\
231  XERUS_SET_LOGGING(critical, xerus::misc::internal::LOGGING_EXCEPTION)\
232  XERUS_SET_LOGGING(error, xerus::misc::internal::LOGGING_EXCEPTION)\
233  XERUS_SET_LOGGING(warning, xerus::misc::internal::LOGGING_ON_ERROR)\
234  XERUS_SET_LOGGING(info, xerus::misc::internal::LOGGING_ON_ERROR)\
235  XERUS_SET_LOGGING(debug, xerus::misc::internal::LOGGING_ON_ERROR)
236 #endif
237 
238 #ifdef XERUS_LOG_WARNING
239 #undef XERUS_SET_DEFAULT_LOG_LEVELS
240 #define XERUS_SET_DEFAULT_LOG_LEVELS \
241  XERUS_SET_LOGGING(fatal, xerus::misc::internal::LOGGING_EXCEPTION)\
242  XERUS_SET_LOGGING(critical, xerus::misc::internal::LOGGING_EXCEPTION)\
243  XERUS_SET_LOGGING(error, xerus::misc::internal::LOGGING_EXCEPTION)\
244  XERUS_SET_LOGGING(warning, xerus::misc::internal::LOGGING_FULL)\
245  XERUS_SET_LOGGING(info, xerus::misc::internal::LOGGING_ON_ERROR)\
246  XERUS_SET_LOGGING(debug, xerus::misc::internal::LOGGING_ON_ERROR)
247 #endif
248 
249 #ifdef XERUS_LOG_INFO
250 #undef XERUS_SET_DEFAULT_LOG_LEVELS
251 #define XERUS_SET_DEFAULT_LOG_LEVELS \
252  XERUS_SET_LOGGING(fatal, xerus::misc::internal::LOGGING_EXCEPTION)\
253  XERUS_SET_LOGGING(critical, xerus::misc::internal::LOGGING_EXCEPTION)\
254  XERUS_SET_LOGGING(error, xerus::misc::internal::LOGGING_EXCEPTION)\
255  XERUS_SET_LOGGING(warning, xerus::misc::internal::LOGGING_FULL)\
256  XERUS_SET_LOGGING(info, xerus::misc::internal::LOGGING_FULL)\
257  XERUS_SET_LOGGING(debug, xerus::misc::internal::LOGGING_ON_ERROR)
258 #endif
259 
260 #ifdef XERUS_LOG_DEBUG
261 #undef XERUS_SET_DEFAULT_LOG_LEVELS
262 #define XERUS_SET_DEFAULT_LOG_LEVELS \
263  XERUS_SET_LOGGING(fatal, xerus::misc::internal::LOGGING_EXCEPTION)\
264  XERUS_SET_LOGGING(critical, xerus::misc::internal::LOGGING_EXCEPTION)\
265  XERUS_SET_LOGGING(error, xerus::misc::internal::LOGGING_EXCEPTION)\
266  XERUS_SET_LOGGING(warning, xerus::misc::internal::LOGGING_FULL)\
267  XERUS_SET_LOGGING(info, xerus::misc::internal::LOGGING_FULL)\
268  XERUS_SET_LOGGING(debug, xerus::misc::internal::LOGGING_FULL)
269 #endif
270 
std::string logFilePrefix
Definition: namedLogger.cpp:39
void dump_log(std::string _comment)
std::ostream & get_fileStream()
Definition: namedLogger.cpp:81
The main namespace of xerus.
Definition: basic.h:37
constexpr uint64_t log_namehash(const char *x)
Hashes a given c-string using the FNV-1a standard hash.
Definition: namedLogger.h:49
Header file for the call-stack functionality.
Header file for xerus::misc::generic_error exception class.
static const auto LOGGING_ON_ERROR
Definition: namedLogger.h:72
std::mutex namedLoggerMutex
Definition: namedLogger.cpp:38
#define XERUS_SET_DEFAULT_LOG_LEVELS
Definition: namedLogger.h:219
void log_timestamp(std::ostream &_out, const char *_file, int _line, const char *_lvl)
Definition: namedLogger.cpp:67
std::chrono::system_clock::time_point programStartTime
Definition: namedLogger.cpp:41