1 //
2 // Copyright 2022 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include "absl/log/internal/log_message.h"
17
18 #include <stddef.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #ifndef _WIN32
24 #include <unistd.h>
25 #endif
26
27 #include <algorithm>
28 #include <array>
29 #include <atomic>
30 #include <memory>
31 #include <ostream>
32 #include <string>
33 #include <tuple>
34
35 #include "absl/base/attributes.h"
36 #include "absl/base/config.h"
37 #include "absl/base/internal/raw_logging.h"
38 #include "absl/base/internal/strerror.h"
39 #include "absl/base/internal/sysinfo.h"
40 #include "absl/base/log_severity.h"
41 #include "absl/container/inlined_vector.h"
42 #include "absl/debugging/internal/examine_stack.h"
43 #include "absl/log/globals.h"
44 #include "absl/log/internal/append_truncated.h"
45 #include "absl/log/internal/globals.h"
46 #include "absl/log/internal/log_format.h"
47 #include "absl/log/internal/log_sink_set.h"
48 #include "absl/log/internal/proto.h"
49 #include "absl/log/log_entry.h"
50 #include "absl/log/log_sink.h"
51 #include "absl/log/log_sink_registry.h"
52 #include "absl/memory/memory.h"
53 #include "absl/strings/string_view.h"
54 #include "absl/time/clock.h"
55 #include "absl/time/time.h"
56 #include "absl/types/span.h"
57
ABSL_INTERNAL_C_SYMBOL(AbslInternalOnFatalLogMessage)58 extern "C" ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(
59 AbslInternalOnFatalLogMessage)(const absl::LogEntry&) {
60 // Default - Do nothing
61 }
62
63 namespace absl {
64 ABSL_NAMESPACE_BEGIN
65 namespace log_internal {
66
67 namespace {
68 // message `logging.proto.Event`
69 enum EventTag : uint8_t {
70 kValue = 7,
71 };
72
73 // message `logging.proto.Value`
74 enum ValueTag : uint8_t {
75 kString = 1,
76 kStringLiteral = 6,
77 };
78
79 // Decodes a `logging.proto.Value` from `buf` and writes a string representation
80 // into `dst`. The string representation will be truncated if `dst` is not
81 // large enough to hold it. Returns false if `dst` has size zero or one (i.e.
82 // sufficient only for a nul-terminator) and no decoded data could be written.
83 // This function may or may not write a nul-terminator into `dst`, and it may or
84 // may not truncate the data it writes in order to do make space for that nul
85 // terminator. In any case, `dst` will be advanced to point at the byte where
86 // subsequent writes should begin.
PrintValue(absl::Span<char> & dst,absl::Span<const char> buf)87 bool PrintValue(absl::Span<char>& dst, absl::Span<const char> buf) {
88 if (dst.size() <= 1) return false;
89 ProtoField field;
90 while (field.DecodeFrom(&buf)) {
91 switch (field.tag()) {
92 case ValueTag::kString:
93 case ValueTag::kStringLiteral:
94 if (field.type() == WireType::kLengthDelimited)
95 if (log_internal::AppendTruncated(field.string_value(), dst) <
96 field.string_value().size())
97 return false;
98 }
99 }
100 return true;
101 }
102
Basename(absl::string_view filepath)103 absl::string_view Basename(absl::string_view filepath) {
104 #ifdef _WIN32
105 size_t path = filepath.find_last_of("/\\");
106 #else
107 size_t path = filepath.find_last_of('/');
108 #endif
109 if (path != filepath.npos) filepath.remove_prefix(path + 1);
110 return filepath;
111 }
112
WriteToString(const char * data,void * str)113 void WriteToString(const char* data, void* str) {
114 reinterpret_cast<std::string*>(str)->append(data);
115 }
WriteToStream(const char * data,void * os)116 void WriteToStream(const char* data, void* os) {
117 auto* cast_os = static_cast<std::ostream*>(os);
118 *cast_os << data;
119 }
120 } // namespace
121
122 struct LogMessage::LogMessageData final {
123 LogMessageData(const char* file, int line, absl::LogSeverity severity,
124 absl::Time timestamp);
125 LogMessageData(const LogMessageData&) = delete;
126 LogMessageData& operator=(const LogMessageData&) = delete;
127
128 // `LogEntry` sent to `LogSink`s; contains metadata.
129 absl::LogEntry entry;
130
131 // true => this was first fatal msg
132 bool first_fatal;
133 // true => all failures should be quiet
134 bool fail_quietly;
135 // true => PLOG was requested
136 bool is_perror;
137
138 // Extra `LogSink`s to log to, in addition to `global_sinks`.
139 absl::InlinedVector<absl::LogSink*, 16> extra_sinks;
140 // If true, log to `extra_sinks` but not to `global_sinks` or hardcoded
141 // non-sink targets (e.g. stderr, log files).
142 bool extra_sinks_only;
143
144 std::ostream manipulated; // ostream with IO manipulators applied
145
146 // A `logging.proto.Event` proto message is built into `encoded_buf`.
147 std::array<char, kLogMessageBufferSize> encoded_buf;
148 // `encoded_remaining` is the suffix of `encoded_buf` that has not been filled
149 // yet. If a datum to be encoded does not fit into `encoded_remaining` and
150 // cannot be truncated to fit, the size of `encoded_remaining` will be zeroed
151 // to prevent encoding of any further data. Note that in this case its data()
152 // pointer will not point past the end of `encoded_buf`.
153 absl::Span<char> encoded_remaining;
154
155 // A formatted string message is built in `string_buf`.
156 std::array<char, kLogMessageBufferSize> string_buf;
157
158 void FinalizeEncodingAndFormat();
159 };
160
LogMessageData(const char * file,int line,absl::LogSeverity severity,absl::Time timestamp)161 LogMessage::LogMessageData::LogMessageData(const char* file, int line,
162 absl::LogSeverity severity,
163 absl::Time timestamp)
164 : extra_sinks_only(false),
165 manipulated(nullptr),
166 // This `absl::MakeSpan` silences spurious -Wuninitialized from GCC:
167 encoded_remaining(absl::MakeSpan(encoded_buf)) {
168 // Legacy defaults for LOG's ostream:
169 manipulated.setf(std::ios_base::showbase | std::ios_base::boolalpha);
170 entry.full_filename_ = file;
171 entry.base_filename_ = Basename(file);
172 entry.line_ = line;
173 entry.prefix_ = absl::ShouldPrependLogPrefix();
174 entry.severity_ = absl::NormalizeLogSeverity(severity);
175 entry.verbose_level_ = absl::LogEntry::kNoVerbosityLevel;
176 entry.timestamp_ = timestamp;
177 entry.tid_ = absl::base_internal::GetCachedTID();
178 }
179
FinalizeEncodingAndFormat()180 void LogMessage::LogMessageData::FinalizeEncodingAndFormat() {
181 // Note that `encoded_remaining` may have zero size without pointing past the
182 // end of `encoded_buf`, so the difference between `data()` pointers is used
183 // to compute the size of `encoded_data`.
184 absl::Span<const char> encoded_data(
185 encoded_buf.data(),
186 static_cast<size_t>(encoded_remaining.data() - encoded_buf.data()));
187 // `string_remaining` is the suffix of `string_buf` that has not been filled
188 // yet.
189 absl::Span<char> string_remaining(string_buf);
190 // We may need to write a newline and nul-terminator at the end of the decoded
191 // string data. Rather than worry about whether those should overwrite the
192 // end of the string (if the buffer is full) or be appended, we avoid writing
193 // into the last two bytes so we always have space to append.
194 string_remaining.remove_suffix(2);
195 entry.prefix_len_ =
196 entry.prefix() ? log_internal::FormatLogPrefix(
197 entry.log_severity(), entry.timestamp(), entry.tid(),
198 entry.source_basename(), entry.source_line(),
199 log_internal::ThreadIsLoggingToLogSink()
200 ? PrefixFormat::kRaw
201 : PrefixFormat::kNotRaw,
202 string_remaining)
203 : 0;
204 // Decode data from `encoded_buf` until we run out of data or we run out of
205 // `string_remaining`.
206 ProtoField field;
207 while (field.DecodeFrom(&encoded_data)) {
208 switch (field.tag()) {
209 case EventTag::kValue:
210 if (field.type() != WireType::kLengthDelimited) continue;
211 if (PrintValue(string_remaining, field.bytes_value())) continue;
212 break;
213 }
214 break;
215 }
216 auto chars_written =
217 static_cast<size_t>(string_remaining.data() - string_buf.data());
218 string_buf[chars_written++] = '\n';
219 string_buf[chars_written++] = '\0';
220 entry.text_message_with_prefix_and_newline_and_nul_ =
221 absl::MakeSpan(string_buf).subspan(0, chars_written);
222 }
223
LogMessage(const char * file,int line,absl::LogSeverity severity)224 LogMessage::LogMessage(const char* file, int line, absl::LogSeverity severity)
225 : data_(absl::make_unique<LogMessageData>(file, line, severity,
226 absl::Now())) {
227 data_->first_fatal = false;
228 data_->is_perror = false;
229 data_->fail_quietly = false;
230
231 // This logs a backtrace even if the location is subsequently changed using
232 // AtLocation. This quirk, and the behavior when AtLocation is called twice,
233 // are fixable but probably not worth fixing.
234 LogBacktraceIfNeeded();
235 }
236
LogMessage(const char * file,int line,InfoTag)237 LogMessage::LogMessage(const char* file, int line, InfoTag)
238 : LogMessage(file, line, absl::LogSeverity::kInfo) {}
LogMessage(const char * file,int line,WarningTag)239 LogMessage::LogMessage(const char* file, int line, WarningTag)
240 : LogMessage(file, line, absl::LogSeverity::kWarning) {}
LogMessage(const char * file,int line,ErrorTag)241 LogMessage::LogMessage(const char* file, int line, ErrorTag)
242 : LogMessage(file, line, absl::LogSeverity::kError) {}
243
~LogMessage()244 LogMessage::~LogMessage() {
245 #ifdef ABSL_MIN_LOG_LEVEL
246 if (data_->entry.log_severity() <
247 static_cast<absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) &&
248 data_->entry.log_severity() < absl::LogSeverity::kFatal) {
249 return;
250 }
251 #endif
252 Flush();
253 }
254
AtLocation(absl::string_view file,int line)255 LogMessage& LogMessage::AtLocation(absl::string_view file, int line) {
256 data_->entry.full_filename_ = file;
257 data_->entry.base_filename_ = Basename(file);
258 data_->entry.line_ = line;
259 LogBacktraceIfNeeded();
260 return *this;
261 }
262
NoPrefix()263 LogMessage& LogMessage::NoPrefix() {
264 data_->entry.prefix_ = false;
265 return *this;
266 }
267
WithVerbosity(int verbose_level)268 LogMessage& LogMessage::WithVerbosity(int verbose_level) {
269 if (verbose_level == absl::LogEntry::kNoVerbosityLevel) {
270 data_->entry.verbose_level_ = absl::LogEntry::kNoVerbosityLevel;
271 } else {
272 data_->entry.verbose_level_ = std::max(0, verbose_level);
273 }
274 return *this;
275 }
276
WithTimestamp(absl::Time timestamp)277 LogMessage& LogMessage::WithTimestamp(absl::Time timestamp) {
278 data_->entry.timestamp_ = timestamp;
279 return *this;
280 }
281
WithThreadID(absl::LogEntry::tid_t tid)282 LogMessage& LogMessage::WithThreadID(absl::LogEntry::tid_t tid) {
283 data_->entry.tid_ = tid;
284 return *this;
285 }
286
WithMetadataFrom(const absl::LogEntry & entry)287 LogMessage& LogMessage::WithMetadataFrom(const absl::LogEntry& entry) {
288 data_->entry.full_filename_ = entry.full_filename_;
289 data_->entry.base_filename_ = entry.base_filename_;
290 data_->entry.line_ = entry.line_;
291 data_->entry.prefix_ = entry.prefix_;
292 data_->entry.severity_ = entry.severity_;
293 data_->entry.verbose_level_ = entry.verbose_level_;
294 data_->entry.timestamp_ = entry.timestamp_;
295 data_->entry.tid_ = entry.tid_;
296 return *this;
297 }
298
WithPerror()299 LogMessage& LogMessage::WithPerror() {
300 data_->is_perror = true;
301 return *this;
302 }
303
ToSinkAlso(absl::LogSink * sink)304 LogMessage& LogMessage::ToSinkAlso(absl::LogSink* sink) {
305 ABSL_INTERNAL_CHECK(sink, "null LogSink*");
306 data_->extra_sinks.push_back(sink);
307 return *this;
308 }
309
ToSinkOnly(absl::LogSink * sink)310 LogMessage& LogMessage::ToSinkOnly(absl::LogSink* sink) {
311 ABSL_INTERNAL_CHECK(sink, "null LogSink*");
312 data_->extra_sinks.clear();
313 data_->extra_sinks.push_back(sink);
314 data_->extra_sinks_only = true;
315 return *this;
316 }
317
318 #ifdef __ELF__
319 extern "C" void __gcov_dump() ABSL_ATTRIBUTE_WEAK;
320 extern "C" void __gcov_flush() ABSL_ATTRIBUTE_WEAK;
321 #endif
322
FailWithoutStackTrace()323 void LogMessage::FailWithoutStackTrace() {
324 // Now suppress repeated trace logging:
325 log_internal::SetSuppressSigabortTrace(true);
326 #if defined _DEBUG && defined COMPILER_MSVC
327 // When debugging on windows, avoid the obnoxious dialog.
328 __debugbreak();
329 #endif
330
331 #ifdef __ELF__
332 // For b/8737634, flush coverage if we are in coverage mode.
333 if (&__gcov_dump != nullptr) {
334 __gcov_dump();
335 } else if (&__gcov_flush != nullptr) {
336 __gcov_flush();
337 }
338 #endif
339
340 abort();
341 }
342
FailQuietly()343 void LogMessage::FailQuietly() {
344 // _exit. Calling abort() would trigger all sorts of death signal handlers
345 // and a detailed stack trace. Calling exit() would trigger the onexit
346 // handlers, including the heap-leak checker, which is guaranteed to fail in
347 // this case: we probably just new'ed the std::string that we logged.
348 // Anyway, if you're calling Fail or FailQuietly, you're trying to bail out
349 // of the program quickly, and it doesn't make much sense for FailQuietly to
350 // offer different guarantees about exit behavior than Fail does. (And as a
351 // consequence for QCHECK and CHECK to offer different exit behaviors)
352 _exit(1);
353 }
354
operator <<(const std::string & v)355 LogMessage& LogMessage::operator<<(const std::string& v) {
356 CopyToEncodedBuffer<StringType::kNotLiteral>(v);
357 return *this;
358 }
359
operator <<(absl::string_view v)360 LogMessage& LogMessage::operator<<(absl::string_view v) {
361 CopyToEncodedBuffer<StringType::kNotLiteral>(v);
362 return *this;
363 }
operator <<(std::ostream & (* m)(std::ostream & os))364 LogMessage& LogMessage::operator<<(std::ostream& (*m)(std::ostream& os)) {
365 OstreamView view(*data_);
366 data_->manipulated << m;
367 return *this;
368 }
operator <<(std::ios_base & (* m)(std::ios_base & os))369 LogMessage& LogMessage::operator<<(std::ios_base& (*m)(std::ios_base& os)) {
370 OstreamView view(*data_);
371 data_->manipulated << m;
372 return *this;
373 }
374 template LogMessage& LogMessage::operator<<(const char& v);
375 template LogMessage& LogMessage::operator<<(const signed char& v);
376 template LogMessage& LogMessage::operator<<(const unsigned char& v);
377 template LogMessage& LogMessage::operator<<(const short& v); // NOLINT
378 template LogMessage& LogMessage::operator<<(const unsigned short& v); // NOLINT
379 template LogMessage& LogMessage::operator<<(const int& v);
380 template LogMessage& LogMessage::operator<<(const unsigned int& v);
381 template LogMessage& LogMessage::operator<<(const long& v); // NOLINT
382 template LogMessage& LogMessage::operator<<(const unsigned long& v); // NOLINT
383 template LogMessage& LogMessage::operator<<(const long long& v); // NOLINT
384 template LogMessage& LogMessage::operator<<(
385 const unsigned long long& v); // NOLINT
386 template LogMessage& LogMessage::operator<<(void* const& v);
387 template LogMessage& LogMessage::operator<<(const void* const& v);
388 template LogMessage& LogMessage::operator<<(const float& v);
389 template LogMessage& LogMessage::operator<<(const double& v);
390 template LogMessage& LogMessage::operator<<(const bool& v);
391
Flush()392 void LogMessage::Flush() {
393 if (data_->entry.log_severity() < absl::MinLogLevel()) return;
394
395 if (data_->is_perror) {
396 InternalStream() << ": " << absl::base_internal::StrError(errno_saver_())
397 << " [" << errno_saver_() << "]";
398 }
399
400 // Have we already seen a fatal message?
401 ABSL_CONST_INIT static std::atomic<bool> seen_fatal(false);
402 if (data_->entry.log_severity() == absl::LogSeverity::kFatal &&
403 absl::log_internal::ExitOnDFatal()) {
404 // Exactly one LOG(FATAL) message is responsible for aborting the process,
405 // even if multiple threads LOG(FATAL) concurrently.
406 bool expected_seen_fatal = false;
407 if (seen_fatal.compare_exchange_strong(expected_seen_fatal, true,
408 std::memory_order_relaxed)) {
409 data_->first_fatal = true;
410 }
411 }
412
413 data_->FinalizeEncodingAndFormat();
414 data_->entry.encoding_ =
415 absl::string_view(data_->encoded_buf.data(),
416 static_cast<size_t>(data_->encoded_remaining.data() -
417 data_->encoded_buf.data()));
418 SendToLog();
419 }
420
SetFailQuietly()421 void LogMessage::SetFailQuietly() { data_->fail_quietly = true; }
422
OstreamView(LogMessageData & message_data)423 LogMessage::OstreamView::OstreamView(LogMessageData& message_data)
424 : data_(message_data), encoded_remaining_copy_(data_.encoded_remaining) {
425 // This constructor sets the `streambuf` up so that streaming into an attached
426 // ostream encodes string data in-place. To do that, we write appropriate
427 // headers into the buffer using a copy of the buffer view so that we can
428 // decide not to keep them later if nothing is ever streamed in. We don't
429 // know how much data we'll get, but we can use the size of the remaining
430 // buffer as an upper bound and fill in the right size once we know it.
431 message_start_ =
432 EncodeMessageStart(EventTag::kValue, encoded_remaining_copy_.size(),
433 &encoded_remaining_copy_);
434 string_start_ =
435 EncodeMessageStart(ValueTag::kString, encoded_remaining_copy_.size(),
436 &encoded_remaining_copy_);
437 setp(encoded_remaining_copy_.data(),
438 encoded_remaining_copy_.data() + encoded_remaining_copy_.size());
439 data_.manipulated.rdbuf(this);
440 }
441
~OstreamView()442 LogMessage::OstreamView::~OstreamView() {
443 data_.manipulated.rdbuf(nullptr);
444 if (!string_start_.data()) {
445 // The second field header didn't fit. Whether the first one did or not, we
446 // shouldn't commit `encoded_remaining_copy_`, and we also need to zero the
447 // size of `data_->encoded_remaining` so that no more data are encoded.
448 data_.encoded_remaining.remove_suffix(data_.encoded_remaining.size());
449 return;
450 }
451 const absl::Span<const char> contents(pbase(),
452 static_cast<size_t>(pptr() - pbase()));
453 if (contents.empty()) return;
454 encoded_remaining_copy_.remove_prefix(contents.size());
455 EncodeMessageLength(string_start_, &encoded_remaining_copy_);
456 EncodeMessageLength(message_start_, &encoded_remaining_copy_);
457 data_.encoded_remaining = encoded_remaining_copy_;
458 }
459
stream()460 std::ostream& LogMessage::OstreamView::stream() { return data_.manipulated; }
461
IsFatal() const462 bool LogMessage::IsFatal() const {
463 return data_->entry.log_severity() == absl::LogSeverity::kFatal &&
464 absl::log_internal::ExitOnDFatal();
465 }
466
PrepareToDie()467 void LogMessage::PrepareToDie() {
468 // If we log a FATAL message, flush all the log destinations, then toss
469 // a signal for others to catch. We leave the logs in a state that
470 // someone else can use them (as long as they flush afterwards)
471 if (data_->first_fatal) {
472 // Notify observers about the upcoming fatal error.
473 ABSL_INTERNAL_C_SYMBOL(AbslInternalOnFatalLogMessage)(data_->entry);
474 }
475
476 if (!data_->fail_quietly) {
477 // Log the message first before we start collecting stack trace.
478 log_internal::LogToSinks(data_->entry, absl::MakeSpan(data_->extra_sinks),
479 data_->extra_sinks_only);
480
481 // `DumpStackTrace` generates an empty string under MSVC.
482 // Adding the constant prefix here simplifies testing.
483 data_->entry.stacktrace_ = "*** Check failure stack trace: ***\n";
484 debugging_internal::DumpStackTrace(
485 0, log_internal::MaxFramesInLogStackTrace(),
486 log_internal::ShouldSymbolizeLogStackTrace(), WriteToString,
487 &data_->entry.stacktrace_);
488 }
489 }
490
Die()491 void LogMessage::Die() {
492 absl::FlushLogSinks();
493
494 if (data_->fail_quietly) {
495 FailQuietly();
496 } else {
497 FailWithoutStackTrace();
498 }
499 }
500
SendToLog()501 void LogMessage::SendToLog() {
502 if (IsFatal()) PrepareToDie();
503 // Also log to all registered sinks, even if OnlyLogToStderr() is set.
504 log_internal::LogToSinks(data_->entry, absl::MakeSpan(data_->extra_sinks),
505 data_->extra_sinks_only);
506 if (IsFatal()) Die();
507 }
508
LogBacktraceIfNeeded()509 void LogMessage::LogBacktraceIfNeeded() {
510 if (!absl::log_internal::IsInitialized()) return;
511
512 if (!absl::log_internal::ShouldLogBacktraceAt(data_->entry.source_basename(),
513 data_->entry.source_line()))
514 return;
515 OstreamView view(*data_);
516 view.stream() << " (stacktrace:\n";
517 debugging_internal::DumpStackTrace(
518 1, log_internal::MaxFramesInLogStackTrace(),
519 log_internal::ShouldSymbolizeLogStackTrace(), WriteToStream,
520 &view.stream());
521 view.stream() << ") ";
522 }
523
524 // Encodes into `data_->encoded_remaining` a partial `logging.proto.Event`
525 // containing the specified string data using a `Value` field appropriate to
526 // `str_type`. Truncates `str` if necessary, but emits nothing and marks the
527 // buffer full if even the field headers do not fit.
528 template <LogMessage::StringType str_type>
CopyToEncodedBuffer(absl::string_view str)529 void LogMessage::CopyToEncodedBuffer(absl::string_view str) {
530 auto encoded_remaining_copy = data_->encoded_remaining;
531 auto start = EncodeMessageStart(
532 EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + str.size(),
533 &encoded_remaining_copy);
534 // If the `logging.proto.Event.value` field header did not fit,
535 // `EncodeMessageStart` will have zeroed `encoded_remaining_copy`'s size and
536 // `EncodeStringTruncate` will fail too.
537 if (EncodeStringTruncate(str_type == StringType::kLiteral
538 ? ValueTag::kStringLiteral
539 : ValueTag::kString,
540 str, &encoded_remaining_copy)) {
541 // The string may have been truncated, but the field header fit.
542 EncodeMessageLength(start, &encoded_remaining_copy);
543 data_->encoded_remaining = encoded_remaining_copy;
544 } else {
545 // The field header(s) did not fit; zero `encoded_remaining` so we don't
546 // write anything else later.
547 data_->encoded_remaining.remove_suffix(data_->encoded_remaining.size());
548 }
549 }
550 template void LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>(
551 absl::string_view str);
552 template void LogMessage::CopyToEncodedBuffer<
553 LogMessage::StringType::kNotLiteral>(absl::string_view str);
554 template <LogMessage::StringType str_type>
CopyToEncodedBuffer(char ch,size_t num)555 void LogMessage::CopyToEncodedBuffer(char ch, size_t num) {
556 auto encoded_remaining_copy = data_->encoded_remaining;
557 auto value_start = EncodeMessageStart(
558 EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + num,
559 &encoded_remaining_copy);
560 auto str_start = EncodeMessageStart(str_type == StringType::kLiteral
561 ? ValueTag::kStringLiteral
562 : ValueTag::kString,
563 num, &encoded_remaining_copy);
564 if (str_start.data()) {
565 // The field headers fit.
566 log_internal::AppendTruncated(ch, num, encoded_remaining_copy);
567 EncodeMessageLength(str_start, &encoded_remaining_copy);
568 EncodeMessageLength(value_start, &encoded_remaining_copy);
569 data_->encoded_remaining = encoded_remaining_copy;
570 } else {
571 // The field header(s) did not fit; zero `encoded_remaining` so we don't
572 // write anything else later.
573 data_->encoded_remaining.remove_suffix(data_->encoded_remaining.size());
574 }
575 }
576 template void LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>(
577 char ch, size_t num);
578 template void LogMessage::CopyToEncodedBuffer<
579 LogMessage::StringType::kNotLiteral>(char ch, size_t num);
580
LogMessageFatal(const char * file,int line)581 LogMessageFatal::LogMessageFatal(const char* file, int line)
582 : LogMessage(file, line, absl::LogSeverity::kFatal) {}
583
LogMessageFatal(const char * file,int line,absl::string_view failure_msg)584 LogMessageFatal::LogMessageFatal(const char* file, int line,
585 absl::string_view failure_msg)
586 : LogMessage(file, line, absl::LogSeverity::kFatal) {
587 *this << "Check failed: " << failure_msg << " ";
588 }
589
590 // ABSL_ATTRIBUTE_NORETURN doesn't seem to work on destructors with msvc, so
591 // disable msvc's warning about the d'tor never returning.
592 #if defined(_MSC_VER) && !defined(__clang__)
593 #pragma warning(push)
594 #pragma warning(disable : 4722)
595 #endif
~LogMessageFatal()596 LogMessageFatal::~LogMessageFatal() {
597 Flush();
598 FailWithoutStackTrace();
599 }
600 #if defined(_MSC_VER) && !defined(__clang__)
601 #pragma warning(pop)
602 #endif
603
LogMessageQuietlyFatal(const char * file,int line)604 LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* file, int line)
605 : LogMessage(file, line, absl::LogSeverity::kFatal) {
606 SetFailQuietly();
607 }
608
LogMessageQuietlyFatal(const char * file,int line,absl::string_view failure_msg)609 LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* file, int line,
610 absl::string_view failure_msg)
611 : LogMessage(file, line, absl::LogSeverity::kFatal) {
612 SetFailQuietly();
613 *this << "Check failed: " << failure_msg << " ";
614 }
615
616 // ABSL_ATTRIBUTE_NORETURN doesn't seem to work on destructors with msvc, so
617 // disable msvc's warning about the d'tor never returning.
618 #if defined(_MSC_VER) && !defined(__clang__)
619 #pragma warning(push)
620 #pragma warning(disable : 4722)
621 #endif
~LogMessageQuietlyFatal()622 LogMessageQuietlyFatal::~LogMessageQuietlyFatal() {
623 Flush();
624 FailQuietly();
625 }
626 #if defined(_MSC_VER) && !defined(__clang__)
627 #pragma warning(pop)
628 #endif
629
630 } // namespace log_internal
631
632 ABSL_NAMESPACE_END
633 } // namespace absl
634