/src/abseil-cpp/absl/base/internal/raw_logging.h
Line  | Count  | Source  | 
1  |  | // Copyright 2017 The Abseil Authors.  | 
2  |  | //  | 
3  |  | // Licensed under the Apache License, Version 2.0 (the "License");  | 
4  |  | // you may not use this file except in compliance with the License.  | 
5  |  | // You may obtain a copy of the License at  | 
6  |  | //  | 
7  |  | //      https://www.apache.org/licenses/LICENSE-2.0  | 
8  |  | //  | 
9  |  | // Unless required by applicable law or agreed to in writing, software  | 
10  |  | // distributed under the License is distributed on an "AS IS" BASIS,  | 
11  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
12  |  | // See the License for the specific language governing permissions and  | 
13  |  | // limitations under the License.  | 
14  |  | //  | 
15  |  | // Thread-safe logging routines that do not allocate any memory or  | 
16  |  | // acquire any locks, and can therefore be used by low-level memory  | 
17  |  | // allocation, synchronization, and signal-handling code.  | 
18  |  |  | 
19  |  | #ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_  | 
20  |  | #define ABSL_BASE_INTERNAL_RAW_LOGGING_H_  | 
21  |  |  | 
22  |  | #include <string>  | 
23  |  |  | 
24  |  | #include "absl/base/attributes.h"  | 
25  |  | #include "absl/base/config.h"  | 
26  |  | #include "absl/base/internal/atomic_hook.h"  | 
27  |  | #include "absl/base/log_severity.h"  | 
28  |  | #include "absl/base/macros.h"  | 
29  |  | #include "absl/base/optimization.h"  | 
30  |  | #include "absl/base/port.h"  | 
31  |  |  | 
32  |  | // This is similar to LOG(severity) << format..., but  | 
33  |  | // * it is to be used ONLY by low-level modules that can't use normal LOG()  | 
34  |  | // * it is designed to be a low-level logger that does not allocate any  | 
35  |  | //   memory and does not need any locks, hence:  | 
36  |  | // * it logs straight and ONLY to STDERR w/o buffering  | 
37  |  | // * it uses an explicit printf-format and arguments list  | 
38  |  | // * it will silently chop off really long message strings  | 
39  |  | // Usage example:  | 
40  |  | //   ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);  | 
41  |  | // This will print an almost standard log line like this to stderr only:  | 
42  |  | //   E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file  | 
43  |  |  | 
44  |  | #define ABSL_RAW_LOG(severity, ...)                                            \  | 
45  | 0  |   do {                                                                         \ | 
46  | 0  |     constexpr const char* absl_raw_log_internal_basename =                     \  | 
47  | 0  |         ::absl::raw_log_internal::Basename(__FILE__, sizeof(__FILE__) - 1);    \  | 
48  | 0  |     ::absl::raw_log_internal::RawLog(ABSL_RAW_LOG_INTERNAL_##severity,         \  | 
49  | 0  |                                      absl_raw_log_internal_basename, __LINE__, \  | 
50  | 0  |                                      __VA_ARGS__);                             \  | 
51  | 0  |     ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_##severity;                        \  | 
52  | 0  |   } while (0)  | 
53  |  |  | 
54  |  | // Similar to CHECK(condition) << message, but for low-level modules:  | 
55  |  | // we use only ABSL_RAW_LOG that does not allocate memory.  | 
56  |  | // We do not want to provide args list here to encourage this usage:  | 
57  |  | //   if (!cond)  ABSL_RAW_LOG(FATAL, "foo ...", hard_to_compute_args);  | 
58  |  | // so that the args are not computed when not needed.  | 
59  |  | #define ABSL_RAW_CHECK(condition, message)                             \  | 
60  | 4.12M  |   do {                                                                 \ | 
61  | 4.12M  |     if (ABSL_PREDICT_FALSE(!(condition))) {                            \ | 
62  | 0  |       ABSL_RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \  | 
63  | 0  |     }                                                                  \  | 
64  | 4.12M  |   } while (0)  | 
65  |  |  | 
66  |  | // ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above,  | 
67  |  | // except that if the richer log library is linked into the binary, we dispatch  | 
68  |  | // to that instead.  This is potentially useful for internal logging and  | 
69  |  | // assertions, where we are using RAW_LOG neither for its async-signal-safety  | 
70  |  | // nor for its non-allocating nature, but rather because raw logging has very  | 
71  |  | // few other dependencies.  | 
72  |  | //  | 
73  |  | // The API is a subset of the above: each macro only takes two arguments.  Use  | 
74  |  | // StrCat if you need to build a richer message.  | 
75  |  | #define ABSL_INTERNAL_LOG(severity, message)                              \  | 
76  | 0  |   do {                                                                    \ | 
77  | 0  |     constexpr const char* absl_raw_log_internal_filename = __FILE__;      \  | 
78  | 0  |     ::absl::raw_log_internal::internal_log_function(                      \  | 
79  | 0  |         ABSL_RAW_LOG_INTERNAL_##severity, absl_raw_log_internal_filename, \  | 
80  | 0  |         __LINE__, message);                                               \  | 
81  | 0  |     ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_##severity;                   \  | 
82  | 0  |   } while (0)  | 
83  |  |  | 
84  |  | #define ABSL_INTERNAL_CHECK(condition, message)                    \  | 
85  | 0  |   do {                                                             \ | 
86  | 0  |     if (ABSL_PREDICT_FALSE(!(condition))) {                        \ | 
87  | 0  |       std::string death_message = "Check " #condition " failed: "; \  | 
88  | 0  |       death_message += std::string(message);                       \  | 
89  | 0  |       ABSL_INTERNAL_LOG(FATAL, death_message);                     \  | 
90  | 0  |     }                                                              \  | 
91  | 0  |   } while (0)  | 
92  |  |  | 
93  |  | #ifndef NDEBUG  | 
94  |  |  | 
95  |  | #define ABSL_RAW_DLOG(severity, ...) ABSL_RAW_LOG(severity, __VA_ARGS__)  | 
96  |  | #define ABSL_RAW_DCHECK(condition, message) ABSL_RAW_CHECK(condition, message)  | 
97  |  |  | 
98  |  | #else  // NDEBUG  | 
99  |  |  | 
100  |  | #define ABSL_RAW_DLOG(severity, ...)                   \  | 
101  |  |   while (false) ABSL_RAW_LOG(severity, __VA_ARGS__)  | 
102  |  | #define ABSL_RAW_DCHECK(condition, message) \  | 
103  |  |   while (false) ABSL_RAW_CHECK(condition, message)  | 
104  |  |  | 
105  |  | #endif  // NDEBUG  | 
106  |  |  | 
107  | 0  | #define ABSL_RAW_LOG_INTERNAL_INFO ::absl::LogSeverity::kInfo  | 
108  | 0  | #define ABSL_RAW_LOG_INTERNAL_WARNING ::absl::LogSeverity::kWarning  | 
109  | 0  | #define ABSL_RAW_LOG_INTERNAL_ERROR ::absl::LogSeverity::kError  | 
110  | 0  | #define ABSL_RAW_LOG_INTERNAL_FATAL ::absl::LogSeverity::kFatal  | 
111  |  | #define ABSL_RAW_LOG_INTERNAL_DFATAL ::absl::kLogDebugFatal  | 
112  |  | #define ABSL_RAW_LOG_INTERNAL_LEVEL(severity) \  | 
113  |  |   ::absl::NormalizeLogSeverity(severity)  | 
114  |  |  | 
115  |  | #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_INFO  | 
116  |  | #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_WARNING  | 
117  |  | #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_ERROR  | 
118  | 0  | #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_FATAL ABSL_UNREACHABLE()  | 
119  |  | #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_DFATAL  | 
120  |  | #define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_LEVEL(severity)  | 
121  |  |  | 
122  |  | namespace absl { | 
123  |  | ABSL_NAMESPACE_BEGIN  | 
124  |  | namespace raw_log_internal { | 
125  |  |  | 
126  |  | // Helper function to implement ABSL_RAW_LOG  | 
127  |  | // Logs format... at "severity" level, reporting it  | 
128  |  | // as called from file:line.  | 
129  |  | // This does not allocate memory or acquire locks.  | 
130  |  | void RawLog(absl::LogSeverity severity, const char* file, int line,  | 
131  |  |             const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);  | 
132  |  |  | 
133  |  | // Writes the provided buffer directly to stderr, in a signal-safe, low-level  | 
134  |  | // manner.  Preserves errno.  | 
135  |  | void AsyncSignalSafeWriteError(const char* s, size_t len);  | 
136  |  |  | 
137  |  | // compile-time function to get the "base" filename, that is, the part of  | 
138  |  | // a filename after the last "/" or "\" path separator.  The search starts at  | 
139  |  | // the end of the string; the second parameter is the length of the string.  | 
140  | 0  | constexpr const char* Basename(const char* fname, int offset) { | 
141  | 0  |   return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\'  | 
142  | 0  |              ? fname + offset  | 
143  | 0  |              : Basename(fname, offset - 1);  | 
144  | 0  | }  | 
145  |  |  | 
146  |  | // For testing only.  | 
147  |  | // Returns true if raw logging is fully supported. When it is not  | 
148  |  | // fully supported, no messages will be emitted, but a log at FATAL  | 
149  |  | // severity will cause an abort.  | 
150  |  | //  | 
151  |  | // TODO(gfalcon): Come up with a better name for this method.  | 
152  |  | bool RawLoggingFullySupported();  | 
153  |  |  | 
154  |  | // Function type for a raw_log customization hook for suppressing messages  | 
155  |  | // by severity, and for writing custom prefixes on non-suppressed messages.  | 
156  |  | //  | 
157  |  | // The installed hook is called for every raw log invocation.  The message will  | 
158  |  | // be logged to stderr only if the hook returns true.  FATAL errors will cause  | 
159  |  | // the process to abort, even if writing to stderr is suppressed.  The hook is  | 
160  |  | // also provided with an output buffer, where it can write a custom log message  | 
161  |  | // prefix.  | 
162  |  | //  | 
163  |  | // The raw_log system does not allocate memory or grab locks.  User-provided  | 
164  |  | // hooks must avoid these operations, and must not throw exceptions.  | 
165  |  | //  | 
166  |  | // 'severity' is the severity level of the message being written.  | 
167  |  | // 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro  | 
168  |  | // was located.  | 
169  |  | // 'buf' and 'buf_size' are pointers to the buffer and buffer size.  If the  | 
170  |  | // hook writes a prefix, it must increment *buf and decrement *buf_size  | 
171  |  | // accordingly.  | 
172  |  | using LogFilterAndPrefixHook = bool (*)(absl::LogSeverity severity,  | 
173  |  |                                         const char* file, int line, char** buf,  | 
174  |  |                                         int* buf_size);  | 
175  |  |  | 
176  |  | // Function type for a raw_log customization hook called to abort a process  | 
177  |  | // when a FATAL message is logged.  If the provided AbortHook() returns, the  | 
178  |  | // logging system will call abort().  | 
179  |  | //  | 
180  |  | // 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro  | 
181  |  | // was located.  | 
182  |  | // The NUL-terminated logged message lives in the buffer between 'buf_start'  | 
183  |  | // and 'buf_end'.  'prefix_end' points to the first non-prefix character of the  | 
184  |  | // buffer (as written by the LogFilterAndPrefixHook.)  | 
185  |  | //  | 
186  |  | // The lifetime of the filename and message buffers will not end while the  | 
187  |  | // process remains alive.  | 
188  |  | using AbortHook = void (*)(const char* file, int line, const char* buf_start,  | 
189  |  |                            const char* prefix_end, const char* buf_end);  | 
190  |  |  | 
191  |  | // Internal logging function for ABSL_INTERNAL_LOG to dispatch to.  | 
192  |  | //  | 
193  |  | // TODO(gfalcon): When string_view no longer depends on base, change this  | 
194  |  | // interface to take its message as a string_view instead.  | 
195  |  | using InternalLogFunction = void (*)(absl::LogSeverity severity,  | 
196  |  |                                      const char* file, int line,  | 
197  |  |                                      const std::string& message);  | 
198  |  |  | 
199  |  | ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook<  | 
200  |  |     InternalLogFunction>  | 
201  |  |     internal_log_function;  | 
202  |  |  | 
203  |  | // Registers hooks of the above types.  Only a single hook of each type may be  | 
204  |  | // registered.  It is an error to call these functions multiple times with  | 
205  |  | // different input arguments.  | 
206  |  | //  | 
207  |  | // These functions are safe to call at any point during initialization; they do  | 
208  |  | // not block or malloc, and are async-signal safe.  | 
209  |  | void RegisterLogFilterAndPrefixHook(LogFilterAndPrefixHook func);  | 
210  |  | void RegisterAbortHook(AbortHook func);  | 
211  |  | void RegisterInternalLogFunction(InternalLogFunction func);  | 
212  |  |  | 
213  |  | }  // namespace raw_log_internal  | 
214  |  | ABSL_NAMESPACE_END  | 
215  |  | }  // namespace absl  | 
216  |  |  | 
217  |  | #endif  // ABSL_BASE_INTERNAL_RAW_LOGGING_H_  |