log.h
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2019 Intel Corporation. All Rights Reserved.
3 
4 #pragma once
5 
6 #include "types.h"
7 
8 namespace librealsense
9 {
10 #if BUILD_EASYLOGGINGPP
11  struct log_message
12  {
13  el::LogMessage const& el_msg;
14  std::string built_msg;
15 
16  log_message( el::LogMessage const& el_msg ) : el_msg( el_msg ) {}
17 
18  unsigned get_log_message_line_number() const {
19  return el_msg.line();
20  }
21 
22  const char* get_log_message_filename() const {
23  return el_msg.file().c_str();
24  }
25 
26  const char* get_raw_log_message() const {
27  return el_msg.message().c_str();
28  }
29 
30  const char* get_full_log_message() {
31  if (built_msg.empty())
32  {
33  bool const append_new_line = false;
34  built_msg = el_msg.logger()->logBuilder()->build(&el_msg, append_new_line);
35  }
36  return built_msg.c_str();
37  }
38  };
39 
40  template<char const * NAME>
41  class logger_type
42  {
43  rs2_log_severity minimum_log_severity = RS2_LOG_SEVERITY_NONE;
44  rs2_log_severity minimum_console_severity = RS2_LOG_SEVERITY_NONE;
45  rs2_log_severity minimum_file_severity = RS2_LOG_SEVERITY_NONE;
46 
47  std::mutex log_mutex;
48  std::ofstream log_file;
49  std::vector< std::string > callback_dispatchers;
50 
52  const std::string log_id = NAME;
53 
54  public:
55  static el::Level severity_to_level(rs2_log_severity severity)
56  {
57  switch (severity)
58  {
64  default: return el::Level::Unknown;
65  }
66  }
67 
68  static rs2_log_severity level_to_severity( el::Level level )
69  {
70  switch( level )
71  {
72  case el::Level::Debug: return RS2_LOG_SEVERITY_DEBUG; // LOG(DEBUG) - useful for developers to debug application
73  case el::Level::Trace: return RS2_LOG_SEVERITY_DEBUG; // LOG(TRACE) - useful to back-trace certain events
74  case el::Level::Info: return RS2_LOG_SEVERITY_INFO; // LOG(INFO) - show current progress of application
75  case el::Level::Verbose: return RS2_LOG_SEVERITY_INFO; // LOG(VERBOSE) - can be highly useful but varies with verbose logging level
76  case el::Level::Warning: return RS2_LOG_SEVERITY_WARN; // LOG(WARNING) - potentially harmful situtaions
77  case el::Level::Error: return RS2_LOG_SEVERITY_ERROR; // LOG(ERROR) - errors in application but application will keep running
78  case el::Level::Fatal: return RS2_LOG_SEVERITY_FATAL; // LOG(FATAL) - severe errors that will presumably abort application
79  default:
80  // Unknown/Global, or otherwise
81  // Global should never occur (no CGLOBAL macro); same for Unknown...
82  return RS2_LOG_SEVERITY_ERROR; // treat as error, since we don't know what it is...
83  }
84  }
85 
86  void open() const
87  {
88  el::Configurations defaultConf;
89  defaultConf.setToDefault();
90  // To set GLOBAL configurations you may use
91 
92  defaultConf.setGlobally(el::ConfigurationType::ToFile, "false");
95  defaultConf.setGlobally(el::ConfigurationType::Format, " %datetime{%d/%M %H:%m:%s,%g} %level [%thread] (%fbase:%line) %msg");
96 
97  for (int i = minimum_console_severity; i < RS2_LOG_SEVERITY_NONE; i++)
98  {
99  defaultConf.set(severity_to_level(static_cast<rs2_log_severity>(i)),
101  }
102 
103  // NOTE: you can only log to one file, so successive calls to log_to_file
104  // will override one another!
105  if (minimum_file_severity != RS2_LOG_SEVERITY_NONE)
106  {
107  // Configure filename for logging only if the severity requires it, which
108  // prevents creation of empty log files that are not required.
109  defaultConf.setGlobally(el::ConfigurationType::Filename, filename);
110  }
111  for (int i = minimum_file_severity; i < RS2_LOG_SEVERITY_NONE; i++)
112  {
113  defaultConf.set(severity_to_level(static_cast<rs2_log_severity>(i)),
115  }
116 
117  el::Loggers::reconfigureLogger(log_id, defaultConf);
118  }
119 
120  void open_def() const
121  {
122  el::Configurations defaultConf;
123  defaultConf.setToDefault();
124  // To set GLOBAL configurations you may use
125 
126  defaultConf.setGlobally(el::ConfigurationType::ToFile, "false");
128 
129  el::Loggers::reconfigureLogger(log_id, defaultConf);
130  }
131 
132 
133  logger_type()
134  : filename(to_string() << datetime_string() << ".log")
135  {
137  if (try_get_log_severity(severity))
138  {
139  log_to_file(severity, filename.c_str());
140  }
141  else
142  {
143  open_def();
144  }
145  }
146 
147  static bool try_get_log_severity(rs2_log_severity& severity)
148  {
149  static const char* severity_var_name = "LRS_LOG_LEVEL";
150  auto content = getenv(severity_var_name);
151 
152  if (content)
153  {
154  std::string content_str(content);
155  std::transform(content_str.begin(), content_str.end(), content_str.begin(), ::tolower);
156 
157  for (uint32_t i = 0; i < RS2_LOG_SEVERITY_COUNT; i++)
158  {
159  auto current = (rs2_log_severity)i;
161  std::transform(name.begin(), name.end(), name.begin(), ::tolower);
162  if (content_str == name)
163  {
164  severity = current;
165  return true;
166  }
167  }
168  }
169 
170  return false;
171  }
172 
173  void log_to_console(rs2_log_severity min_severity)
174  {
175  minimum_console_severity = min_severity;
176  open();
177  }
178 
179  void log_to_file(rs2_log_severity min_severity, const char * file_path)
180  {
181  if (!try_get_log_severity(minimum_file_severity))
182  minimum_file_severity = min_severity;
183 
184  if (file_path)
185  filename = file_path;
186 
187  open();
188  }
189 
190  protected:
191  // Create a dispatch sink which will get any messages logged to EasyLogging, which will then
192  // post the messages on the viewer's notification window.
193  class elpp_dispatcher : public el::LogDispatchCallback
194  {
195  public:
198 
199  protected:
200  void handle( el::LogDispatchData const* data ) noexcept override
201  {
202  // NOTE: once a callback is set, it gets ALL messages -- even from other (non-"librealsense") loggers!
203  el::LogMessage const& msg = *data->logMessage();
204  auto severity = level_to_severity( msg.level() );
205  if( callback && severity >= min_severity )
206  {
207  log_message msg_wrapper( msg );
208  callback->on_log( severity, reinterpret_cast<rs2_log_message const&>(msg_wrapper) ); // noexcept!
209  }
210  }
211  };
212 
213  public:
214  void remove_callbacks()
215  {
216  for( auto const& dispatch : callback_dispatchers )
217  el::Helpers::uninstallLogDispatchCallback< elpp_dispatcher >( dispatch );
218  callback_dispatchers.clear();
219  }
220 
221  void log_to_callback( rs2_log_severity min_severity, log_callback_ptr callback )
222  {
223  open();
224 
225  try_get_log_severity( min_severity );
226  if( callback && min_severity != RS2_LOG_SEVERITY_NONE )
227  {
228  // Each callback we install must have a unique name
229  std::ostringstream ss;
230  ss << "elpp_dispatcher_" << callback_dispatchers.size();
231  std::string dispatch_name = ss.str();
232 
233  // Record all the dispatchers we have so we can erase them
234  callback_dispatchers.push_back( dispatch_name );
235 
236  // The only way to install the callback in ELPP is with a default ctor...
237  el::Helpers::installLogDispatchCallback< elpp_dispatcher >( dispatch_name );
238  auto dispatcher = el::Helpers::logDispatchCallback< elpp_dispatcher >( dispatch_name );
239  dispatcher->callback = callback;
240  dispatcher->min_severity = min_severity;
241 
242  // Remove the default logger (which will log to standard out/err) or it'll still be active
243  //el::Helpers::uninstallLogDispatchCallback< el::base::DefaultLogDispatchCallback >( "DefaultLogDispatchCallback" );
244  }
245  }
246 
247  // Stop logging and reset logger to initial configurations
248  void reset_logger()
249  {
253  remove_callbacks();
254 
255  minimum_log_severity = RS2_LOG_SEVERITY_NONE;
256  minimum_console_severity = RS2_LOG_SEVERITY_NONE;
257  minimum_file_severity = RS2_LOG_SEVERITY_NONE;
258  }
259 
260  // Callback: called by EL++ when the current log file has reached a certain maximum size.
261  // When the callback returns, the log-file will be truncated and reinitialized.
262  // We rename the current log file to "<filename>.old" so as not to lose the contents.
263  static void rolloutHandler( const char * filename, std::size_t size )
264  {
265  std::string file_str( filename );
266  std::string old_file = file_str + ".old";
267 
268  // Remove any existing .old
269  const char* old_filename = old_file.c_str();
270  std::ifstream exists( old_filename );
271  if( exists.is_open() )
272  {
273  exists.close();
274  std::remove( old_filename );
275  }
276 
277  std::rename( filename, old_filename );
278  }
279 
280  // Enable rolling log file:
281  // Upon reaching (max_size/2) bytes, the log will be renamed with an ".old" suffix and a new log created. Any
282  // previous .old file will be erased.
283  // Must have permissions to remove/rename files in log file directory.
284  //
285  // @param max_size max file size in megabytes
286  //
287  void enable_rolling_log_file( unsigned max_size )
288  {
289  auto max_size_in_bytes = max_size * 1024 * 1024;
290  std::string size = std::to_string(max_size_in_bytes / 2 );
291 
292  // Rollout checking happens when Easylogging++ flushes the log file!
293  // Or, with the flag el::LoggingFlags::StrictLogFileSizeCheck, at each log output...
294  //el::Loggers::addFlag( el::LoggingFlag::StrictLogFileSizeCheck );
295 
297  el::Helpers::installPreRollOutCallback( rolloutHandler );
298  }
299  };
300 #else //BUILD_EASYLOGGINGPP
301  struct log_message
302  {
303 
304  unsigned get_log_message_line_number() const {
305  throw std::runtime_error("rs2_get_log_message_line_number is not supported without BUILD_EASYLOGGINGPP");
306  }
307 
308  const char* get_log_message_filename() const {
309  throw std::runtime_error("rs2_get_log_message_filename is not supported without BUILD_EASYLOGGINGPP");
310  }
311 
312  const char* get_raw_log_message() const {
313  throw std::runtime_error("rs2_get_raw_log_message is not supported without BUILD_EASYLOGGINGPP");
314  }
315 
316  const char* get_full_log_message() {
317  throw std::runtime_error("rs2_get_full_log_message is not supported without BUILD_EASYLOGGINGPP");
318  }
319  };
320 #endif //BUILD_EASYLOGGINGPP
321 }
const base::type::string_t & message(void) const
GLint level
void reset_logger()
Definition: log.cpp:59
GLenum GLuint GLenum severity
const char * get_log_message_filename() const
Definition: log.h:308
const char * get_string(rs2_rs400_visual_preset value)
static void installPreRollOutCallback(const PreRollOutCallback &callback)
Installs pre rollout callback, this callback is triggered when log file is about to be rolled out (ca...
static Logger * reconfigureLogger(Logger *logger, const Configurations &configurations)
Reconfigures specified logger with new configurations.
virtual base::type::string_t build(const LogMessage *logMessage, bool appendNewLine) const =0
GLuint const GLchar * name
Information representing errors in application but application will keep running. ...
const char * get_full_log_message()
Definition: log.h:316
void log_to_callback(rs2_log_severity min_severity, log_callback_ptr callback)
Definition: log.cpp:54
GLuint64 GLenum void * handle
Definition: glext.h:7785
Informational events most useful for developers to debug application.
void set(Level level, ConfigurationType configurationType, const std::string &value)
Sets value of configuration for specified level.
Severe error information that will presumably abort application.
void setGlobally(ConfigurationType configurationType, const std::string &value)
Sets configuration for all levels.
GLsizei const GLchar *const * string
void log_to_file(rs2_log_severity min_severity, const char *file_path)
Definition: log.cpp:49
Represents unknown level.
Level
Represents enumeration for severity level used to determine level of logging.
Determines log file (full path) to write logs to for correponding level and logger.
std::shared_ptr< rs2_log_callback > log_callback_ptr
Definition: src/types.h:202
Information that can be highly useful and vary with verbose logging level.
Determines format of logging corresponding level and logger.
GLsizeiptr size
unsigned get_log_message_line_number() const
Definition: log.h:304
unsigned int uint32_t
Definition: stdint.h:80
std::string datetime_string()
Definition: src/types.h:1516
def callback(frame)
Definition: t265_stereo.py:91
Useful when application has potentially harmful situtaions.
#define NAME
Definition: pybackend.cpp:26
LogBuilder * logBuilder(void) const
Thread-safe Configuration repository.
Mainly useful to represent current progress of application.
void enable_rolling_log_file(unsigned max_size)
Definition: log.cpp:64
Specifies number of log entries to hold until we flush pending log data.
Level level(void) const
base::type::LineNumber line(void) const
int i
Whether or not to write corresponding log to log file.
Whether or not to write corresponding level and logger log to standard output. By standard output mea...
GLuint GLenum GLenum transform
Definition: glext.h:11553
void log_to_console(rs2_log_severity min_severity)
Definition: log.cpp:44
Logger * logger(void) const
const char * get_raw_log_message() const
Definition: log.h:312
rs2_log_severity
Severity of the librealsense logger.
Definition: rs_types.h:153
const std::string & file(void) const
Definition: parser.hpp:150
Information that can be useful to back-trace certain events - mostly useful than debug logs...
Specifies log file max size.
void setToDefault(void)
Sets configurations to "factory based" configurations.
std::string to_string(T value)


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:21