• 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 temporary
21 // instance of `LogMessage` and then stream values to it.  At the end of the
22 // LOG/CHECK statement, the LogMessage is voidified by operator&&, and `Flush()`
23 // directs the message to the registered log sinks.  Heap-allocation of
24 // `LogMessage` is unsupported.  Construction outside of a `LOG` macro is
25 // 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   // Types that don't support `AbslStringify()` but do support streaming into a
187   // `std::ostream&` are serialized that way.
188   template <typename T>
189   LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE;
190 
191   // Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s.
192   void Flush();
193 
194   // Note: We explicitly do not support `operator<<` for non-const references
195   // because it breaks logging of non-integer bitfield types (i.e., enums).
196 
197  protected:
198   // Call `abort()` or similar to perform `LOG(FATAL)` crash.  It is assumed
199   // that the caller has already generated and written the trace as appropriate.
200   [[noreturn]] static void FailWithoutStackTrace();
201 
202   // Similar to `FailWithoutStackTrace()`, but without `abort()`.  Terminates
203   // the process with an error exit code.
204   [[noreturn]] static void FailQuietly();
205 
206   // After this is called, failures are done as quiet as possible for this log
207   // message.
208   void SetFailQuietly();
209 
210  private:
211   struct LogMessageData;  // Opaque type containing message state
212   friend class AsLiteralImpl;
213   friend class StringifySink;
214   template <StructuredStringType str_type>
215   friend class AsStructuredStringTypeImpl;
216   template <typename T>
217   friend class AsStructuredValueImpl;
218 
219   // This streambuf writes directly into the structured logging buffer so that
220   // arbitrary types can be encoded as string data (using
221   // `operator<<(std::ostream &, ...)` without any extra allocation or copying.
222   // Space is reserved before the data to store the length field, which is
223   // filled in by `~OstreamView`.
224   class OstreamView final : public std::streambuf {
225    public:
226     explicit OstreamView(LogMessageData& message_data);
227     ~OstreamView() override;
228     OstreamView(const OstreamView&) = delete;
229     OstreamView& operator=(const OstreamView&) = delete;
230     std::ostream& stream();
231 
232    private:
233     LogMessageData& data_;
234     absl::Span<char> encoded_remaining_copy_;
235     absl::Span<char> message_start_;
236     absl::Span<char> string_start_;
237   };
238 
239   enum class StringType {
240     kLiteral,
241     kNotLiteral,
242   };
243   template <StringType str_type>
244   void CopyToEncodedBuffer(absl::string_view str) ABSL_ATTRIBUTE_NOINLINE;
245   template <StringType str_type>
246   void CopyToEncodedBuffer(char ch, size_t num) ABSL_ATTRIBUTE_NOINLINE;
247 
248   // Copies `field` to the encoded buffer, then appends `str` after it
249   // (truncating `str` if necessary to fit).
250   template <StringType str_type>
251   void CopyToEncodedBufferWithStructuredProtoField(StructuredProtoField field,
252                                                    absl::string_view str)
253       ABSL_ATTRIBUTE_NOINLINE;
254 
255   // Returns `true` if the message is fatal or enabled debug-fatal.
256   bool IsFatal() const;
257 
258   // Records some tombstone-type data in anticipation of `Die`.
259   void PrepareToDie();
260   void Die();
261 
262   void SendToLog();
263 
264   // Checks `FLAGS_log_backtrace_at` and appends a backtrace if appropriate.
265   void LogBacktraceIfNeeded();
266 
267   // This should be the first data member so that its initializer captures errno
268   // before any other initializers alter it (e.g. with calls to new) and so that
269   // no other destructors run afterward an alter it (e.g. with calls to delete).
270   absl::base_internal::ErrnoSaver errno_saver_;
271 
272   // We keep the data in a separate struct so that each instance of `LogMessage`
273   // uses less stack space.
274   absl::Nonnull<std::unique_ptr<LogMessageData>> data_;
275 };
276 
277 // Helper class so that `AbslStringify()` can modify the LogMessage.
278 class StringifySink final {
279  public:
StringifySink(LogMessage & message)280   explicit StringifySink(LogMessage& message) : message_(message) {}
281 
Append(size_t count,char ch)282   void Append(size_t count, char ch) {
283     message_.CopyToEncodedBuffer<LogMessage::StringType::kNotLiteral>(ch,
284                                                                       count);
285   }
286 
Append(absl::string_view v)287   void Append(absl::string_view v) {
288     message_.CopyToEncodedBuffer<LogMessage::StringType::kNotLiteral>(v);
289   }
290 
291   // For types that implement `AbslStringify` using `absl::Format()`.
AbslFormatFlush(absl::Nonnull<StringifySink * > sink,absl::string_view v)292   friend void AbslFormatFlush(absl::Nonnull<StringifySink*> sink,
293                               absl::string_view v) {
294     sink->Append(v);
295   }
296 
297  private:
298   LogMessage& message_;
299 };
300 
301 // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
302 template <typename T>
303 LogMessage& LogMessage::operator<<(const T& v) {
304   if constexpr (absl::HasAbslStringify<T>::value) {
305     StringifySink sink(*this);
306     // Replace with public API.
307     AbslStringify(sink, v);
308   } else {
309     OstreamView view(*data_);
310     view.stream() << log_internal::NullGuard<T>().Guard(v);
311   }
312   return *this;
313 }
314 
315 template <int SIZE>
316 LogMessage& LogMessage::operator<<(const char (&buf)[SIZE]) {
317   CopyToEncodedBuffer<StringType::kLiteral>(buf);
318   return *this;
319 }
320 
321 // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
322 template <int SIZE>
323 LogMessage& LogMessage::operator<<(char (&buf)[SIZE]) {
324   CopyToEncodedBuffer<StringType::kNotLiteral>(buf);
325   return *this;
326 }
327 // We instantiate these specializations in the library's TU to save space in
328 // other TUs.  Since the template is marked `ABSL_ATTRIBUTE_NOINLINE` we will be
329 // emitting a function call either way.
330 // NOLINTBEGIN(runtime/int)
331 // NOLINTBEGIN(google-runtime-int)
332 extern template LogMessage& LogMessage::operator<<(const char& v);
333 extern template LogMessage& LogMessage::operator<<(const signed char& v);
334 extern template LogMessage& LogMessage::operator<<(const unsigned char& v);
335 extern template LogMessage& LogMessage::operator<<(const short& v);
336 extern template LogMessage& LogMessage::operator<<(const unsigned short& v);
337 extern template LogMessage& LogMessage::operator<<(const int& v);
338 extern template LogMessage& LogMessage::operator<<(const unsigned int& v);
339 extern template LogMessage& LogMessage::operator<<(const long& v);
340 extern template LogMessage& LogMessage::operator<<(const unsigned long& v);
341 extern template LogMessage& LogMessage::operator<<(const long long& v);
342 extern template LogMessage& LogMessage::operator<<(const unsigned long long& v);
343 extern template LogMessage& LogMessage::operator<<(
344     absl::Nullable<void*> const& v);
345 extern template LogMessage& LogMessage::operator<<(
346     absl::Nullable<const void*> const& v);
347 extern template LogMessage& LogMessage::operator<<(const float& v);
348 extern template LogMessage& LogMessage::operator<<(const double& v);
349 extern template LogMessage& LogMessage::operator<<(const bool& v);
350 // NOLINTEND(google-runtime-int)
351 // NOLINTEND(runtime/int)
352 
353 extern template void LogMessage::CopyToEncodedBuffer<
354     LogMessage::StringType::kLiteral>(absl::string_view str);
355 extern template void LogMessage::CopyToEncodedBuffer<
356     LogMessage::StringType::kNotLiteral>(absl::string_view str);
357 extern template void
358 LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>(char ch,
359                                                                   size_t num);
360 extern template void LogMessage::CopyToEncodedBuffer<
361     LogMessage::StringType::kNotLiteral>(char ch, size_t num);
362 
363 // `LogMessageFatal` ensures the process will exit in failure after logging this
364 // message.
365 class LogMessageFatal final : public LogMessage {
366  public:
367   LogMessageFatal(absl::Nonnull<const char*> file,
368                   int line) ABSL_ATTRIBUTE_COLD;
369   LogMessageFatal(absl::Nonnull<const char*> file, int line,
370                   absl::Nonnull<const char*> failure_msg) ABSL_ATTRIBUTE_COLD;
371   [[noreturn]] ~LogMessageFatal();
372 };
373 
374 // `LogMessageDebugFatal` ensures the process will exit in failure after logging
375 // this message. It matches LogMessageFatal but is not [[noreturn]] as it's used
376 // for DLOG(FATAL) variants.
377 class LogMessageDebugFatal final : public LogMessage {
378  public:
379   LogMessageDebugFatal(absl::Nonnull<const char*> file,
380                        int line) ABSL_ATTRIBUTE_COLD;
381   ~LogMessageDebugFatal();
382 };
383 
384 class LogMessageQuietlyDebugFatal final : public LogMessage {
385  public:
386   // DLOG(QFATAL) calls this instead of LogMessageQuietlyFatal to make sure the
387   // destructor is not [[noreturn]] even if this is always FATAL as this is only
388   // invoked when DLOG() is enabled.
389   LogMessageQuietlyDebugFatal(absl::Nonnull<const char*> file,
390                               int line) ABSL_ATTRIBUTE_COLD;
391   ~LogMessageQuietlyDebugFatal();
392 };
393 
394 // Used for LOG(QFATAL) to make sure it's properly understood as [[noreturn]].
395 class LogMessageQuietlyFatal final : public LogMessage {
396  public:
397   LogMessageQuietlyFatal(absl::Nonnull<const char*> file,
398                          int line) ABSL_ATTRIBUTE_COLD;
399   LogMessageQuietlyFatal(absl::Nonnull<const char*> file, int line,
400                          absl::Nonnull<const char*> failure_msg)
401       ABSL_ATTRIBUTE_COLD;
402   [[noreturn]] ~LogMessageQuietlyFatal();
403 };
404 
405 }  // namespace log_internal
406 ABSL_NAMESPACE_END
407 }  // namespace absl
408 
409 extern "C" ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(
410     AbslInternalOnFatalLogMessage)(const absl::LogEntry&);
411 
412 #endif  // ABSL_LOG_INTERNAL_LOG_MESSAGE_H_
413