Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
logging.cc
Go to the documentation of this file.
1 
18 #include "ion/base/logging.h"
19 
20 #include <functional>
21 #include <map>
22 #include <set>
23 
25 #include "ion/port/atomic.h"
26 #include "ion/port/break.h"
27 #include "ion/port/logging.h"
28 #include "ion/port/timer.h"
29 
30 namespace ion {
31 namespace base {
32 
33 namespace logging_internal {
34 
36 static port::LogEntryWriter* s_writer_ = NULL;
37 
39 static std::function<void()> s_break_handler_;
40 
41 static const std::function<void()> GetBreakHandler() {
42  static std::atomic<int> has_been_initialized_(0);
43  if (has_been_initialized_.exchange(1) == 0) {
45  }
46  return s_break_handler_;
47 }
48 
49 static port::Mutex* GetSingleLoggerMutex() {
51  return mutex;
52 }
53 
54 static std::set<std::string>& GetSingleLoggerMessageSet() {
55  ION_DECLARE_SAFE_STATIC_POINTER(std::set<std::string>, logged_messages);
56  return *logged_messages;
57 }
58 
59 static void BreakOnFatalSeverity(port::LogSeverity severity) {
60  bool is_fatal = (severity == port::FATAL);
61 #if ION_DEBUG
62  is_fatal |= (severity == port::DFATAL);
63 #endif
64  if (is_fatal) {
67  std::function<void()> break_handler = GetBreakHandler();
68  if (break_handler) {
69  break_handler();
70  }
71  }
72 }
73 
74 static bool HasLoggedMessageSince(const char* file_name, int line_number,
75  float past_seconds) {
77  const port::Timer::steady_clock::time_point now =
78  port::Timer::steady_clock::now();
79  const port::Timer::steady_clock::time_point when =
80  now - std::chrono::duration_cast<port::Timer::steady_clock::duration>(
81  std::chrono::duration<float>(past_seconds));
82  static std::map<std::string, port::Timer::steady_clock::time_point>
83  logged_messages;
84  std::stringstream str;
85  str << file_name << ":" << line_number;
86  const std::string key = str.str();
87 
88  LockGuard guard(mutex);
89  const auto& insert_pair = logged_messages.insert(std::make_pair(key, now));
90  if (insert_pair.second) {
92  return false;
93  } else {
94  if (insert_pair.first->second >= when) {
96  return true;
97  }
100  insert_pair.first->second = now;
101  return false;
102  }
103 }
104 
105 Logger::Logger(const char* filename, int line_number,
106  port::LogSeverity severity)
107  : severity_(severity) {
108  stream_ << "[" << filename << ":" << line_number << "] ";
109 }
110 
113  {
114  LockGuard guard(mutex);
115  GetLogEntryWriter()->Write(severity_, stream_.str());
116  }
117 
120  BreakOnFatalSeverity(severity_);
121 }
122 
124  BreakOnFatalSeverity(severity);
125 }
126 
127 std::ostream& NullLogger::GetStream() {
128  static std::ostream null_stream(NULL);
129  return null_stream;
130 }
131 
132 std::ostream& Logger::GetStream() { return stream_; }
133 
134 const std::string Logger::CheckMessage(const char* check_string,
135  const char* expr_string) {
136  return std::string(check_string) + " failed: expression='" + expr_string +
137  "' ";
138 }
139 
140 static std::ostream& GetNullStream() {
141  static std::ostream null_stream(NULL);
142  return null_stream;
143 }
144 
145 SingleLogger::SingleLogger(const char* file_name, int line_number,
146  port::LogSeverity severity)
147  : logger_(HasLoggedMessageAt(file_name, line_number)
148  ? NULL
149  : new Logger(file_name, line_number, severity)) {}
150 
152 
154  LockGuard guard(GetSingleLoggerMutex());
155  GetSingleLoggerMessageSet().clear();
156 }
157 
158 std::ostream& SingleLogger::GetStream() {
159  return logger_ ? logger_->GetStream() : GetNullStream();
160 }
161 
162 bool SingleLogger::HasLoggedMessageAt(const char* file_name, int line_number) {
163  LockGuard guard(GetSingleLoggerMutex());
164  std::set<std::string>& logged_messages = GetSingleLoggerMessageSet();
165  std::stringstream str;
166  str << file_name << ":" << line_number;
167  return !(logged_messages.insert(str.str()).second);
168 }
169 
170 ThrottledLogger::ThrottledLogger(const char* file_name, int line_number,
171  port::LogSeverity severity, float seconds)
172  : logger_(HasLoggedMessageSince(file_name, line_number, seconds)
173  ? NULL
174  : new Logger(file_name, line_number, severity)) {}
175 
177 
178 std::ostream& ThrottledLogger::GetStream() {
179  return logger_ ? logger_->GetStream() : GetNullStream();
180 }
181 
182 } // namespace logging_internal
183 
185 
187 
189  logging_internal::s_writer_ = w;
190 }
191 
193  return logging_internal::s_writer_ ? logging_internal::s_writer_
195 }
196 
199  port::LogEntryWriter, default_writer,
201 
202  return default_writer;
203 }
204 
205 void SetBreakHandler(const std::function<void()>& break_handler) {
207  logging_internal::GetBreakHandler();
208  logging_internal::s_break_handler_ = break_handler;
209 }
210 
212  logging_internal::s_break_handler_ = port::BreakOrAbort;
213 }
214 
215 } // namespace base
216 } // namespace ion
Logger(const char *file_name, int line_number, port::LogSeverity severity)
Definition: logging.cc:105
Abstract class which can be overridden to integrate Ion logging with other logging systems...
Definition: logging.h:36
#define ION_DECLARE_SAFE_STATIC_POINTER(type, variable)
Declare a static non-array pointer and calls a default constructor.
const std::string & str
#define ION_DECLARE_SAFE_STATIC_POINTER_WITH_CONSTRUCTOR(type, variable, constructor)
Declare a static non-array pointer and calls a non-default constructor.
static void ClearMessages()
Clears the set of messages that have been logged.
Definition: logging.cc:153
std::ostream & GetStream()
Returns the stream to which output is sent.
Definition: logging.cc:127
static const std::string CheckMessage(const char *check_string, const char *expr_string)
Returns a message that can be used in CHECK or DCHECK output.
Definition: logging.cc:134
port::LogEntryWriter * GetDefaultLogEntryWriter()
Returns the log-writer that messages will be logged to if if another is not explicitly specified via ...
Definition: logging.cc:197
LogSeverity
Definition: logging.h:26
std::ostream & GetStream()
Return the stream to which output is sent (or accumulated).
Definition: logging.cc:158
ThrottledLogger(const char *file_name, int line_number, port::LogSeverity severity, float seconds)
Definition: logging.cc:170
NullLogger()
Constructs a NullLogger that does nothing.
Definition: logging.h:96
A LockGuard locks a mutex when created, and unlocks it when destroyed.
Definition: lockguards.h:90
port::LogEntryWriter * GetLogEntryWriter()
Returns the log-writer that messages are currently logged to.
Definition: logging.cc:192
std::ostream & GetStream()
Return the stream to which output is sent (or accumulated).
Definition: logging.cc:132
SingleLogger(const char *file_name, int line_number, port::LogSeverity severity)
Definition: logging.cc:145
virtual void Write(LogSeverity severity, const std::string &message)=0
Copyright 2016 Google Inc.
std::ostream & GetStream()
Return the stream to which output is sent (or accumulated).
Definition: logging.cc:178
void BreakOrAbort()
Calls Break() if running in a debugger, abort() otherwise.
Definition: break.cc:141
void RestoreDefaultBreakHandler()
Restores the default break handler (port::BreakAndAbort).
Definition: logging.cc:211
void SetLogEntryWriter(port::LogEntryWriter *w)
Public functions.
Definition: logging.cc:188
ION_API LogEntryWriter * CreateDefaultLogEntryWriter()
Instantiate a new LogEntryWriter of the default type for the current platform...
A Mutex is used to ensure that only one thread or process can access a block of code at one time...
Definition: mutex.h:34
void SetBreakHandler(const std::function< void()> &break_handler)
Sets a custom break handler that gets invoked by Logger::CheckMessage.
Definition: logging.cc:205
This class is used for regular logging.
Definition: logging.h:73