Coverage Report

Created: 2026-05-30 06:40

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