OmniSciDB  29e35f4d58
Logger.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 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 
18 
19 #ifndef __CUDACC__
20 
21 #include "Logger.h"
22 #include "StringTransform.h"
23 
24 #include <boost/algorithm/string.hpp>
25 #include <boost/log/expressions.hpp>
26 #include <boost/log/sinks.hpp>
27 #include <boost/log/sources/global_logger_storage.hpp>
28 #include <boost/log/sources/logger.hpp>
29 #include <boost/log/sources/severity_feature.hpp>
30 #include <boost/log/support/date_time.hpp>
31 #include <boost/log/utility/setup.hpp>
32 #include <boost/phoenix.hpp>
33 #include <boost/variant.hpp>
34 
35 #include <atomic>
36 #include <cstdlib>
37 #include <iostream>
38 #include <mutex>
39 #include <regex>
40 
41 namespace logger {
42 
43 namespace attr = boost::log::attributes;
44 namespace expr = boost::log::expressions;
45 namespace keywords = boost::log::keywords;
46 namespace sinks = boost::log::sinks;
47 namespace sources = boost::log::sources;
48 namespace po = boost::program_options;
49 
50 BOOST_LOG_ATTRIBUTE_KEYWORD(process_id, "ProcessID", attr::current_process_id::value_type)
51 BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", Channel)
52 BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", Severity)
53 
54 BOOST_LOG_GLOBAL_LOGGER_DEFAULT(gChannelLogger, ChannelLogger)
55 BOOST_LOG_GLOBAL_LOGGER_DEFAULT(gSeverityLogger, SeverityLogger)
56 
57 // Return last component of path
58 std::string filename(char const* path) {
59  return boost::filesystem::path(path).filename().string();
60 }
61 
62 LogOptions::LogOptions(char const* argv0) {
63  // Log file base_name matches name of program.
64  std::string const base_name =
65  argv0 == nullptr ? std::string("omnisci_server") : filename(argv0);
67  symlink_ = base_name + symlink_;
68  set_options();
69 }
70 
71 boost::filesystem::path LogOptions::full_log_dir() const {
72  return log_dir_.has_root_directory() ? log_dir_ : base_path_ / log_dir_;
73 }
74 
75 po::options_description const& LogOptions::get_options() const {
76  return *options_;
77 }
78 
79 // Typical usage calls either get_options() or parse_command_line() but not both.
80 void LogOptions::parse_command_line(int argc, char const* const* argv) {
81  po::variables_map vm;
82  po::store(
83  po::command_line_parser(argc, argv).options(*options_).allow_unregistered().run(),
84  vm);
85  po::notify(vm); // Sets LogOptions member variables.
86 }
87 
88 // Must be called before init() to take effect.
89 void LogOptions::set_base_path(std::string const& base_path) {
90  base_path_ = base_path;
91 }
92 
93 // May be called to update default values based on updated member variables.
95  options_ = std::make_unique<boost::program_options::options_description>("Logging");
96  std::string const channels = join(ChannelNames, " ");
97  // Filter out DEBUG[1-4] severities from --help options
98  std::string severities;
99  for (auto const& name : SeverityNames) {
100  if (!boost::algorithm::starts_with(name, "DEBUG")) {
101  (severities += (severities.empty() ? "" : " ")) += name;
102  }
103  }
104  options_->add_options()(
105  "log-directory",
106  po::value<boost::filesystem::path>(&log_dir_)->default_value(log_dir_),
107  "Logging directory. May be relative to data directory, or absolute.");
108  options_->add_options()(
109  "log-file-name",
110  po::value<std::string>(&file_name_pattern_)->default_value(file_name_pattern_),
111  "Log file name relative to log-directory.");
112  options_->add_options()("log-symlink",
113  po::value<std::string>(&symlink_)->default_value(symlink_),
114  "Symlink to active log.");
115  options_->add_options()("log-severity",
116  po::value<Severity>(&severity_)->default_value(severity_),
117  ("Log to file severity level: " + severities).c_str());
118  options_->add_options()(
119  "log-severity-clog",
120  po::value<Severity>(&severity_clog_)->default_value(severity_clog_),
121  ("Log to console severity level: " + severities).c_str());
122  options_->add_options()("log-channels",
123  po::value<Channels>(&channels_)->default_value(channels_),
124  ("Log channel debug info: " + channels).c_str());
125  options_->add_options()("log-auto-flush",
126  po::value<bool>(&auto_flush_)->default_value(auto_flush_),
127  "Flush logging buffer to file after each message.");
128  options_->add_options()("log-max-files",
129  po::value<size_t>(&max_files_)->default_value(max_files_),
130  "Maximum number of log files to keep.");
131  options_->add_options()(
132  "log-min-free-space",
133  po::value<size_t>(&min_free_space_)->default_value(min_free_space_),
134  "Minimum number of bytes left on device before oldest log files are deleted.");
135  options_->add_options()("log-rotate-daily",
136  po::value<bool>(&rotate_daily_)->default_value(rotate_daily_),
137  "Start new log files at midnight.");
138  options_->add_options()(
139  "log-rotation-size",
140  po::value<size_t>(&rotation_size_)->default_value(rotation_size_),
141  "Maximum file size in bytes before new log files are started.");
142 }
143 
144 template <typename TAG>
145 std::string replace_braces(std::string const& str, TAG const tag) {
146  constexpr std::regex::flag_type flags = std::regex::ECMAScript | std::regex::optimize;
147  static std::regex const regex(R"(\{SEVERITY\})", flags);
148  if /*constexpr*/ (std::is_same<TAG, Channel>::value) {
149  return std::regex_replace(str, regex, ChannelNames[tag]);
150  } else {
151  return std::regex_replace(str, regex, SeverityNames[tag]);
152  }
153 }
154 
155 // Print decimal value for process_id (14620) instead of hex (0x0000391c)
156 boost::log::attributes::current_process_id::value_type::native_type get_native_process_id(
157  boost::log::value_ref<boost::log::attributes::current_process_id::value_type,
158  tag::process_id> const& pid) {
159  return pid ? pid->native_id() : 0;
160 }
161 
162 template <typename SINK>
163 sinks::text_file_backend::open_handler_type create_or_replace_symlink(
164  boost::weak_ptr<SINK> weak_ptr,
165  std::string&& symlink) {
166  namespace fs = boost::filesystem;
167  return [weak_ptr,
168  symlink = std::move(symlink)](sinks::text_file_backend::stream_type& stream) {
169  if (boost::shared_ptr<SINK> sink = weak_ptr.lock()) {
171  fs::path const& file_name = sink->locked_backend()->get_current_file_name();
172  fs::path const symlink_path = file_name.parent_path() / symlink;
173  fs::remove(symlink_path, ec);
174  if (ec) {
175  stream << filename(__FILE__) << ':' << __LINE__ << ' ' << ec.message() << '\n';
176  }
177  fs::create_symlink(file_name.filename(), symlink_path, ec);
178  if (ec) {
179  stream << filename(__FILE__) << ':' << __LINE__ << ' ' << ec.message() << '\n';
180  }
181  }
182  };
183 }
184 
185 boost::log::formatting_ostream& operator<<(
186  boost::log::formatting_ostream& strm,
187  boost::log::to_log_manip<Channel, tag::channel> const& manip) {
188  return strm << ChannelSymbols[manip.get()];
189 }
190 
191 boost::log::formatting_ostream& operator<<(
192  boost::log::formatting_ostream& strm,
193  boost::log::to_log_manip<Severity, tag::severity> const& manip) {
194  return strm << SeveritySymbols[manip.get()];
195 }
196 
197 template <typename TAG, typename SINK>
198 void set_formatter(SINK& sink) {
199  if /*constexpr*/ (std::is_same<TAG, Channel>::value) {
200  sink->set_formatter(
201  expr::stream << expr::format_date_time<boost::posix_time::ptime>(
202  "TimeStamp", "%Y-%m-%dT%H:%M:%S.%f")
203  << ' ' << channel << ' '
204  << boost::phoenix::bind(&get_native_process_id, process_id.or_none())
205  << ' ' << expr::smessage);
206  } else {
207  sink->set_formatter(
208  expr::stream << expr::format_date_time<boost::posix_time::ptime>(
209  "TimeStamp", "%Y-%m-%dT%H:%M:%S.%f")
210  << ' ' << severity << ' '
211  << boost::phoenix::bind(&get_native_process_id, process_id.or_none())
212  << ' ' << expr::smessage);
213  }
214 }
215 
216 template <typename FILE_SINK, typename TAG>
217 boost::shared_ptr<FILE_SINK> make_sink(LogOptions const& log_opts,
218  boost::filesystem::path const& full_log_dir,
219  TAG const tag) {
220  auto sink = boost::make_shared<FILE_SINK>(
221  keywords::file_name =
222  full_log_dir / replace_braces(log_opts.file_name_pattern_, tag),
223  keywords::auto_flush = log_opts.auto_flush_,
224  keywords::rotation_size = log_opts.rotation_size_);
225  if /*constexpr*/ (std::is_same<TAG, Channel>::value) {
226  sink->set_filter(channel == static_cast<Channel>(tag));
227  set_formatter<Channel>(sink);
228  } else {
229  // INFO sink logs all other levels. Other sinks only log at their level or higher.
230  Severity const min_filter_level = static_cast<Severity>(tag) == Severity::INFO
231  ? log_opts.severity_
232  : static_cast<Severity>(tag);
233  sink->set_filter(min_filter_level <= severity);
234  set_formatter<Severity>(sink);
235  }
236  typename FILE_SINK::locked_backend_ptr backend = sink->locked_backend();
237  if (log_opts.rotate_daily_) {
238  backend->set_time_based_rotation(sinks::file::rotation_at_time_point(0, 0, 0));
239  }
240  backend->set_file_collector(
241  sinks::file::make_collector(keywords::target = full_log_dir,
242  keywords::max_files = log_opts.max_files_,
243  keywords::min_free_space = log_opts.min_free_space_));
244  backend->set_open_handler(create_or_replace_symlink(
245  boost::weak_ptr<FILE_SINK>(sink), replace_braces(log_opts.symlink_, tag)));
246  backend->scan_for_files();
247  return sink;
248 }
249 
250 // Pointer to function to optionally call on LOG(FATAL).
251 std::atomic<FatalFunc> g_fatal_func{nullptr};
252 std::once_flag g_fatal_func_flag;
253 
254 using ClogSync = sinks::synchronous_sink<sinks::text_ostream_backend>;
255 using FileSync = sinks::synchronous_sink<sinks::text_file_backend>;
256 
257 template <typename CONSOLE_SINK>
258 boost::shared_ptr<CONSOLE_SINK> make_sink(LogOptions const& log_opts) {
259  auto sink = boost::make_shared<CONSOLE_SINK>();
260  boost::shared_ptr<std::ostream> clog(&std::clog, boost::null_deleter());
261  sink->locked_backend()->add_stream(clog);
262  sink->set_filter(log_opts.severity_clog_ <= severity);
263  set_formatter<Severity>(sink);
264  return sink;
265 }
266 
267 // Locking/atomicity not needed for g_any_active_channels or g_min_active_severity
268 // as they are modifed by init() once.
271 
272 void init(LogOptions const& log_opts) {
273  boost::shared_ptr<boost::log::core> core = boost::log::core::get();
274  // boost::log::add_common_attributes(); // LineID TimeStamp ProcessID ThreadID
275  core->add_global_attribute("TimeStamp", attr::local_clock());
276  core->add_global_attribute("ProcessID", attr::current_process_id());
277  if (0 < log_opts.max_files_) {
278  boost::filesystem::path const full_log_dir = log_opts.full_log_dir();
279  bool const log_dir_was_created = boost::filesystem::create_directory(full_log_dir);
280  // Don't create separate log sinks for anything less than Severity::INFO.
281  Severity const min_sink_level = std::max(Severity::INFO, log_opts.severity_);
282  for (int i = min_sink_level; i < Severity::_NSEVERITIES; ++i) {
283  Severity const level = static_cast<Severity>(i);
284  core->add_sink(make_sink<FileSync>(log_opts, full_log_dir, level));
285  }
287  if (log_dir_was_created) {
288  LOG(INFO) << "Log directory(" << full_log_dir.native() << ") created.";
289  }
290  for (auto const channel : log_opts.channels_) {
291  core->add_sink(make_sink<FileSync>(log_opts, full_log_dir, channel));
292  }
293  g_any_active_channels = !log_opts.channels_.empty();
294  }
295  core->add_sink(make_sink<ClogSync>(log_opts));
297 }
298 
299 void set_once_fatal_func(FatalFunc fatal_func) {
300  if (g_fatal_func.exchange(fatal_func)) {
301  throw std::runtime_error(
302  "logger::set_once_fatal_func() should not be called more than once.");
303  }
304 }
305 
306 void shutdown() {
307  boost::log::core::get()->remove_all_sinks();
308 }
309 
310 // Used by boost::program_options when parsing enum Channel.
311 std::istream& operator>>(std::istream& in, Channels& channels) {
312  std::string line;
313  std::getline(in, line);
314  std::regex const rex(R"(\w+)");
315  using TokenItr = std::regex_token_iterator<std::string::iterator>;
316  TokenItr const end;
317  for (TokenItr tok(line.begin(), line.end(), rex); tok != end; ++tok) {
318  auto itr = std::find(ChannelNames.cbegin(), ChannelNames.cend(), *tok);
319  if (itr == ChannelNames.cend()) {
320  in.setstate(std::ios_base::failbit);
321  break;
322  } else {
323  channels.emplace(static_cast<Channel>(itr - ChannelNames.cbegin()));
324  }
325  }
326  return in;
327 }
328 
329 // Used by boost::program_options when stringifying Channels.
330 std::ostream& operator<<(std::ostream& out, Channels const& channels) {
331  int i = 0;
332  for (auto const channel : channels) {
333  out << (i++ ? " " : "") << ChannelNames.at(channel);
334  }
335  return out;
336 }
337 
338 // Used by boost::program_options when parsing enum Severity.
339 std::istream& operator>>(std::istream& in, Severity& sev) {
340  std::string token;
341  in >> token;
342  auto itr = std::find(SeverityNames.cbegin(), SeverityNames.cend(), token);
343  if (itr == SeverityNames.cend()) {
344  in.setstate(std::ios_base::failbit);
345  } else {
346  sev = static_cast<Severity>(itr - SeverityNames.cbegin());
347  }
348  return in;
349 }
350 
351 // Used by boost::program_options when stringifying enum Severity.
352 std::ostream& operator<<(std::ostream& out, Severity const& sev) {
353  return out << SeverityNames.at(sev);
354 }
355 
357  : is_channel_(true)
358  , enum_value_(channel)
359  , record_(std::make_unique<boost::log::record>(
360  gChannelLogger::get().open_record(boost::log::keywords::channel = channel))) {
361  if (*record_) {
362  stream_ = std::make_unique<boost::log::record_ostream>(*record_);
363  }
364 }
365 
367  : is_channel_(false)
368  , enum_value_(severity)
369  , record_(std::make_unique<boost::log::record>(gSeverityLogger::get().open_record(
370  boost::log::keywords::severity = severity))) {
371  if (*record_) {
372  stream_ = std::make_unique<boost::log::record_ostream>(*record_);
373  }
374 }
375 
377  if (stream_) {
378  if (is_channel_) {
379  gChannelLogger::get().push_record(boost::move(stream_->get_record()));
380  } else {
381  gSeverityLogger::get().push_record(boost::move(stream_->get_record()));
382  }
383  }
384  if (!is_channel_ && static_cast<Severity>(enum_value_) == Severity::FATAL) {
385  if (FatalFunc fatal_func = g_fatal_func.load()) {
386  // set_once_fatal_func() prevents race condition.
387  // Exceptions thrown by (*fatal_func)() are propagated here.
388  std::call_once(g_fatal_func_flag, *fatal_func);
389  }
390  abort();
391  }
392 }
393 
394 Logger::operator bool() const {
395  return static_cast<bool>(stream_);
396 }
397 
398 boost::log::record_ostream& Logger::stream(char const* file, int line) {
399  return *stream_ << filename(file) << ':' << line << ' ';
400 }
401 
402 // DebugTimer-related classes and functions.
403 
404 using Clock = std::chrono::steady_clock;
405 
406 class DurationTree;
407 
408 class Duration {
410  Clock::time_point const start_;
411  Clock::time_point stop_;
412 
413  public:
414  int const depth_;
416  char const* const file_;
417  int const line_;
418  char const* const name_;
419 
420  Duration(DurationTree* duration_tree,
421  int depth,
422  Severity severity,
423  char const* file,
424  int line,
425  char const* name)
426  : duration_tree_(duration_tree)
427  , start_(Clock::now())
428  , depth_(depth)
429  , severity_(severity)
430  , file_(file)
431  , line_(line)
432  , name_(name) {}
433  bool stop();
434  template <typename Units = std::chrono::milliseconds>
435  typename Units::rep value() const {
436  return std::chrono::duration_cast<Units>(stop_ - start_).count();
437  }
438 };
439 
440 using DurationTreeNode = boost::variant<Duration, DurationTree&>;
441 
443  std::deque<DurationTreeNode> durations_;
444  int current_depth_; //< Depth of next DurationTreeNode.
445 
446  public:
447  int const depth_; //< Depth of tree within parent tree, 0 for base tree.
448  std::thread::id const thread_id_;
449  DurationTree(std::thread::id thread_id, int start_depth)
450  // Add +1 to current_depth_ for non-base DurationTrees for extra indentation.
451  : current_depth_(start_depth + (start_depth == 0 ? 0 : 1))
452  , depth_(start_depth)
453  , thread_id_(thread_id) {}
454  void pushDurationTree(DurationTree& duration_tree) {
455  durations_.emplace_back(duration_tree);
456  }
457  const Duration& baseDuration() const {
458  CHECK(!durations_.empty());
459  return boost::get<Duration>(durations_.front());
460  }
461  int currentDepth() const { return current_depth_; }
462  void decrementDepth() { --current_depth_; }
463  std::deque<DurationTreeNode> const& durations() const { return durations_; }
464  template <typename... Ts>
466  durations_.emplace_back(Duration(this, current_depth_++, std::forward<Ts>(args)...));
467  return boost::get<Duration>(&durations_.back());
468  }
469 };
470 
474  stop_ = Clock::now();
475  duration_tree_->decrementDepth();
476  return depth_ == 0;
477 }
478 
479 using DurationTreeMap =
480  std::unordered_map<std::thread::id, std::unique_ptr<DurationTree>>;
481 
484 
485 template <typename... Ts>
486 Duration* newDuration(Severity severity, Ts&&... args) {
487  if (g_enable_debug_timer) {
488  auto const thread_id = std::this_thread::get_id();
489  std::lock_guard<std::mutex> lock_guard(gDurationTreeMapMutex);
490  auto& duration_tree_ptr = gDurationTreeMap[thread_id];
491  if (!duration_tree_ptr) {
492  duration_tree_ptr = std::make_unique<DurationTree>(thread_id, 0);
493  }
494  return duration_tree_ptr->newDuration(severity, std::forward<Ts>(args)...);
495  }
496  return nullptr; // Inactive - don't measure or report timing.
497 }
498 
499 std::ostream& operator<<(std::ostream& os, Duration const& duration) {
500  return os << std::setw(2 * duration.depth_) << ' ' << duration.value() << "ms "
501  << duration.name_ << ' ' << filename(duration.file_) << ':' << duration.line_;
502 }
503 
504 std::ostream& operator<<(std::ostream& os, DurationTree const& duration_tree) {
505  os << std::setw(2 * duration_tree.depth_) << ' ' << "New thread("
506  << duration_tree.thread_id_ << ')';
507  for (auto const& duration_tree_node : duration_tree.durations()) {
508  os << '\n' << duration_tree_node;
509  }
510  return os << '\n'
511  << std::setw(2 * duration_tree.depth_) << ' ' << "End thread("
512  << duration_tree.thread_id_ << ')';
513 }
514 
515 // Only called by logAndEraseDurationTree() on base tree
516 boost::log::record_ostream& operator<<(boost::log::record_ostream& os,
517  DurationTreeMap::const_reference kv_pair) {
518  auto itr = kv_pair.second->durations().cbegin();
519  auto const end = kv_pair.second->durations().cend();
520  auto const& base_duration = boost::get<Duration>(*itr);
521  os << "DEBUG_TIMER thread_id(" << kv_pair.first << ")\n"
522  << base_duration.value() << "ms total duration for " << base_duration.name_;
523  for (++itr; itr != end; ++itr) {
524  os << '\n' << *itr;
525  }
526  return os;
527 }
528 
529 // Depth-first search and erase all DurationTrees. Not thread-safe.
530 struct EraseDurationTrees : boost::static_visitor<> {
531  void operator()(DurationTreeMap::const_iterator const& itr) const {
532  for (auto const& duration_tree_node : itr->second->durations()) {
533  apply_visitor(*this, duration_tree_node);
534  }
535  gDurationTreeMap.erase(itr);
536  }
537  void operator()(Duration const&) const {}
538  void operator()(DurationTree const& duration_tree) const {
539  for (auto const& duration_tree_node : duration_tree.durations()) {
540  apply_visitor(*this, duration_tree_node);
541  }
542  gDurationTreeMap.erase(duration_tree.thread_id_);
543  }
544 };
545 
546 void logAndEraseDurationTree(std::thread::id const thread_id) {
547  std::lock_guard<std::mutex> lock_guard(gDurationTreeMapMutex);
548  DurationTreeMap::const_iterator const itr = gDurationTreeMap.find(thread_id);
549  CHECK(itr != gDurationTreeMap.cend());
550  auto const& base_duration = itr->second->baseDuration();
551  if (auto log = Logger(base_duration.severity_)) {
552  log.stream(base_duration.file_, base_duration.line_) << *itr;
553  }
554  EraseDurationTrees const tree_trimmer;
555  tree_trimmer(itr);
556 }
557 
558 DebugTimer::DebugTimer(Severity severity, char const* file, int line, char const* name)
559  : duration_(newDuration(severity, file, line, name)) {}
560 
562  stop();
563 }
564 
566  if (duration_) {
567  if (duration_->stop()) {
568  logAndEraseDurationTree(std::this_thread::get_id());
569  }
570  duration_ = nullptr;
571  }
572 }
573 
576 void debugTimerNewThread(std::thread::id parent_thread_id) {
577  if (g_enable_debug_timer) {
578  auto const thread_id = std::this_thread::get_id();
579  if (thread_id != parent_thread_id) {
580  std::lock_guard<std::mutex> lock_guard(gDurationTreeMapMutex);
581  auto parent_itr = gDurationTreeMap.find(parent_thread_id);
582  if (parent_itr != gDurationTreeMap.end()) {
583  auto& duration_tree_ptr = gDurationTreeMap[thread_id];
584  if (!duration_tree_ptr) {
585  auto const current_depth = parent_itr->second->currentDepth();
586  duration_tree_ptr =
587  std::make_unique<DurationTree>(thread_id, current_depth + 1);
588  parent_itr->second->pushDurationTree(*duration_tree_ptr);
589  }
590  }
591  }
592  }
593 }
594 
595 } // namespace logger
596 
597 #endif // #ifndef __CUDACC__
std::istream & operator>>(std::istream &in, Channels &channels)
Definition: Logger.cpp:311
void pushDurationTree(DurationTree &duration_tree)
Definition: Logger.cpp:454
std::unique_ptr< boost::program_options::options_description > options_
Definition: Logger.h:110
int const enum_value_
Definition: Logger.h:159
std::string filename(char const *path)
Definition: Logger.cpp:58
size_t min_free_space_
Definition: Logger.h:123
void operator()(Duration const &) const
Definition: Logger.cpp:537
std::string replace_braces(std::string const &str, TAG const tag)
Definition: Logger.cpp:145
std::set< Channel > Channels
Definition: Logger.h:103
void debugTimerNewThread(std::thread::id parent_thread_id)
Definition: Logger.cpp:576
boost::log::sources::channel_logger_mt< Channel > ChannelLogger
Definition: Logger.h:150
void set_formatter(SINK &sink)
Definition: Logger.cpp:198
std::unique_ptr< boost::log::record > record_
Definition: Logger.h:161
LogOptions(char const *argv0)
Definition: Logger.cpp:62
sinks::text_file_backend::open_handler_type create_or_replace_symlink(boost::weak_ptr< SINK > weak_ptr, std::string &&symlink)
Definition: Logger.cpp:163
std::once_flag g_fatal_func_flag
Definition: Logger.cpp:252
void operator()(DurationTree const &duration_tree) const
Definition: Logger.cpp:538
std::deque< DurationTreeNode > durations_
Definition: Logger.cpp:443
std::string base_path_
Definition: Logger.h:107
Duration * newDuration(Severity severity, Ts &&... args)
Definition: Logger.cpp:486
#define LOG(tag)
Definition: Logger.h:188
Clock::time_point const start_
Definition: Logger.cpp:410
Duration(DurationTree *duration_tree, int depth, Severity severity, char const *file, int line, char const *name)
Definition: Logger.cpp:420
bool g_enable_debug_timer
Definition: Logger.cpp:17
Channel
Definition: Logger.h:61
std::string join(T const &container, std::string const &delim)
Duration * newDuration(Ts &&... args)
Definition: Logger.cpp:465
void logAndEraseDurationTree(std::thread::id const thread_id)
Definition: Logger.cpp:546
boost::program_options::options_description const & get_options() const
Definition: Logger.cpp:75
Duration * duration_
Definition: Logger.h:288
void set_once_fatal_func(FatalFunc fatal_func)
Definition: Logger.cpp:299
sinks::synchronous_sink< sinks::text_ostream_backend > ClogSync
Definition: Logger.cpp:254
char const *const name_
Definition: Logger.cpp:418
int const line_
Definition: Logger.cpp:417
constexpr std::array< char, 8 > SeveritySymbols
Definition: Logger.h:94
Channels channels_
Definition: Logger.h:120
bool const is_channel_
Definition: Logger.h:158
constexpr std::array< char, 2 > ChannelSymbols
Definition: Logger.h:65
int const depth_
Definition: Logger.cpp:414
sinks::synchronous_sink< sinks::text_file_backend > FileSync
Definition: Logger.cpp:255
Units::rep value() const
Definition: Logger.cpp:435
void init(LogOptions const &log_opts)
Definition: Logger.cpp:272
Severity g_min_active_severity
Definition: Logger.cpp:270
std::atomic< FatalFunc > g_fatal_func
Definition: Logger.cpp:251
const int8_t const int64_t const uint64_t const int32_t const int64_t int64_t uint32_t const int64_t int32_t * error_code
DebugTimer(Severity, char const *file, int line, char const *name)
Definition: Logger.cpp:558
void operator()(DurationTreeMap::const_iterator const &itr) const
Definition: Logger.cpp:531
boost::shared_ptr< FILE_SINK > make_sink(LogOptions const &log_opts, boost::filesystem::path const &full_log_dir, TAG const tag)
Definition: Logger.cpp:217
std::thread::id const thread_id_
Definition: Logger.cpp:448
bool rotate_daily_
Definition: Logger.h:124
DurationTree *const duration_tree_
Definition: Logger.cpp:409
std::deque< DurationTreeNode > const & durations() const
Definition: Logger.cpp:463
std::string symlink_
Definition: Logger.h:117
std::mutex gDurationTreeMapMutex
Definition: Logger.cpp:482
std::unique_ptr< boost::log::record_ostream > stream_
Definition: Logger.h:162
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:185
void shutdown()
Definition: Logger.cpp:306
constexpr std::array< char const *, 8 > SeverityNames
Definition: Logger.h:85
boost::filesystem::path full_log_dir() const
Definition: Logger.cpp:71
DurationTree(std::thread::id thread_id, int start_depth)
Definition: Logger.cpp:449
int currentDepth() const
Definition: Logger.cpp:461
Severity severity_
Definition: Logger.h:118
constexpr std::array< char const *, 2 > ChannelNames
Definition: Logger.h:63
bool g_any_active_channels
Definition: Logger.cpp:269
DurationTreeMap gDurationTreeMap
Definition: Logger.cpp:483
boost::log::sources::severity_logger_mt< Severity > SeverityLogger
Definition: Logger.h:153
std::string file_name_pattern_
Definition: Logger.h:116
std::unordered_map< std::thread::id, std::unique_ptr< DurationTree > > DurationTreeMap
Definition: Logger.cpp:480
#define CHECK(condition)
Definition: Logger.h:193
size_t rotation_size_
Definition: Logger.h:125
void set_base_path(std::string const &base_path)
Definition: Logger.cpp:89
char const *const file_
Definition: Logger.cpp:416
int const depth_
Definition: Logger.cpp:447
std::chrono::steady_clock Clock
Definition: Logger.cpp:404
boost::log::attributes::current_process_id::value_type::native_type get_native_process_id(boost::log::value_ref< boost::log::attributes::current_process_id::value_type, tag::process_id > const &pid)
Definition: Logger.cpp:156
size_t max_files_
Definition: Logger.h:122
Logger(Channel)
Definition: Logger.cpp:356
const int8_t const int64_t const uint64_t const int32_t const int64_t int64_t ** out
boost::variant< Duration, DurationTree & > DurationTreeNode
Definition: Logger.cpp:440
void(*)() FatalFunc
Definition: Logger.h:147
const Duration & baseDuration() const
Definition: Logger.cpp:457
Severity severity_clog_
Definition: Logger.h:119
boost::filesystem::path log_dir_
Definition: Logger.h:114
void set_options()
Definition: Logger.cpp:94
Severity const severity_
Definition: Logger.cpp:415
Clock::time_point stop_
Definition: Logger.cpp:411
boost::log::record_ostream & stream(char const *file, int line)
Definition: Logger.cpp:398
void parse_command_line(int, char const *const *)
Definition: Logger.cpp:80