Coverage Report

Created: 2026-04-01 06:29

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
  // Handle stream manipulators e.g. std::endl.
183
  LogMessage& operator<<(std::ostream& (*absl_nonnull m)(std::ostream& os));
184
  LogMessage& operator<<(std::ios_base& (*absl_nonnull m)(std::ios_base& os));
185
186
  // Literal strings.  This allows us to record C string literals as literals in
187
  // the logging.proto.Value.
188
  //
189
  // Allow this overload to be inlined to prevent generating instantiations of
190
  // this template for every value of `SIZE` encountered in each source code
191
  // file. That significantly increases linker input sizes. Inlining is cheap
192
  // because the argument to this overload is almost always a string literal so
193
  // the call to `strlen` can be replaced at compile time. The overloads for
194
  // `char[]`/`wchar_t[]` below should not be inlined. The compiler typically
195
  // does not have the string at compile time and cannot replace the call to
196
  // `strlen` so inlining it increases the binary size. See the discussion on
197
  // cl/107527369.
198
  template <int SIZE>
199
  LogMessage& operator<<(const char (&buf)[SIZE]);
200
  template <int SIZE>
201
  LogMessage& operator<<(const wchar_t (&buf)[SIZE]);
202
203
  // This prevents non-const `char[]` arrays from looking like literals.
204
  template <int SIZE>
205
  LogMessage& operator<<(char (&buf)[SIZE]) ABSL_ATTRIBUTE_NOINLINE;
206
  // `wchar_t[SIZE]` is handled by `operator<< <const wchar_t*>`.
207
208
  // Types that support `AbslStringify()` are serialized that way.
209
  // Types that don't support `AbslStringify()` but do support streaming into a
210
  // `std::ostream&` are serialized that way.
211
  template <typename T>
212
  LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE;
213
214
  // Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s.
215
  void Flush();
216
217
  // Note: We explicitly do not support `operator<<` for non-const references
218
  // because it breaks logging of non-integer bitfield types (i.e., enums).
219
220
 protected:
221
  // Call `abort()` or similar to perform `LOG(FATAL)` crash.  It is assumed
222
  // that the caller has already generated and written the trace as appropriate.
223
  [[noreturn]] static void FailWithoutStackTrace();
224
225
  // Similar to `FailWithoutStackTrace()`, but without `abort()`.  Terminates
226
  // the process with an error exit code.
227
  [[noreturn]] static void FailQuietly();
228
229
  // After this is called, failures are done as quiet as possible for this log
230
  // message.
231
  void SetFailQuietly();
232
233
 private:
234
  struct LogMessageData;  // Opaque type containing message state
235
  friend class AsLiteralImpl;
236
  friend class StringifySink;
237
  template <StructuredStringType str_type>
238
  friend class AsStructuredStringTypeImpl;
239
  template <typename T>
240
  friend class AsStructuredValueImpl;
241
242
  // This streambuf writes directly into the structured logging buffer so that
243
  // arbitrary types can be encoded as string data (using
244
  // `operator<<(std::ostream &, ...)` without any extra allocation or copying.
245
  // Space is reserved before the data to store the length field, which is
246
  // filled in by `~OstreamView`.
247
  class OstreamView final : public std::streambuf {
248
   public:
249
    explicit OstreamView(LogMessageData& message_data);
250
    ~OstreamView() override;
251
    OstreamView(const OstreamView&) = delete;
252
    OstreamView& operator=(const OstreamView&) = delete;
253
    std::ostream& stream();
254
255
   private:
256
    LogMessageData& data_;
257
    absl::Span<char> encoded_remaining_copy_;
258
    absl::Span<char> message_start_;
259
    absl::Span<char> string_start_;
260
  };
261
262
  enum class StringType {
263
    kLiteral,
264
    kNotLiteral,
265
  };
266
  template <StringType str_type>
267
  void CopyToEncodedBuffer(absl::string_view str) ABSL_ATTRIBUTE_NOINLINE;
268
  template <StringType str_type>
269
  void CopyToEncodedBuffer(char ch, size_t num) ABSL_ATTRIBUTE_NOINLINE;
270
  template <StringType str_type>
271
  void CopyToEncodedBuffer(std::wstring_view str) ABSL_ATTRIBUTE_NOINLINE;
272
273
  // Copies `field` to the encoded buffer, then appends `str` after it
274
  // (truncating `str` if necessary to fit).
275
  template <StringType str_type>
276
  void CopyToEncodedBufferWithStructuredProtoField(StructuredProtoField field,
277
                                                   absl::string_view str)
278
      ABSL_ATTRIBUTE_NOINLINE;
279
280
  // Returns `true` if the message is fatal or enabled debug-fatal.
281
  bool IsFatal() const;
282
283
  // Records some tombstone-type data in anticipation of `Die`.
284
  void PrepareToDie();
285
  void Die();
286
287
  void SendToLog();
288
289
  // Checks `FLAGS_log_backtrace_at` and appends a backtrace if appropriate.
290
  void LogBacktraceIfNeeded();
291
292
  // This should be the first data member so that its initializer captures errno
293
  // before any other initializers alter it (e.g. with calls to new) and so that
294
  // no other destructors run afterward an alter it (e.g. with calls to delete).
295
  absl::base_internal::ErrnoSaver errno_saver_;
296
297
  // We keep the data in a separate struct so that each instance of `LogMessage`
298
  // uses less stack space.
299
  absl_nonnull std::unique_ptr<LogMessageData> data_;
300
};
301
302
// Explicitly specializes the generic operator<< for `const wchar_t*`
303
// arguments.
304
//
305
// This method is used instead of a non-template `const wchar_t*` overload,
306
// as the latter was found to take precedence over the array template
307
// (`operator<<(const wchar_t(&)[SIZE])`) when handling string literals.
308
// This specialization ensures the array template now correctly processes
309
// literals.
310
template <>
311
LogMessage& LogMessage::operator<< <const wchar_t*>(
312
    const wchar_t* absl_nullable const& v);
313
314
0
inline LogMessage& LogMessage::operator<<(wchar_t* absl_nullable v) {
315
0
  return operator<<(const_cast<const wchar_t*>(v));
316
0
}
317
318
// Helper class so that `AbslStringify()` can modify the LogMessage.
319
class StringifySink final {
320
 public:
321
0
  explicit StringifySink(LogMessage& message) : message_(message) {}
322
323
0
  void Append(size_t count, char ch) {
324
0
    message_.CopyToEncodedBuffer<LogMessage::StringType::kNotLiteral>(ch,
325
0
                                                                      count);
326
0
  }
327
328
0
  void Append(absl::string_view v) {
329
0
    message_.CopyToEncodedBuffer<LogMessage::StringType::kNotLiteral>(v);
330
0
  }
331
332
  // For types that implement `AbslStringify` using `absl::Format()`.
333
  friend void AbslFormatFlush(StringifySink* absl_nonnull sink,
334
0
                              absl::string_view v) {
335
0
    sink->Append(v);
336
0
  }
337
338
 private:
339
  LogMessage& message_;
340
};
341
342
// Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
343
template <typename T>
344
0
LogMessage& LogMessage::operator<<(const T& v) {
345
  if constexpr (absl::HasAbslStringify<T>::value) {
346
    StringifySink sink(*this);
347
    // Replace with public API.
348
    AbslStringify(sink, v);
349
0
  } else {
350
0
    OstreamView view(*data_);
351
0
    view.stream() << log_internal::NullGuard<T>().Guard(v);
352
0
  }
353
0
  return *this;
354
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&)
355
356
template <int SIZE>
357
0
LogMessage& LogMessage::operator<<(const char (&buf)[SIZE]) {
358
0
  CopyToEncodedBuffer<StringType::kLiteral>(buf);
359
0
  return *this;
360
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])
361
362
template <int SIZE>
363
LogMessage& LogMessage::operator<<(const wchar_t (&buf)[SIZE]) {
364
  CopyToEncodedBuffer<StringType::kLiteral>(buf);
365
  return *this;
366
}
367
368
// Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
369
template <int SIZE>
370
LogMessage& LogMessage::operator<<(char (&buf)[SIZE]) {
371
  CopyToEncodedBuffer<StringType::kNotLiteral>(buf);
372
  return *this;
373
}
374
// We instantiate these specializations in the library's TU to save space in
375
// other TUs.  Since the template is marked `ABSL_ATTRIBUTE_NOINLINE` we will be
376
// emitting a function call either way.
377
// NOLINTBEGIN(runtime/int)
378
// NOLINTBEGIN(google-runtime-int)
379
extern template LogMessage& LogMessage::operator<<(const char& v);
380
extern template LogMessage& LogMessage::operator<<(const signed char& v);
381
extern template LogMessage& LogMessage::operator<<(const unsigned char& v);
382
extern template LogMessage& LogMessage::operator<<(const short& v);
383
extern template LogMessage& LogMessage::operator<<(const unsigned short& v);
384
extern template LogMessage& LogMessage::operator<<(const int& v);
385
extern template LogMessage& LogMessage::operator<<(const unsigned int& v);
386
extern template LogMessage& LogMessage::operator<<(const long& v);
387
extern template LogMessage& LogMessage::operator<<(const unsigned long& v);
388
extern template LogMessage& LogMessage::operator<<(const long long& v);
389
extern template LogMessage& LogMessage::operator<<(const unsigned long long& v);
390
extern template LogMessage& LogMessage::operator<<(
391
    void* absl_nullable const& v);
392
extern template LogMessage& LogMessage::operator<<(
393
    const void* absl_nullable const& v);
394
extern template LogMessage& LogMessage::operator<<(const float& v);
395
extern template LogMessage& LogMessage::operator<<(const double& v);
396
extern template LogMessage& LogMessage::operator<<(const bool& v);
397
// NOLINTEND(google-runtime-int)
398
// NOLINTEND(runtime/int)
399
400
extern template void LogMessage::CopyToEncodedBuffer<
401
    LogMessage::StringType::kLiteral>(absl::string_view str);
402
extern template void LogMessage::CopyToEncodedBuffer<
403
    LogMessage::StringType::kNotLiteral>(absl::string_view str);
404
extern template void
405
LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>(char ch,
406
                                                                  size_t num);
407
extern template void LogMessage::CopyToEncodedBuffer<
408
    LogMessage::StringType::kNotLiteral>(char ch, size_t num);
409
extern template void LogMessage::CopyToEncodedBuffer<
410
    LogMessage::StringType::kLiteral>(std::wstring_view str);
411
extern template void LogMessage::CopyToEncodedBuffer<
412
    LogMessage::StringType::kNotLiteral>(std::wstring_view str);
413
414
// `LogMessageFatal` ensures the process will exit in failure after logging this
415
// message.
416
class LogMessageFatal final : public LogMessage {
417
 public:
418
  LogMessageFatal(const char* absl_nonnull file, int line) ABSL_ATTRIBUTE_COLD;
419
  LogMessageFatal(const char* absl_nonnull file, int line,
420
                  const char* absl_nonnull failure_msg) ABSL_ATTRIBUTE_COLD;
421
  [[noreturn]] ~LogMessageFatal();
422
};
423
424
// `LogMessageDebugFatal` ensures the process will exit in failure after logging
425
// this message. It matches LogMessageFatal but is not [[noreturn]] as it's used
426
// for DLOG(FATAL) variants.
427
class LogMessageDebugFatal final : public LogMessage {
428
 public:
429
  LogMessageDebugFatal(const char* absl_nonnull file,
430
                       int line) ABSL_ATTRIBUTE_COLD;
431
  ~LogMessageDebugFatal();
432
};
433
434
class LogMessageQuietlyDebugFatal final : public LogMessage {
435
 public:
436
  // DLOG(QFATAL) calls this instead of LogMessageQuietlyFatal to make sure the
437
  // destructor is not [[noreturn]] even if this is always FATAL as this is only
438
  // invoked when DLOG() is enabled.
439
  LogMessageQuietlyDebugFatal(const char* absl_nonnull file,
440
                              int line) ABSL_ATTRIBUTE_COLD;
441
  ~LogMessageQuietlyDebugFatal();
442
};
443
444
// Used for LOG(QFATAL) to make sure it's properly understood as [[noreturn]].
445
class LogMessageQuietlyFatal final : public LogMessage {
446
 public:
447
  LogMessageQuietlyFatal(const char* absl_nonnull file,
448
                         int line) ABSL_ATTRIBUTE_COLD;
449
  LogMessageQuietlyFatal(const char* absl_nonnull file, int line,
450
                         const char* absl_nonnull failure_msg)
451
      ABSL_ATTRIBUTE_COLD;
452
  [[noreturn]] ~LogMessageQuietlyFatal();
453
};
454
455
}  // namespace log_internal
456
ABSL_NAMESPACE_END
457
}  // namespace absl
458
459
extern "C" ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(
460
    AbslInternalOnFatalLogMessage)(const absl::LogEntry&);
461
462
#endif  // ABSL_LOG_INTERNAL_LOG_MESSAGE_H_