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