HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
logging.h
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License.
3 
4 #pragma once
5 
6 #include <atomic>
7 #include <chrono>
8 #include <climits>
9 #include <map>
10 #include <memory>
11 #include <mutex>
12 #include <string>
13 
14 #include "core/common/common.h"
18 
20 
21 /*
22 
23  Logging overview and expected usage:
24 
25  At program startup:
26  * Create one or more ISink instances. If multiple, combine using composite_sink.
27  * Create a LoggingManager instance with the sink/s with is_default_instance set to true
28  * Only one instance should be created in this way, and it should remain valid for
29  until the program no longer needs to produce log output.
30 
31  You can either use the static default Logger which LoggingManager will create when constructed
32  via LoggingManager::DefaultLogger(), or separate Logger instances each with different log ids
33  via LoggingManager::CreateLogger.
34 
35  The log id is passed to the ISink instance with the sink determining how the log id is used
36  in the output.
37 
38  LoggingManager
39  * creates the Logger instances used by the application
40  * provides a static default logger instance
41  * owns the log sink instance
42  * applies checks on severity and output of user data
43 
44  The log macros create a Capture instance to capture the information to log.
45  If the severity and/or user filtering settings would prevent logging, no evaluation
46  of the log arguments will occur, so no performance cost beyond the severity and user
47  filtering check.
48 
49  A sink can do further filter as needed.
50 
51 */
52 
53 namespace onnxruntime {
54 
55 namespace logging {
56 
57 using Timestamp = std::chrono::time_point<std::chrono::system_clock>;
58 
59 #ifndef NDEBUG
60 ORT_ATTRIBUTE_UNUSED static bool vlog_enabled = true; // Set directly based on your needs.
61 #else
62 constexpr bool vlog_enabled = false; // no VLOG output
63 #endif
64 
65 enum class DataType {
66  SYSTEM = 0, ///< System data.
67  USER = 1 ///< Contains potentially sensitive user data.
68 };
69 
70 // Internal log categories.
71 // Logging interface takes const char* so arbitrary values can also be used.
72 struct Category {
73  static const char* onnxruntime; ///< General output
74  static const char* System; ///< Log output regarding interactions with the host system
75  // TODO: What other high level categories are meaningful? Model? Optimizer? Execution?
76 };
77 
78 /// <summary>
79 /// ORT TraceLogging keywords for categories of dynamic logging enablement
80 /// </summary>
81 enum class ORTTraceLoggingKeyword : uint64_t {
82  Session = 0x1, // ORT Session TraceLoggingWrite
83  Logs = 0x2, // LOGS() Macro ORT logs. Pair with an appropriate level depending on detail required
84  Reserved1 = 0x4, // Reserved if we want to add some specific sub-categories instead of just LOGS() or other uses
85  Reserved2 = 0x8,
86  Reserved3 = 0x10,
87  Reserved4 = 0x20,
88  Reserved5 = 0x40,
89  Reserved6 = 0x80,
90  Profiling = 0x100 // Enables profiling. At higher levels >5 can impact inference performance
91 };
92 
93 class ISink;
94 class Logger;
95 class Capture;
96 
97 /// <summary>
98 /// The logging manager.
99 /// Owns the log sink and potentially provides a default Logger instance.
100 /// Provides filtering based on a minimum LogSeverity level, and of messages with DataType::User if enabled.
101 /// </summary>
102 class LoggingManager final {
103  public:
105  Default, ///< Default instance of LoggingManager that should exist for the lifetime of the program
106  Temporal ///< Temporal instance. CreateLogger(...) should be used, however DefaultLogger() will NOT be provided via this instance.
107  };
108 
109  /**
110  Initializes a new instance of the LoggingManager class.
111  @param sink The sink to write to. Use CompositeSink if you need to write to multiple places.
112  @param default_min_severity The default minimum severity. Messages with lower severity will be ignored unless
113  overridden in CreateLogger.
114  @param default_filter_user_data If set to true ignore messages with DataType::USER unless overridden in CreateLogger.
115  @param instance_type If InstanceType::Default, this is the default instance of the LoggingManager
116  and is expected to exist for the lifetime of the program.
117  It creates and owns the default logger that calls to the static DefaultLogger method return.
118  @param default_logger_id Logger Id to use for the default logger. nullptr/ignored if instance_type == Temporal.
119  @param default_max_vlog_level Default maximum level for VLOG messages to be created unless overridden in CreateLogger.
120  Requires a severity of kVERBOSE for VLOG messages to be logged.
121  */
122  LoggingManager(std::unique_ptr<ISink> sink, Severity default_min_severity, bool default_filter_user_data,
123  InstanceType instance_type,
124  const std::string* default_logger_id = nullptr,
125  int default_max_vlog_level = -1);
126 
127  /**
128  Creates a new logger instance which will use the provided logger_id and default severity and vlog levels.
129  @param logger_id The log identifier.
130  @returns A new Logger instance that the caller owns.
131  */
132  std::unique_ptr<Logger> CreateLogger(const std::string& logger_id);
133 
134  /**
135  Creates a new logger instance which will use the provided logger_id, severity and vlog levels.
136  @param logger_id The log identifier.
137  @param min_severity The minimum severity. Requests to create messages with lower severity will be ignored.
138  @param filter_user_data If set to true ignore messages with DataType::USER.
139  @param max_vlog_level Maximum level for VLOG messages to be created.
140  @returns A new Logger instance that the caller owns.
141  */
142  std::unique_ptr<Logger> CreateLogger(const std::string& logger_id,
143  Severity min_severity, bool filter_user_data, int max_vlog_level = -1);
144 
145  /**
146  Gets the default logger instance if set. Throws if no default logger is currently registered.
147  @remarks
148  Creating a LoggingManager instance with is_default_instance == true registers a default logger.
149  Note that the default logger is only valid until the LoggerManager that registered it is destroyed.
150  @returns The default logger if available.
151  */
152  static const Logger& DefaultLogger();
153 
154  /**
155  Return a boolean indicating if the default logger has been initialized
156  */
157  static bool HasDefaultLogger() { return nullptr != s_default_logger_; }
158 
159  /**
160  Change the minimum severity level for log messages to be output by the default logger.
161  @param severity The severity.
162  */
164 
165  /**
166  Change the maximum verbosity level for log messages to be output by the default logger.
167  @remarks
168  To activate the verbose log, the logger severity must also be set to kVERBOSE.
169  @param vlog_level The verbosity level.
170  */
171  static void SetDefaultLoggerVerbosity(int vlog_level);
172 
173  /**
174  Logs a FATAL level message and creates an exception that can be thrown with error information.
175  @param category The log category.
176  @param location The location the log message was generated.
177  @param format_str The printf format string.
178  @param ... The printf arguments.
179  @returns A new Logger instance that the caller owns.
180  */
181  static std::exception LogFatalAndCreateException(const char* category,
182  const CodeLocation& location,
183  const char* format_str, ...);
184 
185  /**
186  Logs the message using the provided logger id.
187  @param logger_id The log identifier.
188  @param message The log message.
189  */
190  void Log(const std::string& logger_id, const Capture& message) const;
191 
192  /**
193  Sends a Profiling Event Record to the sink.
194  @param Profiling Event Record
195  */
196  void SendProfileEvent(profiling::EventRecord& eventRecord) const;
197  ~LoggingManager();
198 
199  private:
200  ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(LoggingManager);
201 
202  Timestamp GetTimestamp() const noexcept;
203  void CreateDefaultLogger(const std::string& logger_id);
204 
205  std::unique_ptr<ISink> sink_;
206  const Severity default_min_severity_;
207  const bool default_filter_user_data_;
208  const int default_max_vlog_level_;
209  bool owns_default_logger_;
210 
211  static Logger* s_default_logger_;
212 
213  struct Epochs {
214  const std::chrono::time_point<std::chrono::high_resolution_clock> high_res;
215  const std::chrono::time_point<std::chrono::system_clock> system;
216  const std::chrono::minutes localtime_offset_from_utc;
217  };
218 
219  static const Epochs& GetEpochs() noexcept;
220 };
221 
222 /**
223  Logger provides a per-instance log id. Everything else is passed back up to the LoggingManager
224 */
226  public:
227  /**
228  Initializes a new instance of the Logger class.
229  @param loggingManager The logging manager.
230  @param id The identifier for messages coming from this Logger.
231  @param severity Minimum severity for messages to be created and logged.
232  @param filter_user_data Should USER data be filtered from output.
233  @param vlog_level Minimum level for VLOG messages to be created. Note that a severity of kVERBOSE must be provided
234  for VLOG messages to be logged.
235  */
236  Logger(const LoggingManager& loggingManager, std::string id,
237  Severity severity, bool filter_user_data, int vlog_level)
238  : logging_manager_{&loggingManager},
239  id_{id},
240  min_severity_{severity},
241  filter_user_data_{filter_user_data},
242  max_vlog_level_{vlog_level} {
243  }
244 
245  /**
246  Get the minimum severity level for log messages to be output.
247  @returns The severity.
248  */
249  Severity GetSeverity() const noexcept { return min_severity_; }
250 
251  /**
252  Change the minimum severity level for log messages to be output.
253  @param severity The severity.
254  */
255  void SetSeverity(Severity severity) noexcept { min_severity_ = severity; }
256 
257  /**
258  Change the maximum verbosity level for log messages to be output.
259  @remarks
260  To activate the verbose log, the logger severity must also be set to kVERBOSE.
261  @param vlog_level The verbosity.
262  */
263  void SetVerbosity(int vlog_level) noexcept { max_vlog_level_ = vlog_level; }
264 
265  /**
266  Check if output is enabled for the provided LogSeverity and DataType values.
267  @param severity The severity.
268  @param data_type Type of the data.
269  @returns True if a message with these values will be logged.
270  */
271  bool OutputIsEnabled(Severity severity, DataType data_type) const noexcept {
272  return (severity >= min_severity_ && (data_type != DataType::USER || !filter_user_data_));
273  }
274 
275  /**
276  Return the maximum VLOG level allowed. Disabled unless logging VLOG messages
277  */
278  int VLOGMaxLevel() const noexcept {
279  return min_severity_ > Severity::kVERBOSE ? -1 : max_vlog_level_;
280  }
281 
282  /**
283  Logs the captured message.
284  @param message The log message.
285  */
286  void Log(const Capture& message) const {
287  logging_manager_->Log(id_, message);
288  }
289 
290  /**
291  Sends a Profiling Event Record to the sink.
292  @param Profiling Event Record
293  */
294  void SendProfileEvent(profiling::EventRecord& eventRecord) const {
295  logging_manager_->SendProfileEvent(eventRecord);
296  }
297 
298  private:
299  const LoggingManager* logging_manager_;
300  const std::string id_;
301  Severity min_severity_;
302  const bool filter_user_data_;
303  int max_vlog_level_;
304 };
305 
307  if (s_default_logger_ == nullptr) {
308  // fail early for attempted misuse. don't use logging macros as we have no logger.
309  ORT_THROW("Attempt to use DefaultLogger but none has been registered.");
310  }
311 
312  return *s_default_logger_;
313 }
314 
316  if (s_default_logger_ == nullptr) {
317  // fail early for attempted misuse. don't use logging macros as we have no logger.
318  ORT_THROW("Attempt to use DefaultLogger but none has been registered.");
319  }
320 
321  s_default_logger_->SetSeverity(severity);
322 }
323 
324 inline void LoggingManager::SetDefaultLoggerVerbosity(int vlog_level) {
325  if (s_default_logger_ == nullptr) {
326  // fail early for attempted misuse. don't use logging macros as we have no logger.
327  ORT_THROW("Attempt to use DefaultLogger but none has been registered.");
328  }
329 
330  s_default_logger_->SetVerbosity(vlog_level);
331 }
332 
333 inline Timestamp LoggingManager::GetTimestamp() const noexcept {
334  static const Epochs& epochs = GetEpochs();
335 
336  const auto high_res_now = std::chrono::high_resolution_clock::now();
337  return std::chrono::time_point_cast<std::chrono::system_clock::duration>(
338  epochs.system + (high_res_now - epochs.high_res) + epochs.localtime_offset_from_utc);
339 }
340 
341 /**
342  Return the current thread id.
343 */
344 unsigned int GetThreadId();
345 
346 /**
347  Return the current process id.
348 */
349 unsigned int GetProcessId();
350 
351 /**
352  If the ONNXRuntimeTraceLoggingProvider ETW Provider is enabled, then adds to the existing logger.
353 */
354 std::unique_ptr<ISink> EnhanceLoggerWithEtw(std::unique_ptr<ISink> existingLogger, logging::Severity originalSeverity,
355  logging::Severity etwSeverity);
356 
357 /**
358  If the ONNXRuntimeTraceLoggingProvider ETW Provider is enabled, then can override the logging level.
359  But this overrided level only applies to the ETW sink. The original logger(s) retain their original logging level
360 */
361 Severity OverrideLevelWithEtw(Severity originalSeverity);
362 
363 } // namespace logging
364 } // namespace onnxruntime
Logger(const LoggingManager &loggingManager, std::string id, Severity severity, bool filter_user_data, int vlog_level)
Definition: logging.h:236
GLuint GLsizei const GLchar * message
Definition: glcorearb.h:2543
void Log(const std::string &logger_id, const Capture &message) const
*get result *(waiting if necessary)*A common idiom is to fire a bunch of sub tasks at the and then *wait for them to all complete We provide a helper class
Definition: thread.h:623
std::unique_ptr< Logger > CreateLogger(const std::string &logger_id)
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
void SendProfileEvent(profiling::EventRecord &eventRecord) const
Definition: logging.h:294
LoggingManager(std::unique_ptr< ISink > sink, Severity default_min_severity, bool default_filter_user_data, InstanceType instance_type, const std::string *default_logger_id=nullptr, int default_max_vlog_level=-1)
void SendProfileEvent(profiling::EventRecord &eventRecord) const
static void SetDefaultLoggerSeverity(Severity severity)
Definition: logging.h:315
Contains potentially sensitive user data.
unsigned int GetThreadId()
Temporal instance. CreateLogger(...) should be used, however DefaultLogger() will NOT be provided via...
Definition: logging.h:106
ORTTraceLoggingKeyword
ORT TraceLogging keywords for categories of dynamic logging enablement
Definition: logging.h:81
unsigned int GetProcessId()
Severity OverrideLevelWithEtw(Severity originalSeverity)
static const Logger & DefaultLogger()
Definition: logging.h:306
static const char * onnxruntime
General output.
Definition: logging.h:73
The logging manager. Owns the log sink and potentially provides a default Logger instance. Provides filtering based on a minimum LogSeverity level, and of messages with DataType::User if enabled.
Definition: logging.h:102
std::chrono::time_point< std::chrono::system_clock > Timestamp
Definition: logging.h:57
void SetVerbosity(int vlog_level) noexcept
Definition: logging.h:263
std::unique_ptr< ISink > EnhanceLoggerWithEtw(std::unique_ptr< ISink > existingLogger, logging::Severity originalSeverity, logging::Severity etwSeverity)
#define ORT_ATTRIBUTE_UNUSED
Definition: common.h:66
GLint location
Definition: glcorearb.h:805
GLenum GLenum severity
Definition: glcorearb.h:2539
static void SetDefaultLoggerVerbosity(int vlog_level)
Definition: logging.h:324
Severity GetSeverity() const noexcept
Definition: logging.h:249
#define ORT_THROW(...)
Definition: common.h:162
void SetSeverity(Severity severity) noexcept
Definition: logging.h:255
bool OutputIsEnabled(Severity severity, DataType data_type) const noexcept
Definition: logging.h:271
void Log(const Capture &message) const
Definition: logging.h:286
static const char * System
Log output regarding interactions with the host system.
Definition: logging.h:74
int VLOGMaxLevel() const noexcept
Definition: logging.h:278
static std::exception LogFatalAndCreateException(const char *category, const CodeLocation &location, const char *format_str,...)
Default instance of LoggingManager that should exist for the lifetime of the program.
Definition: logging.h:105