1 // Copyright 2022 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 // -----------------------------------------------------------------------------
16 // File: log/internal/log_message.h
17 // -----------------------------------------------------------------------------
18 //
19 // This file declares `class absl::log_internal::LogMessage`. This class more or
20 // less represents a particular log message. LOG/CHECK macros create a
21 // temporary instance of `LogMessage` and then stream values to it.  At the end
22 // of the LOG/CHECK statement, LogMessage instance goes out of scope and
23 // `~LogMessage` directs the message to the registered log sinks.
24 // Heap-allocation of `LogMessage` is unsupported.  Construction outside of a
25 // `LOG` macro is unsupported.
26 
27 #ifndef ABSL_LOG_INTERNAL_LOG_MESSAGE_H_
28 #define ABSL_LOG_INTERNAL_LOG_MESSAGE_H_
29 
30 #include <ios>
31 #include <memory>
32 #include <ostream>
33 #include <streambuf>
34 #include <string>
35 
36 #include "absl/base/attributes.h"
37 #include "absl/base/config.h"
38 #include "absl/base/internal/errno_saver.h"
39 #include "absl/base/log_severity.h"
40 #include "absl/log/internal/nullguard.h"
41 #include "absl/log/log_entry.h"
42 #include "absl/log/log_sink.h"
43 #include "absl/strings/internal/has_absl_stringify.h"
44 #include "absl/strings/string_view.h"
45 #include "absl/time/time.h"
46 
47 namespace absl {
48 ABSL_NAMESPACE_BEGIN
49 namespace log_internal {
50 constexpr int kLogMessageBufferSize = 15000;
51 
52 class LogMessage {
53  public:
54   // Used for `LOG`.
55   LogMessage(const char* file, int line,
56              absl::LogSeverity severity) ABSL_ATTRIBUTE_COLD;
57   LogMessage(const LogMessage&) = delete;
58   LogMessage& operator=(const LogMessage&) = delete;
59   ~LogMessage() ABSL_ATTRIBUTE_COLD;
60 
61   // Overrides the location inferred from the callsite.  The string pointed to
62   // by `file` must be valid until the end of the statement.
63   LogMessage& AtLocation(absl::string_view file, int line);
64   // Omits the prefix from this line.  The prefix includes metadata about the
65   // logged data such as source code location and timestamp.
66   LogMessage& NoPrefix();
67   // Sets the verbosity field of the logged message as if it was logged by
68   // `VLOG(verbose_level)`.  Unlike `VLOG`, this method does not affect
69   // evaluation of the statement when the specified `verbose_level` has been
70   // disabled.  The only effect is on `absl::LogSink` implementations which
71   // make use of the `absl::LogSink::verbosity()` value.  The value
72   // `absl::LogEntry::kNoVerbosityLevel` can be specified to mark the message
73   // not verbose.
74   LogMessage& WithVerbosity(int verbose_level);
75   // Uses the specified timestamp instead of one collected in the constructor.
76   LogMessage& WithTimestamp(absl::Time timestamp);
77   // Uses the specified thread ID instead of one collected in the constructor.
78   LogMessage& WithThreadID(absl::LogEntry::tid_t tid);
79   // Copies all metadata (but no data) from the specified `absl::LogEntry`.
80   LogMessage& WithMetadataFrom(const absl::LogEntry& entry);
81   // Appends to the logged message a colon, a space, a textual description of
82   // the current value of `errno` (as by strerror(3)), and the numerical value
83   // of `errno`.
84   LogMessage& WithPerror();
85   // Sends this message to `*sink` in addition to whatever other sinks it would
86   // otherwise have been sent to.  `sink` must not be null.
87   LogMessage& ToSinkAlso(absl::LogSink* sink);
88   // Sends this message to `*sink` and no others.  `sink` must not be null.
89   LogMessage& ToSinkOnly(absl::LogSink* sink);
90 
91   // Don't call this method from outside this library.
InternalStream()92   LogMessage& InternalStream() { return *this; }
93 
94   // By-value overloads for small, common types let us overlook common failures
95   // to define globals and static data members (i.e. in a .cc file).
96   // clang-format off
97   // The CUDA toolchain cannot handle these <<<'s:
98   LogMessage& operator<<(char v) { return operator<< <char>(v); }
99   LogMessage& operator<<(signed char v) { return operator<< <signed char>(v); }
100   LogMessage& operator<<(unsigned char v) {
101     return operator<< <unsigned char>(v);
102   }
103   LogMessage& operator<<(signed short v) {  // NOLINT
104     return operator<< <signed short>(v);  // NOLINT
105   }
106   LogMessage& operator<<(signed int v) { return operator<< <signed int>(v); }
107   LogMessage& operator<<(signed long v) {  // NOLINT
108     return operator<< <signed long>(v);  // NOLINT
109   }
110   LogMessage& operator<<(signed long long v) {  // NOLINT
111     return operator<< <signed long long>(v);  // NOLINT
112   }
113   LogMessage& operator<<(unsigned short v) {  // NOLINT
114     return operator<< <unsigned short>(v);  // NOLINT
115   }
116   LogMessage& operator<<(unsigned int v) {
117     return operator<< <unsigned int>(v);
118   }
119   LogMessage& operator<<(unsigned long v) {  // NOLINT
120     return operator<< <unsigned long>(v);  // NOLINT
121   }
122   LogMessage& operator<<(unsigned long long v) {  // NOLINT
123     return operator<< <unsigned long long>(v);  // NOLINT
124   }
125   LogMessage& operator<<(void* v) { return operator<< <void*>(v); }
126   LogMessage& operator<<(const void* v) { return operator<< <const void*>(v); }
127   LogMessage& operator<<(float v) { return operator<< <float>(v); }
128   LogMessage& operator<<(double v) { return operator<< <double>(v); }
129   LogMessage& operator<<(bool v) { return operator<< <bool>(v); }
130   // clang-format on
131 
132   // These overloads are more efficient since no `ostream` is involved.
133   LogMessage& operator<<(const std::string& v);
134   LogMessage& operator<<(absl::string_view v);
135 
136   // Handle stream manipulators e.g. std::endl.
137   LogMessage& operator<<(std::ostream& (*m)(std::ostream& os));
138   LogMessage& operator<<(std::ios_base& (*m)(std::ios_base& os));
139 
140   // Literal strings.  This allows us to record C string literals as literals in
141   // the logging.proto.Value.
142   //
143   // Allow this overload to be inlined to prevent generating instantiations of
144   // this template for every value of `SIZE` encountered in each source code
145   // file. That significantly increases linker input sizes. Inlining is cheap
146   // because the argument to this overload is almost always a string literal so
147   // the call to `strlen` can be replaced at compile time. The overload for
148   // `char[]` below should not be inlined. The compiler typically does not have
149   // the string at compile time and cannot replace the call to `strlen` so
150   // inlining it increases the binary size. See the discussion on
151   // cl/107527369.
152   template <int SIZE>
153   LogMessage& operator<<(const char (&buf)[SIZE]);
154 
155   // This prevents non-const `char[]` arrays from looking like literals.
156   template <int SIZE>
157   LogMessage& operator<<(char (&buf)[SIZE]) ABSL_ATTRIBUTE_NOINLINE;
158 
159   // Types that support `AbslStringify()` are serialized that way.
160   template <typename T,
161             typename std::enable_if<
162                 strings_internal::HasAbslStringify<T>::value, int>::type = 0>
163   LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE;
164 
165   // Types that don't support `AbslStringify()` but do support streaming into a
166   // `std::ostream&` are serialized that way.
167   template <typename T,
168             typename std::enable_if<
169                 !strings_internal::HasAbslStringify<T>::value, int>::type = 0>
170   LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE;
171 
172   // Note: We explicitly do not support `operator<<` for non-const references
173   // because it breaks logging of non-integer bitfield types (i.e., enums).
174 
175  protected:
176   // Call `abort()` or similar to perform `LOG(FATAL)` crash.  It is assumed
177   // that the caller has already generated and written the trace as appropriate.
178   ABSL_ATTRIBUTE_NORETURN static void FailWithoutStackTrace();
179 
180   // Similar to `FailWithoutStackTrace()`, but without `abort()`.  Terminates
181   // the process with an error exit code.
182   ABSL_ATTRIBUTE_NORETURN static void FailQuietly();
183 
184   // Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s.
185   // This might as well be inlined into `~LogMessage` except that
186   // `~LogMessageFatal` needs to call it early.
187   void Flush();
188 
189   // After this is called, failures are done as quiet as possible for this log
190   // message.
191   void SetFailQuietly();
192 
193  private:
194   struct LogMessageData;  // Opaque type containing message state
195   friend class AsLiteralImpl;
196   friend class StringifySink;
197 
198   // This streambuf writes directly into the structured logging buffer so that
199   // arbitrary types can be encoded as string data (using
200   // `operator<<(std::ostream &, ...)` without any extra allocation or copying.
201   // Space is reserved before the data to store the length field, which is
202   // filled in by `~OstreamView`.
203   class OstreamView final : public std::streambuf {
204    public:
205     explicit OstreamView(LogMessageData& message_data);
206     ~OstreamView() override;
207     OstreamView(const OstreamView&) = delete;
208     OstreamView& operator=(const OstreamView&) = delete;
209     std::ostream& stream();
210 
211    private:
212     LogMessageData& data_;
213     absl::Span<char> encoded_remaining_copy_;
214     absl::Span<char> message_start_;
215     absl::Span<char> string_start_;
216   };
217 
218   enum class StringType {
219     kLiteral,
220     kNotLiteral,
221   };
222   void CopyToEncodedBuffer(absl::string_view str,
223                            StringType str_type) ABSL_ATTRIBUTE_NOINLINE;
224   void CopyToEncodedBuffer(char ch, size_t num,
225                            StringType str_type) ABSL_ATTRIBUTE_NOINLINE;
226 
227   // Returns `true` if the message is fatal or enabled debug-fatal.
228   bool IsFatal() const;
229 
230   // Records some tombstone-type data in anticipation of `Die`.
231   void PrepareToDie();
232   void Die();
233 
234   void SendToLog();
235 
236   // Checks `FLAGS_log_backtrace_at` and appends a backtrace if appropriate.
237   void LogBacktraceIfNeeded();
238 
239   // This should be the first data member so that its initializer captures errno
240   // before any other initializers alter it (e.g. with calls to new) and so that
241   // no other destructors run afterward an alter it (e.g. with calls to delete).
242   absl::base_internal::ErrnoSaver errno_saver_;
243 
244   // We keep the data in a separate struct so that each instance of `LogMessage`
245   // uses less stack space.
246   std::unique_ptr<LogMessageData> data_;
247 };
248 
249 // Helper class so that `AbslStringify()` can modify the LogMessage.
250 class StringifySink final {
251  public:
StringifySink(LogMessage & message)252   explicit StringifySink(LogMessage& message) : message_(message) {}
253 
Append(size_t count,char ch)254   void Append(size_t count, char ch) {
255     message_.CopyToEncodedBuffer(ch, count,
256                                  LogMessage::StringType::kNotLiteral);
257   }
258 
Append(absl::string_view v)259   void Append(absl::string_view v) {
260     message_.CopyToEncodedBuffer(v, LogMessage::StringType::kNotLiteral);
261   }
262 
263   // For types that implement `AbslStringify` using `absl::Format()`.
AbslFormatFlush(StringifySink * sink,absl::string_view v)264   friend void AbslFormatFlush(StringifySink* sink, absl::string_view v) {
265     sink->Append(v);
266   }
267 
268  private:
269   LogMessage& message_;
270 };
271 
272 // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
273 template <typename T,
274           typename std::enable_if<strings_internal::HasAbslStringify<T>::value,
275                                   int>::type>
276 LogMessage& LogMessage::operator<<(const T& v) {
277   StringifySink sink(*this);
278   // Replace with public API.
279   AbslStringify(sink, v);
280   return *this;
281 }
282 
283 // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
284 template <typename T,
285           typename std::enable_if<!strings_internal::HasAbslStringify<T>::value,
286                                   int>::type>
287 LogMessage& LogMessage::operator<<(const T& v) {
288   OstreamView view(*data_);
289   view.stream() << log_internal::NullGuard<T>().Guard(v);
290   return *this;
291 }
292 
293 template <int SIZE>
294 LogMessage& LogMessage::operator<<(const char (&buf)[SIZE]) {
295   CopyToEncodedBuffer(buf, StringType::kLiteral);
296   return *this;
297 }
298 
299 // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
300 template <int SIZE>
301 LogMessage& LogMessage::operator<<(char (&buf)[SIZE]) {
302   CopyToEncodedBuffer(buf, StringType::kNotLiteral);
303   return *this;
304 }
305 // We instantiate these specializations in the library's TU to save space in
306 // other TUs.  Since the template is marked `ABSL_ATTRIBUTE_NOINLINE` we will be
307 // emitting a function call either way.
308 extern template LogMessage& LogMessage::operator<<(const char& v);
309 extern template LogMessage& LogMessage::operator<<(const signed char& v);
310 extern template LogMessage& LogMessage::operator<<(const unsigned char& v);
311 extern template LogMessage& LogMessage::operator<<(const short& v);  // NOLINT
312 extern template LogMessage& LogMessage::operator<<(
313     const unsigned short& v);  // NOLINT
314 extern template LogMessage& LogMessage::operator<<(const int& v);
315 extern template LogMessage& LogMessage::operator<<(
316     const unsigned int& v);                                         // NOLINT
317 extern template LogMessage& LogMessage::operator<<(const long& v);  // NOLINT
318 extern template LogMessage& LogMessage::operator<<(
319     const unsigned long& v);  // NOLINT
320 extern template LogMessage& LogMessage::operator<<(
321     const long long& v);  // NOLINT
322 extern template LogMessage& LogMessage::operator<<(
323     const unsigned long long& v);  // NOLINT
324 extern template LogMessage& LogMessage::operator<<(void* const& v);
325 extern template LogMessage& LogMessage::operator<<(const void* const& v);
326 extern template LogMessage& LogMessage::operator<<(const float& v);
327 extern template LogMessage& LogMessage::operator<<(const double& v);
328 extern template LogMessage& LogMessage::operator<<(const bool& v);
329 
330 // `LogMessageFatal` ensures the process will exit in failure after logging this
331 // message.
332 class LogMessageFatal final : public LogMessage {
333  public:
334   LogMessageFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD;
335   LogMessageFatal(const char* file, int line,
336                   absl::string_view failure_msg) ABSL_ATTRIBUTE_COLD;
337   ABSL_ATTRIBUTE_NORETURN ~LogMessageFatal();
338 };
339 
340 class LogMessageQuietlyFatal final : public LogMessage {
341  public:
342   LogMessageQuietlyFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD;
343   LogMessageQuietlyFatal(const char* file, int line,
344                          absl::string_view failure_msg) ABSL_ATTRIBUTE_COLD;
345   ABSL_ATTRIBUTE_NORETURN ~LogMessageQuietlyFatal();
346 };
347 
348 }  // namespace log_internal
349 ABSL_NAMESPACE_END
350 }  // namespace absl
351 
352 extern "C" ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(
353     AbslInternalOnFatalLogMessage)(const absl::LogEntry&);
354 
355 #endif  // ABSL_LOG_INTERNAL_LOG_MESSAGE_H_
356