Coverage Report

Created: 2024-09-23 06:29

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