OmniSciDB  1dac507f6e
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Logger.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 OmniSci, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * @file Logger.h
19  * @author Matt Pulver <matt.pulver@omnisci.com>
20  * @description Use Boost.Log for logging data compatible with previous API.
21  *
22  * Usage:
23  * - Initialize a LogOptions object. E.g.
24  * logger::LogOptions log_options(argv[0]);
25  * - LogOptions can optionally be added to boost::program_options:
26  * help_desc.add(log_options.get_options());
27  * - Initialize global logger once per application:
28  * logger::init(log_options);
29  * - From anywhere in the program:
30  * - LOG(INFO) << "Nice query!";
31  * - LOG(DEBUG4) << "x = " << x;
32  * - CHECK(condition);
33  * - CHECK_LE(x, xmax);
34  * Newlines are automatically appended to log messages.
35  */
36 
37 #ifndef SHARED_LOGGER_H
38 #define SHARED_LOGGER_H
39 
40 #ifndef __CUDACC__
41 
42 #include <boost/config.hpp>
43 #include <boost/filesystem.hpp>
44 #include <boost/log/common.hpp>
45 #include <boost/program_options.hpp>
46 
47 #include <memory>
48 #include <set>
49 
50 #endif
51 
52 #include <array>
53 #include <sstream>
54 #include <thread>
55 
56 extern bool g_enable_debug_timer;
57 
58 namespace logger {
59 
60 // Channel, ChannelNames, and ChannelSymbols must be updated together.
61 enum Channel { IR = 0, PTX, _NCHANNELS };
62 
63 constexpr std::array<char const*, 2> ChannelNames{"IR", "PTX"};
64 
65 constexpr std::array<char, 2> ChannelSymbols{'R', 'P'};
66 
67 static_assert(Channel::_NCHANNELS == ChannelNames.size(),
68  "Size of ChannelNames must equal number of Channels.");
69 static_assert(Channel::_NCHANNELS == ChannelSymbols.size(),
70  "Size of ChannelSymbols must equal number of Channels.");
71 
72 // Severity, SeverityNames, and SeveritySymbols must be updated together.
73 enum Severity {
74  DEBUG4 = 0,
82  _NSEVERITIES // number of severity levels
83 };
84 
85 constexpr std::array<char const*, 8> SeverityNames{"DEBUG4",
86  "DEBUG3",
87  "DEBUG2",
88  "DEBUG1",
89  "INFO",
90  "WARNING",
91  "ERROR",
92  "FATAL"};
93 
94 constexpr std::array<char, 8> SeveritySymbols{'4', '3', '2', '1', 'I', 'W', 'E', 'F'};
95 
96 static_assert(Severity::_NSEVERITIES == SeverityNames.size(),
97  "Size of SeverityNames must equal number of Severity levels.");
98 static_assert(Severity::_NSEVERITIES == SeveritySymbols.size(),
99  "Size of SeveritySymbols must equal number of Severity levels.");
100 
101 #ifndef __CUDACC__
102 
103 using Channels = std::set<Channel>;
104 
105 // Filled by boost::program_options
106 class LogOptions {
107  std::string base_path_{"."}; // ignored if log_dir_ is absolute.
108  boost::program_options::options_description options_;
109 
110  public:
111  // Initialize to default values
112  boost::filesystem::path log_dir_{"mapd_log"};
113  // file_name_pattern and symlink are prepended with base_name.
114  std::string file_name_pattern_{".{SEVERITY}.%Y%m%d-%H%M%S.log"};
115  std::string symlink_{".{SEVERITY}"};
119  bool auto_flush_{true};
120  size_t max_files_{100};
121  size_t min_free_space_{20 << 20};
122  bool rotate_daily_{true};
123  size_t rotation_size_{10 << 20};
124 
125  LogOptions(char const* argv0);
126  boost::filesystem::path full_log_dir() const;
127  boost::program_options::options_description const& get_options() const;
128  void parse_command_line(int, char const* const*);
129  void set_base_path(std::string const& base_path);
130 };
131 
132 // Execute once in main() to initialize boost loggers.
133 void init(LogOptions const&);
134 
135 // Flush all sinks.
136 // https://www.boost.org/libs/log/doc/html/log/rationale/why_crash_on_term.html
137 void shutdown();
138 
139 struct LogShutdown {
140  inline ~LogShutdown() { shutdown(); }
141 };
142 
143 // Optional pointer to function to call on LOG(FATAL).
144 using FatalFunc = void (*)();
146 
147 using ChannelLogger = boost::log::sources::channel_logger_mt<Channel>;
148 BOOST_LOG_GLOBAL_LOGGER(gChannelLogger, ChannelLogger)
149 
150 using SeverityLogger = boost::log::sources::severity_logger_mt<Severity>;
151 BOOST_LOG_GLOBAL_LOGGER(gSeverityLogger, SeverityLogger)
152 
153 // Lifetime of Logger is each call to LOG().
154 class Logger {
155  bool const is_channel_;
156  int const enum_value_;
157  // Pointers are used to minimize size of inline objects.
158  std::unique_ptr<boost::log::record> record_;
159  std::unique_ptr<boost::log::record_ostream> stream_;
160 
161  public:
162  Logger(Channel);
163  Logger(Severity);
164  Logger(Logger&&) = default;
165  ~Logger();
166  operator bool() const;
167  // Must check operator bool() first before calling stream().
168  boost::log::record_ostream& stream(char const* file, int line);
169 };
170 
172  extern bool g_any_active_channels;
173  return g_any_active_channels;
174 }
175 
176 inline bool fast_logging_check(Severity severity) {
178  return g_min_active_severity <= severity;
179 }
180 
181 // These macros risk inadvertent else-matching to the if statements,
182 // which are fortunately prevented by our clang-tidy requirements.
183 // These can be changed to for/while loops with slight performance degradation.
184 
185 #define LOG(tag) \
186  if (logger::fast_logging_check(logger::tag)) \
187  if (auto _omnisci_logger_ = logger::Logger(logger::tag)) \
188  _omnisci_logger_.stream(__FILE__, __LINE__)
189 
190 #define CHECK(condition) \
191  if (BOOST_UNLIKELY(!(condition))) \
192  LOG(FATAL) << "Check failed: " #condition " "
193 
194 #define CHECK_OP(OP, x, y) \
195  if (std::string* fatal_msg = logger::Check##OP(x, y, #x, #y)) \
196  LOG(FATAL) << *std::unique_ptr<std::string>(fatal_msg)
197 
198 #define CHECK_EQ(x, y) CHECK_OP(EQ, x, y)
199 #define CHECK_NE(x, y) CHECK_OP(NE, x, y)
200 #define CHECK_LT(x, y) CHECK_OP(LT, x, y)
201 #define CHECK_LE(x, y) CHECK_OP(LE, x, y)
202 #define CHECK_GT(x, y) CHECK_OP(GT, x, y)
203 #define CHECK_GE(x, y) CHECK_OP(GE, x, y)
204 
205 template <typename X, typename Y>
206 BOOST_NOINLINE std::string* check_failed(X const& x,
207  Y const& y,
208  char const* xstr,
209  char const* ystr,
210  char const* op_str) {
211  std::stringstream ss;
212  ss << "Check failed: " << xstr << op_str << ystr << " (" << x << op_str << y << ") ";
213  return new std::string(ss.str()); // Deleted by CHECK_OP macro.
214 }
215 
216 // Complexity comes from requirement that x and y be evaluated only once.
217 #define OMINSCI_CHECKOP_FUNCTION(name, op) \
218  template <typename X, typename Y> \
219  inline std::string* Check##name( \
220  X const& x, Y const& y, char const* xstr, char const* ystr) { \
221  if (BOOST_LIKELY(x op y)) \
222  return nullptr; \
223  else \
224  return logger::check_failed(x, y, xstr, ystr, " " #op " "); \
225  }
232 #undef OMINSCI_CHECKOP_FUNCTION
233 
234 #define UNREACHABLE() LOG(FATAL) << "UNREACHABLE "
235 
236 #else // __CUDACC__
237 
238 // Provided for backward compatibility to allow code to compile.
239 // No logging is actually done, since cuda code should not log.
240 template <Severity severity>
241 class NullLogger {
242  public:
243  NullLogger() {
244  if /*constexpr*/ (severity == Severity::FATAL) {
245  abort();
246  }
247  }
248  template <typename T>
249 #ifndef SUPPRESS_NULL_LOGGER_DEPRECATION_WARNINGS
250  [[deprecated]]
251 #endif
252  // If you are here because of a deprecation warning, that is because the code
253  // is attempting to log something in cuda (e.g. CHECK macros). It should
254  // probably be fixed there.
255  NullLogger&
256  operator<<(const T&) {
257  return *this;
258  }
259 };
260 
261 #define LOG(severity) logger::NullLogger<logger::Severity::severity>()
262 
263 #define CHECK(condition) LOG_IF(FATAL, !(condition))
264 
265 #define CHECK_EQ(x, y) CHECK((x) == (y))
266 #define CHECK_NE(x, y) CHECK((x) != (y))
267 #define CHECK_LT(x, y) CHECK((x) < (y))
268 #define CHECK_LE(x, y) CHECK((x) <= (y))
269 #define CHECK_GT(x, y) CHECK((x) > (y))
270 #define CHECK_GE(x, y) CHECK((x) >= (y))
271 
272 #define UNREACHABLE() LOG(FATAL)
273 
274 #endif // __CUDACC__
275 
276 #define LOG_IF(severity, condition) \
277  if (condition) \
278  LOG(severity)
279 
280 #define VLOG(n) LOG(DEBUG##n)
281 
282 class Duration;
283 
284 class DebugTimer {
286 
287  public:
288  DebugTimer(Severity, char const* file, int line, char const* name);
289  ~DebugTimer();
290  void stop();
291 };
292 
293 void debugTimerNewThread(std::thread::id parent_thread_id);
294 
295 // Typical usage: auto timer = DEBUG_TIMER(__func__);
296 #define DEBUG_TIMER(name) logger::DebugTimer(logger::INFO, __FILE__, __LINE__, name)
297 
298 #define DEBUG_TIMER_NEW_THREAD(parent_thread_id) \
299  logger::debugTimerNewThread(parent_thread_id)
300 
301 } // namespace logger
302 
303 #endif // SHARED_LOGGER_H
int const enum_value_
Definition: Logger.h:156
size_t min_free_space_
Definition: Logger.h:121
std::set< Channel > Channels
Definition: Logger.h:103
void debugTimerNewThread(std::thread::id parent_thread_id)
Definition: Logger.cpp:569
boost::log::sources::channel_logger_mt< Channel > ChannelLogger
Definition: Logger.h:147
std::unique_ptr< boost::log::record > record_
Definition: Logger.h:158
LogOptions(char const *argv0)
Definition: Logger.cpp:62
std::string base_path_
Definition: Logger.h:107
bool g_enable_debug_timer
Definition: Logger.cpp:17
Channel
Definition: Logger.h:61
Duration * duration_
Definition: Logger.h:285
void set_once_fatal_func(FatalFunc fatal_func)
Definition: Logger.cpp:292
boost::program_options::options_description const & get_options() const
Definition: Logger.cpp:119
constexpr std::array< char, 8 > SeveritySymbols
Definition: Logger.h:94
Channels channels_
Definition: Logger.h:118
bool const is_channel_
Definition: Logger.h:155
constexpr std::array< char, 2 > ChannelSymbols
Definition: Logger.h:65
bool fast_logging_check(Channel)
Definition: Logger.h:171
void init(LogOptions const &log_opts)
Definition: Logger.cpp:265
Severity g_min_active_severity
Definition: Logger.cpp:263
DebugTimer(Severity, char const *file, int line, char const *name)
Definition: Logger.cpp:551
#define OMINSCI_CHECKOP_FUNCTION(name, op)
Definition: Logger.h:217
bool rotate_daily_
Definition: Logger.h:122
BOOST_NOINLINE std::string * check_failed(X const &x, Y const &y, char const *xstr, char const *ystr, char const *op_str)
Definition: Logger.h:206
std::string symlink_
Definition: Logger.h:115
std::unique_ptr< boost::log::record_ostream > stream_
Definition: Logger.h:159
Severity
Definition: Logger.h:73
boost::log::formatting_ostream & operator<<(boost::log::formatting_ostream &strm, boost::log::to_log_manip< Channel, tag::channel > const &manip)
Definition: Logger.cpp:178
void shutdown()
Definition: Logger.cpp:299
constexpr std::array< char const *, 8 > SeverityNames
Definition: Logger.h:85
Severity severity_
Definition: Logger.h:116
constexpr std::array< char const *, 2 > ChannelNames
Definition: Logger.h:63
bool g_any_active_channels
Definition: Logger.cpp:262
boost::program_options::options_description options_
Definition: Logger.h:108
boost::log::sources::severity_logger_mt< Severity > SeverityLogger
Definition: Logger.h:150
std::string file_name_pattern_
Definition: Logger.h:114
size_t rotation_size_
Definition: Logger.h:123
void set_base_path(std::string const &base_path)
Definition: Logger.cpp:133
boost::filesystem::path full_log_dir() const
Definition: Logger.cpp:115
void(*)( FatalFunc)
Definition: Logger.h:144
size_t max_files_
Definition: Logger.h:120
Severity severity_clog_
Definition: Logger.h:117
boost::filesystem::path log_dir_
Definition: Logger.h:112
void parse_command_line(int, char const *const *)
Definition: Logger.cpp:124