/Users/deen/code/yugabyte-db/src/yb/util/logging.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
19 | | // you may not use this file except in compliance with the License. |
20 | | // You may obtain a copy of the License at |
21 | | // |
22 | | // http://www.apache.org/licenses/LICENSE-2.0 |
23 | | // |
24 | | // Unless required by applicable law or agreed to in writing, software |
25 | | // distributed under the License is distributed on an "AS IS" BASIS, |
26 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
27 | | // See the License for the specific language governing permissions and |
28 | | // limitations under the License. |
29 | | // |
30 | | // The following only applies to changes made to this file as part of YugaByte development. |
31 | | // |
32 | | // Portions Copyright (c) YugaByte, Inc. |
33 | | // |
34 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
35 | | // in compliance with the License. You may obtain a copy of the License at |
36 | | // |
37 | | // http://www.apache.org/licenses/LICENSE-2.0 |
38 | | // |
39 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
40 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
41 | | // or implied. See the License for the specific language governing permissions and limitations |
42 | | // under the License. |
43 | | |
44 | | #ifndef YB_UTIL_LOGGING_H |
45 | | #define YB_UTIL_LOGGING_H |
46 | | |
47 | | #include <mutex> |
48 | | #include <string> |
49 | | |
50 | | #include <boost/preprocessor/cat.hpp> |
51 | | #include <boost/preprocessor/stringize.hpp> |
52 | | #include <glog/logging.h> |
53 | | |
54 | | #include "yb/gutil/atomicops.h" |
55 | | #include "yb/gutil/dynamic_annotations.h" |
56 | | #include "yb/gutil/walltime.h" |
57 | | |
58 | | #include "yb/util/logging_callback.h" |
59 | | #include "yb/util/monotime.h" |
60 | | |
61 | | //////////////////////////////////////////////////////////////////////////////// |
62 | | // Throttled logging support |
63 | | //////////////////////////////////////////////////////////////////////////////// |
64 | | |
65 | | // Logs a message throttled to appear at most once every 'n_secs' seconds to |
66 | | // the given severity. |
67 | | // |
68 | | // The log message may include the special token 'THROTTLE_MSG' which expands |
69 | | // to either an empty string or '[suppressed <n> similar messages]'. |
70 | | // |
71 | | // Example usage: |
72 | | // YB_LOG_EVERY_N_SECS(WARNING, 1) << "server is low on memory" << THROTTLE_MSG; |
73 | | #define YB_LOG_EVERY_N_SECS(severity, n_secs) \ |
74 | 7.30M | static yb::logging_internal::LogThrottler LOG_THROTTLER; \ |
75 | 7.30M | int num_suppressed = 0; \ |
76 | 7.02M | if (LOG_THROTTLER.ShouldLog(n_secs, &num_suppressed)) \ |
77 | 37.2k | BOOST_PP_CAT(GOOGLE_LOG_, severity)(num_suppressed).stream() |
78 | | |
79 | | #define YB_LOG_WITH_PREFIX_EVERY_N_SECS(severity, n_secs) \ |
80 | 65.8k | YB_LOG_EVERY_N_SECS(severity, n_secs) << LogPrefix() |
81 | | |
82 | | #define YB_LOG_WITH_PREFIX_UNLOCKED_EVERY_N_SECS(severity, n_secs) \ |
83 | 9.89k | YB_LOG_EVERY_N_SECS(severity, n_secs) << LogPrefixUnlocked() |
84 | | |
85 | | // Logs a messages with 2 different severities. By default used severity1, but if during |
86 | | // duration there were more than count messages, then it will use severity2. |
87 | | #define YB_LOG_HIGHER_SEVERITY_WHEN_TOO_MANY(severity1, severity2, duration, count) \ |
88 | 298k | static yb::logging_internal::LogRateThrottler LOG_THROTTLER(duration, count); \ |
89 | 298k | google::LogMessage( \ |
90 | 298k | __FILE__, __LINE__, \ |
91 | 298k | LOG_THROTTLER.TooMany() ? BOOST_PP_CAT(google::GLOG_, severity2) \ |
92 | 298k | : BOOST_PP_CAT(google::GLOG_, severity1)).stream() |
93 | | |
94 | | namespace yb { |
95 | | enum PRIVATE_ThrottleMsg {THROTTLE_MSG}; |
96 | | } // namespace yb |
97 | | |
98 | | //////////////////////////////////////////////////////////////////////////////// |
99 | | // Versions of glog macros for "LOG_EVERY" and "LOG_FIRST" that annotate the |
100 | | // benign races on their internal static variables. |
101 | | //////////////////////////////////////////////////////////////////////////////// |
102 | | |
103 | | // The "base" macros. |
104 | | #define YB_SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \ |
105 | 12.5M | static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \ |
106 | 12.5M | ANNOTATE_BENIGN_RACE(&LOG_OCCURRENCES, "Logging every N is approximate"); \ |
107 | 12.5M | ANNOTATE_BENIGN_RACE(&LOG_OCCURRENCES_MOD_N, "Logging every N is approximate"); \ |
108 | 12.5M | ++LOG_OCCURRENCES; \ |
109 | 12.5M | if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ |
110 | 12.5M | if (LOG_OCCURRENCES_MOD_N == 1) \ |
111 | 16.9k | google::LogMessage( \ |
112 | 16.9k | __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ |
113 | 16.9k | &what_to_do).stream() |
114 | | |
115 | | #define YB_SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \ |
116 | 30.1M | static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \ |
117 | 30.1M | ANNOTATE_BENIGN_RACE(&LOG_OCCURRENCES, "Logging every N is approximate"); \ |
118 | 30.1M | ANNOTATE_BENIGN_RACE(&LOG_OCCURRENCES_MOD_N, "Logging every N is approximate"); \ |
119 | 30.1M | ++LOG_OCCURRENCES; \ |
120 | 30.1M | if (condition && \ |
121 | 0 | ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \ |
122 | 0 | google::LogMessage( \ |
123 | 0 | __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ |
124 | 0 | &what_to_do).stream() |
125 | | |
126 | | #define YB_SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \ |
127 | | static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \ |
128 | | ANNOTATE_BENIGN_RACE(&LOG_OCCURRENCES, "Logging every N is approximate"); \ |
129 | | ANNOTATE_BENIGN_RACE(&LOG_OCCURRENCES_MOD_N, "Logging every N is approximate"); \ |
130 | | ++LOG_OCCURRENCES; \ |
131 | | if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ |
132 | | if (LOG_OCCURRENCES_MOD_N == 1) \ |
133 | | google::ErrnoLogMessage( \ |
134 | | __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ |
135 | | &what_to_do).stream() |
136 | | |
137 | | #define YB_SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \ |
138 | 134k | static uint64_t LOG_OCCURRENCES = 0; \ |
139 | 134k | ANNOTATE_BENIGN_RACE(&LOG_OCCURRENCES, "Logging the first N is approximate"); \ |
140 | 95.1k | if (LOG_OCCURRENCES++ < (n)) \ |
141 | 14.9k | google::LogMessage( \ |
142 | 14.9k | __FILE__, __LINE__, google::GLOG_ ## severity, static_cast<int>(LOG_OCCURRENCES), \ |
143 | 14.9k | &what_to_do).stream() |
144 | | |
145 | | // The direct user-facing macros. |
146 | | #define YB_LOG_EVERY_N(severity, n) \ |
147 | 15.6M | static_assert(google::GLOG_ ## severity < google::NUM_SEVERITIES, \ |
148 | 15.6M | "Invalid requested log severity"); \ |
149 | 12.5M | YB_SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) |
150 | | |
151 | 334k | #define YB_LOG_WITH_PREFIX_EVERY_N(severity, n) YB_LOG_EVERY_N(severity, n) << LogPrefix() |
152 | | #define YB_LOG_WITH_PREFIX_UNLOCKED_EVERY_N(severity, n) \ |
153 | | YB_LOG_EVERY_N(severity, n) << LogPrefixUnlocked() |
154 | | |
155 | | #define YB_SYSLOG_EVERY_N(severity, n) \ |
156 | | YB_SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog) |
157 | | |
158 | | #define YB_PLOG_EVERY_N(severity, n) \ |
159 | | YB_SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) |
160 | | |
161 | | #define YB_LOG_FIRST_N(severity, n) \ |
162 | 95.1k | YB_SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog) |
163 | | |
164 | | #define YB_LOG_IF_EVERY_N(severity, condition, n) \ |
165 | 30.1M | YB_SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog) |
166 | | |
167 | | // We also disable the un-annotated glog macros for anyone who includes this header. |
168 | | #undef LOG_EVERY_N |
169 | | #define LOG_EVERY_N(severity, n) \ |
170 | | GOOGLE_GLOG_COMPILE_ASSERT(false, "LOG_EVERY_N is deprecated. Please use YB_LOG_EVERY_N.") |
171 | | |
172 | | #undef SYSLOG_EVERY_N |
173 | | #define SYSLOG_EVERY_N(severity, n) \ |
174 | | GOOGLE_GLOG_COMPILE_ASSERT(false, "SYSLOG_EVERY_N is deprecated. Please use YB_SYSLOG_EVERY_N.") |
175 | | |
176 | | #undef PLOG_EVERY_N |
177 | | #define PLOG_EVERY_N(severity, n) \ |
178 | | GOOGLE_GLOG_COMPILE_ASSERT(false, "PLOG_EVERY_N is deprecated. Please use YB_PLOG_EVERY_N.") |
179 | | |
180 | | #undef LOG_FIRST_N |
181 | | #define LOG_FIRST_N(severity, n) \ |
182 | | GOOGLE_GLOG_COMPILE_ASSERT(false, "LOG_FIRST_N is deprecated. Please use YB_LOG_FIRST_N.") |
183 | | |
184 | | #undef LOG_IF_EVERY_N |
185 | | #define LOG_IF_EVERY_N(severity, condition, n) \ |
186 | | GOOGLE_GLOG_COMPILE_ASSERT(false, "LOG_IF_EVERY_N is deprecated. Please use YB_LOG_IF_EVERY_N.") |
187 | | |
188 | | namespace yb { |
189 | | |
190 | | // glog doesn't allow multiple invocations of InitGoogleLogging. This method conditionally |
191 | | // calls InitGoogleLogging only if it hasn't been called before. |
192 | | // |
193 | | // It also takes care of installing the google failure signal handler. |
194 | | void InitGoogleLoggingSafe(const char* arg); |
195 | | |
196 | | // Like InitGoogleLoggingSafe() but stripped down: no signal handlers are |
197 | | // installed, regular logging is disabled, and log events of any severity |
198 | | // will be written to stderr. |
199 | | // |
200 | | // These properties make it attractive for us in libraries. |
201 | | void InitGoogleLoggingSafeBasic(const char* arg); |
202 | | |
203 | | // Like InitGoogleLoggingSafeBasic() but nothing will be written to stderr. |
204 | | void InitGoogleLoggingSafeBasicSuppressNonNativePostgresLogs(const char* arg); |
205 | | |
206 | | // Check if Google Logging has been initialized. Can be used e.g. to determine whether to print |
207 | | // something to stderr or log it. The implementation takes the logging mutex, so should not be used |
208 | | // in hot codepaths. |
209 | | bool IsLoggingInitialized(); |
210 | | |
211 | | // Demotes stderr logging to ERROR or higher and registers 'cb' as the |
212 | | // recipient for all log events. |
213 | | // |
214 | | // Subsequent calls to RegisterLoggingCallback no-op (until the callback |
215 | | // is unregistered with UnregisterLoggingCallback()). |
216 | | void RegisterLoggingCallback(const LoggingCallback& cb); |
217 | | |
218 | | // Unregisters a callback previously registered with |
219 | | // RegisterLoggingCallback() and promotes stderr logging back to all |
220 | | // severities. |
221 | | // |
222 | | // If no callback is registered, this is a no-op. |
223 | | void UnregisterLoggingCallback(); |
224 | | |
225 | | // Returns the full pathname of the symlink to the most recent log |
226 | | // file corresponding to this severity |
227 | | void GetFullLogFilename(google::LogSeverity severity, std::string* filename); |
228 | | |
229 | | // Shuts down the google logging library. Call before exit to ensure that log files are |
230 | | // flushed. |
231 | | void ShutdownLoggingSafe(); |
232 | | |
233 | | // Writes all command-line flags to the log at level INFO. |
234 | | void LogCommandLineFlags(); |
235 | | |
236 | | // Internal function. Used by tooling for integrating with PostgreSQL C codebase. |
237 | | void InitializeGoogleLogging(const char *arg); |
238 | | |
239 | | namespace logging_internal { |
240 | | |
241 | | // Internal implementation class used for throttling log messages. |
242 | | class LogThrottler { |
243 | | public: |
244 | 18.8k | LogThrottler() : num_suppressed_(0), last_ts_(0) { |
245 | 18.8k | ANNOTATE_BENIGN_RACE(&last_ts_, "OK to be sloppy with log throttling"); |
246 | 18.8k | } |
247 | | |
248 | 6.98M | bool ShouldLog(int n_secs, int* num_suppressed) { |
249 | 6.98M | MicrosecondsInt64 ts = GetMonoTimeMicros(); |
250 | 6.98M | if (ts - last_ts_ < n_secs * 1e6) { |
251 | 6.66M | *num_suppressed = base::subtle::NoBarrier_AtomicIncrement(&num_suppressed_, 1); |
252 | 6.66M | return false; |
253 | 6.66M | } |
254 | 317k | last_ts_ = ts; |
255 | 317k | *num_suppressed = base::subtle::NoBarrier_AtomicExchange(&num_suppressed_, 0); |
256 | 317k | return true; |
257 | 317k | } |
258 | | private: |
259 | | Atomic32 num_suppressed_; |
260 | | uint64_t last_ts_; |
261 | | }; |
262 | | |
263 | | // Utility class that is used by YB_LOG_HIGHER_SEVERITY_WHEN_TOO_MANY macros. |
264 | | class LogRateThrottler { |
265 | | public: |
266 | | LogRateThrottler(const CoarseMonoClock::duration& duration, int count) |
267 | 17 | : duration_(duration), queue_(count) {} |
268 | | |
269 | | bool TooMany(); |
270 | | private: |
271 | | std::mutex mutex_; |
272 | | CoarseMonoClock::duration duration_; |
273 | | // Use manual queue implementation to avoid including too heavy boost/circular_buffer |
274 | | // to this very frequently used header. |
275 | | std::vector<CoarseMonoClock::time_point> queue_; |
276 | | size_t head_ = 0; |
277 | | size_t count_ = 0; |
278 | | }; |
279 | | |
280 | | } // namespace logging_internal |
281 | | |
282 | | std::ostream& operator<<(std::ostream &os, const PRIVATE_ThrottleMsg&); |
283 | | |
284 | | // Convenience macros to prefix log messages with some prefix, these are the unlocked |
285 | | // versions and should not obtain a lock (if one is required to obtain the prefix). |
286 | | // There must be a LogPrefixUnlocked()/LogPrefixLocked() method available in the current |
287 | | // scope in order to use these macros. |
288 | 586k | #define LOG_WITH_PREFIX_UNLOCKED(severity) LOG(severity) << LogPrefixUnlocked() |
289 | 7.83M | #define VLOG_WITH_PREFIX_UNLOCKED(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel)) \ |
290 | 7.83M | << LogPrefixUnlocked() |
291 | | |
292 | | // Same as the above, but obtain the lock. |
293 | 26.4M | #define LOG_WITH_PREFIX(severity) LOG(severity) << LogPrefix() |
294 | 14.2k | #define LOG_WITH_FUNC(severity) LOG(severity) << __func__ << ": " |
295 | 2.11k | #define LOG_WITH_PREFIX_AND_FUNC(severity) LOG_WITH_PREFIX(severity) << __func__ << ": " |
296 | | |
297 | 65.9M | #define VLOG_WITH_PREFIX(verboselevel) VLOG(verboselevel) << LogPrefix() |
298 | 551k | #define VLOG_WITH_FUNC(verboselevel) VLOG(verboselevel) << __func__ << ": " |
299 | 256k | #define DVLOG_WITH_FUNC(verboselevel) DVLOG(verboselevel) << __func__ << ": " |
300 | 33.8M | #define VLOG_WITH_PREFIX_AND_FUNC(verboselevel) VLOG_WITH_PREFIX(verboselevel) << __func__ << ": " |
301 | | |
302 | 42.9M | #define DVLOG_WITH_PREFIX(verboselevel) DVLOG(verboselevel) << LogPrefix() |
303 | 77.3k | #define LOG_IF_WITH_PREFIX(severity, condition) LOG_IF(severity, condition) << LogPrefix() |
304 | 18.4E | #define VLOG_IF_WITH_PREFIX(verboselevel, condition) VLOG_IF(verboselevel, condition) << LogPrefix() |
305 | | |
306 | | // DCHECK_ONLY_NOTNULL is like DCHECK_NOTNULL, but does not result in an unused expression in |
307 | | // release mode, so it is suitable for being used as a stand-alone statement. In other words, use |
308 | | // DCHECK_NOTNULL when you care about the result (e.g. when assigning it to a variable), and use |
309 | | // DCHECK_ONLY_NOTNULL when you want to verify that an expression is not null in debug mode, but do |
310 | | // nothing in release. |
311 | | // E.g. |
312 | | // DCHECK_ONLY_NOTNULL(my_ptr) |
313 | | // SomeType* p = DCHECK_NOTNULL(SomeFunc()); |
314 | | |
315 | | #define CHECK_BETWEEN(val, lower_bound, upper_bound) \ |
316 | | do { CHECK_GE(val, lower_bound); CHECK_LE(val, upper_bound); } while(false) |
317 | | |
318 | | #ifndef NDEBUG |
319 | 221M | #define DCHECK_ONLY_NOTNULL(expr) do { DCHECK_NOTNULL(expr); } while(false) |
320 | | #define DCHECK_BETWEEN(val, lower_bound, upper_bound) CHECK_BETWEEN(val, lower_bound, upper_bound) |
321 | | #else |
322 | | #define DCHECK_ONLY_NOTNULL(expr) do {} while(false) |
323 | | #define DCHECK_BETWEEN(val, lower_bound, upper_bound) \ |
324 | | GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ |
325 | | while (false) \ |
326 | | GLOG_MSVC_POP_WARNING() CHECK_BETWEEN(val, lower_bound, upper_bound) |
327 | | #endif |
328 | | |
329 | | // Unlike plain LOG(FATAL), here the compiler always knows we're not returning. |
330 | | #define FATAL_ERROR(msg) \ |
331 | 18.4E | do { \ |
332 | 18.4E | LOG(FATAL) << (msg); \ |
333 | 18.4E | abort(); \ |
334 | 0 | } while (false) |
335 | | |
336 | | void DisableCoreDumps(); |
337 | | |
338 | | // Get the path prefix for files that will contain details of a fatal crash (message and stack |
339 | | // trace). This is based on the --fatal_details_path_prefix flag and the |
340 | | // YB_FATAL_DETAILS_PATH_PREFIX environment variable. If neither of those are set, the result is |
341 | | // based on the FATAL log path. |
342 | | string GetFatalDetailsPathPrefix(); |
343 | | |
344 | | // Implements special handling for LOG(FATAL) and CHECK failures, such as disabling core dumps and |
345 | | // printing the failure stack trace into a separate file. |
346 | | class LogFatalHandlerSink : public google::LogSink { |
347 | | public: |
348 | | LogFatalHandlerSink(); |
349 | | ~LogFatalHandlerSink(); |
350 | | void send(google::LogSeverity severity, const char* /* full_filename */, |
351 | | const char* base_filename, int line, const struct tm* tm_time, const char* message, |
352 | | size_t message_len) override; |
353 | | }; |
354 | | |
355 | 110k | #define EXPR_VALUE_FOR_LOG(expr) BOOST_PP_STRINGIZE(expr) << "=" << (yb::ToString(expr)) |
356 | | |
357 | | } // namespace yb |
358 | | |
359 | | #endif // YB_UTIL_LOGGING_H |