/src/abseil-cpp/absl/log/internal/log_message.cc
Line | Count | Source (jump to first uncovered line) |
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 | | |
58 | | extern "C" ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL( |
59 | 0 | AbslInternalOnFatalLogMessage)(const absl::LogEntry&) { |
60 | | // Default - Do nothing |
61 | 0 | } |
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. |
87 | 6.47M | bool PrintValue(absl::Span<char>& dst, absl::Span<const char> buf) { |
88 | 6.47M | if (dst.size() <= 1) return false; |
89 | 6.47M | ProtoField field; |
90 | 12.9M | while (field.DecodeFrom(&buf)) { |
91 | 6.47M | switch (field.tag()) { |
92 | 3.23M | case ValueTag::kString: |
93 | 6.47M | case ValueTag::kStringLiteral: |
94 | 6.47M | if (field.type() == WireType::kLengthDelimited) |
95 | 6.47M | if (log_internal::AppendTruncated(field.string_value(), dst) < |
96 | 6.47M | field.string_value().size()) |
97 | 0 | return false; |
98 | 6.47M | } |
99 | 6.47M | } |
100 | 6.47M | return true; |
101 | 6.47M | } |
102 | | |
103 | 3.24M | absl::string_view Basename(absl::string_view filepath) { |
104 | | #ifdef _WIN32 |
105 | | size_t path = filepath.find_last_of("/\\"); |
106 | | #else |
107 | 3.24M | size_t path = filepath.find_last_of('/'); |
108 | 3.24M | #endif |
109 | 3.24M | if (path != filepath.npos) filepath.remove_prefix(path + 1); |
110 | 3.24M | return filepath; |
111 | 3.24M | } |
112 | | |
113 | 0 | void WriteToString(const char* data, void* str) { |
114 | 0 | reinterpret_cast<std::string*>(str)->append(data); |
115 | 0 | } |
116 | 0 | void WriteToStream(const char* data, void* os) { |
117 | 0 | auto* cast_os = static_cast<std::ostream*>(os); |
118 | 0 | *cast_os << data; |
119 | 0 | } |
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 | | |
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 | 3.24M | encoded_remaining(absl::MakeSpan(encoded_buf)) { |
168 | | // Legacy defaults for LOG's ostream: |
169 | 3.24M | manipulated.setf(std::ios_base::showbase | std::ios_base::boolalpha); |
170 | 3.24M | entry.full_filename_ = file; |
171 | 3.24M | entry.base_filename_ = Basename(file); |
172 | 3.24M | entry.line_ = line; |
173 | 3.24M | entry.prefix_ = absl::ShouldPrependLogPrefix(); |
174 | 3.24M | entry.severity_ = absl::NormalizeLogSeverity(severity); |
175 | 3.24M | entry.verbose_level_ = absl::LogEntry::kNoVerbosityLevel; |
176 | 3.24M | entry.timestamp_ = timestamp; |
177 | 3.24M | entry.tid_ = absl::base_internal::GetCachedTID(); |
178 | 3.24M | } |
179 | | |
180 | 3.24M | 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 | 3.24M | absl::Span<const char> encoded_data( |
185 | 3.24M | encoded_buf.data(), |
186 | 3.24M | 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 | 3.24M | 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 | 3.24M | string_remaining.remove_suffix(2); |
195 | 3.24M | entry.prefix_len_ = |
196 | 3.24M | entry.prefix() ? log_internal::FormatLogPrefix( |
197 | 3.24M | entry.log_severity(), entry.timestamp(), entry.tid(), |
198 | 3.24M | entry.source_basename(), entry.source_line(), |
199 | 3.24M | log_internal::ThreadIsLoggingToLogSink() |
200 | 3.24M | ? PrefixFormat::kRaw |
201 | 3.24M | : PrefixFormat::kNotRaw, |
202 | 3.24M | string_remaining) |
203 | 3.24M | : 0; |
204 | | // Decode data from `encoded_buf` until we run out of data or we run out of |
205 | | // `string_remaining`. |
206 | 3.24M | ProtoField field; |
207 | 9.71M | while (field.DecodeFrom(&encoded_data)) { |
208 | 6.47M | switch (field.tag()) { |
209 | 6.47M | case EventTag::kValue: |
210 | 6.47M | if (field.type() != WireType::kLengthDelimited) continue; |
211 | 6.47M | if (PrintValue(string_remaining, field.bytes_value())) continue; |
212 | 0 | break; |
213 | 6.47M | } |
214 | 0 | break; |
215 | 6.47M | } |
216 | 3.24M | auto chars_written = |
217 | 3.24M | static_cast<size_t>(string_remaining.data() - string_buf.data()); |
218 | 3.24M | string_buf[chars_written++] = '\n'; |
219 | 3.24M | string_buf[chars_written++] = '\0'; |
220 | 3.24M | entry.text_message_with_prefix_and_newline_and_nul_ = |
221 | 3.24M | absl::MakeSpan(string_buf).subspan(0, chars_written); |
222 | 3.24M | } |
223 | | |
224 | | LogMessage::LogMessage(const char* file, int line, absl::LogSeverity severity) |
225 | | : data_(absl::make_unique<LogMessageData>(file, line, severity, |
226 | 3.24M | absl::Now())) { |
227 | 3.24M | data_->first_fatal = false; |
228 | 3.24M | data_->is_perror = false; |
229 | 3.24M | 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 | 3.24M | LogBacktraceIfNeeded(); |
235 | 3.24M | } |
236 | | |
237 | | LogMessage::LogMessage(const char* file, int line, InfoTag) |
238 | 0 | : LogMessage(file, line, absl::LogSeverity::kInfo) {} |
239 | | LogMessage::LogMessage(const char* file, int line, WarningTag) |
240 | 3.69k | : LogMessage(file, line, absl::LogSeverity::kWarning) {} |
241 | | LogMessage::LogMessage(const char* file, int line, ErrorTag) |
242 | 3.23M | : LogMessage(file, line, absl::LogSeverity::kError) {} |
243 | | |
244 | 3.24M | 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 | 3.24M | Flush(); |
253 | 3.24M | } |
254 | | |
255 | 0 | LogMessage& LogMessage::AtLocation(absl::string_view file, int line) { |
256 | 0 | data_->entry.full_filename_ = file; |
257 | 0 | data_->entry.base_filename_ = Basename(file); |
258 | 0 | data_->entry.line_ = line; |
259 | 0 | LogBacktraceIfNeeded(); |
260 | 0 | return *this; |
261 | 0 | } |
262 | | |
263 | 0 | LogMessage& LogMessage::NoPrefix() { |
264 | 0 | data_->entry.prefix_ = false; |
265 | 0 | return *this; |
266 | 0 | } |
267 | | |
268 | 0 | LogMessage& LogMessage::WithVerbosity(int verbose_level) { |
269 | 0 | if (verbose_level == absl::LogEntry::kNoVerbosityLevel) { |
270 | 0 | data_->entry.verbose_level_ = absl::LogEntry::kNoVerbosityLevel; |
271 | 0 | } else { |
272 | 0 | data_->entry.verbose_level_ = std::max(0, verbose_level); |
273 | 0 | } |
274 | 0 | return *this; |
275 | 0 | } |
276 | | |
277 | 0 | LogMessage& LogMessage::WithTimestamp(absl::Time timestamp) { |
278 | 0 | data_->entry.timestamp_ = timestamp; |
279 | 0 | return *this; |
280 | 0 | } |
281 | | |
282 | 0 | LogMessage& LogMessage::WithThreadID(absl::LogEntry::tid_t tid) { |
283 | 0 | data_->entry.tid_ = tid; |
284 | 0 | return *this; |
285 | 0 | } |
286 | | |
287 | 0 | LogMessage& LogMessage::WithMetadataFrom(const absl::LogEntry& entry) { |
288 | 0 | data_->entry.full_filename_ = entry.full_filename_; |
289 | 0 | data_->entry.base_filename_ = entry.base_filename_; |
290 | 0 | data_->entry.line_ = entry.line_; |
291 | 0 | data_->entry.prefix_ = entry.prefix_; |
292 | 0 | data_->entry.severity_ = entry.severity_; |
293 | 0 | data_->entry.verbose_level_ = entry.verbose_level_; |
294 | 0 | data_->entry.timestamp_ = entry.timestamp_; |
295 | 0 | data_->entry.tid_ = entry.tid_; |
296 | 0 | return *this; |
297 | 0 | } |
298 | | |
299 | 0 | LogMessage& LogMessage::WithPerror() { |
300 | 0 | data_->is_perror = true; |
301 | 0 | return *this; |
302 | 0 | } |
303 | | |
304 | 0 | LogMessage& LogMessage::ToSinkAlso(absl::LogSink* sink) { |
305 | 0 | ABSL_INTERNAL_CHECK(sink, "null LogSink*"); |
306 | 0 | data_->extra_sinks.push_back(sink); |
307 | 0 | return *this; |
308 | 0 | } |
309 | | |
310 | 0 | LogMessage& LogMessage::ToSinkOnly(absl::LogSink* sink) { |
311 | 0 | ABSL_INTERNAL_CHECK(sink, "null LogSink*"); |
312 | 0 | data_->extra_sinks.clear(); |
313 | 0 | data_->extra_sinks.push_back(sink); |
314 | 0 | data_->extra_sinks_only = true; |
315 | 0 | return *this; |
316 | 0 | } |
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 | | |
323 | 0 | void LogMessage::FailWithoutStackTrace() { |
324 | | // Now suppress repeated trace logging: |
325 | 0 | 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 | 0 | #ifdef __ELF__ |
332 | | // For b/8737634, flush coverage if we are in coverage mode. |
333 | 0 | if (&__gcov_dump != nullptr) { |
334 | 0 | __gcov_dump(); |
335 | 0 | } else if (&__gcov_flush != nullptr) { |
336 | 0 | __gcov_flush(); |
337 | 0 | } |
338 | 0 | #endif |
339 | |
|
340 | 0 | abort(); |
341 | 0 | } |
342 | | |
343 | 0 | 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 | 0 | _exit(1); |
353 | 0 | } |
354 | | |
355 | 0 | LogMessage& LogMessage::operator<<(const std::string& v) { |
356 | 0 | CopyToEncodedBuffer<StringType::kNotLiteral>(v); |
357 | 0 | return *this; |
358 | 0 | } |
359 | | |
360 | 0 | LogMessage& LogMessage::operator<<(absl::string_view v) { |
361 | 0 | CopyToEncodedBuffer<StringType::kNotLiteral>(v); |
362 | 0 | return *this; |
363 | 0 | } |
364 | 0 | LogMessage& LogMessage::operator<<(std::ostream& (*m)(std::ostream& os)) { |
365 | 0 | OstreamView view(*data_); |
366 | 0 | data_->manipulated << m; |
367 | 0 | return *this; |
368 | 0 | } |
369 | 0 | LogMessage& LogMessage::operator<<(std::ios_base& (*m)(std::ios_base& os)) { |
370 | 0 | OstreamView view(*data_); |
371 | 0 | data_->manipulated << m; |
372 | 0 | return *this; |
373 | 0 | } |
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 | | |
392 | 3.24M | void LogMessage::Flush() { |
393 | 3.24M | if (data_->entry.log_severity() < absl::MinLogLevel()) return; |
394 | | |
395 | 3.24M | if (data_->is_perror) { |
396 | 0 | InternalStream() << ": " << absl::base_internal::StrError(errno_saver_()) |
397 | 0 | << " [" << errno_saver_() << "]"; |
398 | 0 | } |
399 | | |
400 | | // Have we already seen a fatal message? |
401 | 3.24M | ABSL_CONST_INIT static std::atomic<bool> seen_fatal(false); |
402 | 3.24M | if (data_->entry.log_severity() == absl::LogSeverity::kFatal && |
403 | 3.24M | 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 | 0 | bool expected_seen_fatal = false; |
407 | 0 | if (seen_fatal.compare_exchange_strong(expected_seen_fatal, true, |
408 | 0 | std::memory_order_relaxed)) { |
409 | 0 | data_->first_fatal = true; |
410 | 0 | } |
411 | 0 | } |
412 | | |
413 | 3.24M | data_->FinalizeEncodingAndFormat(); |
414 | 3.24M | data_->entry.encoding_ = |
415 | 3.24M | absl::string_view(data_->encoded_buf.data(), |
416 | 3.24M | static_cast<size_t>(data_->encoded_remaining.data() - |
417 | 3.24M | data_->encoded_buf.data())); |
418 | 3.24M | SendToLog(); |
419 | 3.24M | } |
420 | | |
421 | 0 | void LogMessage::SetFailQuietly() { data_->fail_quietly = true; } |
422 | | |
423 | | LogMessage::OstreamView::OstreamView(LogMessageData& message_data) |
424 | 3.23M | : 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 | 3.23M | message_start_ = |
432 | 3.23M | EncodeMessageStart(EventTag::kValue, encoded_remaining_copy_.size(), |
433 | 3.23M | &encoded_remaining_copy_); |
434 | 3.23M | string_start_ = |
435 | 3.23M | EncodeMessageStart(ValueTag::kString, encoded_remaining_copy_.size(), |
436 | 3.23M | &encoded_remaining_copy_); |
437 | 3.23M | setp(encoded_remaining_copy_.data(), |
438 | 3.23M | encoded_remaining_copy_.data() + encoded_remaining_copy_.size()); |
439 | 3.23M | data_.manipulated.rdbuf(this); |
440 | 3.23M | } |
441 | | |
442 | 3.23M | LogMessage::OstreamView::~OstreamView() { |
443 | 3.23M | data_.manipulated.rdbuf(nullptr); |
444 | 3.23M | 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 | 0 | data_.encoded_remaining.remove_suffix(data_.encoded_remaining.size()); |
449 | 0 | return; |
450 | 0 | } |
451 | 3.23M | const absl::Span<const char> contents(pbase(), |
452 | 3.23M | static_cast<size_t>(pptr() - pbase())); |
453 | 3.23M | if (contents.empty()) return; |
454 | 3.23M | encoded_remaining_copy_.remove_prefix(contents.size()); |
455 | 3.23M | EncodeMessageLength(string_start_, &encoded_remaining_copy_); |
456 | 3.23M | EncodeMessageLength(message_start_, &encoded_remaining_copy_); |
457 | 3.23M | data_.encoded_remaining = encoded_remaining_copy_; |
458 | 3.23M | } |
459 | | |
460 | 3.23M | std::ostream& LogMessage::OstreamView::stream() { return data_.manipulated; } |
461 | | |
462 | 6.48M | bool LogMessage::IsFatal() const { |
463 | 6.48M | return data_->entry.log_severity() == absl::LogSeverity::kFatal && |
464 | 6.48M | absl::log_internal::ExitOnDFatal(); |
465 | 6.48M | } |
466 | | |
467 | 0 | 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 | 0 | if (data_->first_fatal) { |
472 | | // Notify observers about the upcoming fatal error. |
473 | 0 | ABSL_INTERNAL_C_SYMBOL(AbslInternalOnFatalLogMessage)(data_->entry); |
474 | 0 | } |
475 | |
|
476 | 0 | if (!data_->fail_quietly) { |
477 | | // Log the message first before we start collecting stack trace. |
478 | 0 | log_internal::LogToSinks(data_->entry, absl::MakeSpan(data_->extra_sinks), |
479 | 0 | data_->extra_sinks_only); |
480 | | |
481 | | // `DumpStackTrace` generates an empty string under MSVC. |
482 | | // Adding the constant prefix here simplifies testing. |
483 | 0 | data_->entry.stacktrace_ = "*** Check failure stack trace: ***\n"; |
484 | 0 | debugging_internal::DumpStackTrace( |
485 | 0 | 0, log_internal::MaxFramesInLogStackTrace(), |
486 | 0 | log_internal::ShouldSymbolizeLogStackTrace(), WriteToString, |
487 | 0 | &data_->entry.stacktrace_); |
488 | 0 | } |
489 | 0 | } |
490 | | |
491 | 0 | void LogMessage::Die() { |
492 | 0 | absl::FlushLogSinks(); |
493 | |
|
494 | 0 | if (data_->fail_quietly) { |
495 | 0 | FailQuietly(); |
496 | 0 | } else { |
497 | 0 | FailWithoutStackTrace(); |
498 | 0 | } |
499 | 0 | } |
500 | | |
501 | 3.24M | void LogMessage::SendToLog() { |
502 | 3.24M | if (IsFatal()) PrepareToDie(); |
503 | | // Also log to all registered sinks, even if OnlyLogToStderr() is set. |
504 | 3.24M | log_internal::LogToSinks(data_->entry, absl::MakeSpan(data_->extra_sinks), |
505 | 3.24M | data_->extra_sinks_only); |
506 | 3.24M | if (IsFatal()) Die(); |
507 | 3.24M | } |
508 | | |
509 | 3.24M | void LogMessage::LogBacktraceIfNeeded() { |
510 | 3.24M | if (!absl::log_internal::IsInitialized()) return; |
511 | | |
512 | 0 | if (!absl::log_internal::ShouldLogBacktraceAt(data_->entry.source_basename(), |
513 | 0 | data_->entry.source_line())) |
514 | 0 | return; |
515 | 0 | OstreamView view(*data_); |
516 | 0 | view.stream() << " (stacktrace:\n"; |
517 | 0 | debugging_internal::DumpStackTrace( |
518 | 0 | 1, log_internal::MaxFramesInLogStackTrace(), |
519 | 0 | log_internal::ShouldSymbolizeLogStackTrace(), WriteToStream, |
520 | 0 | &view.stream()); |
521 | 0 | view.stream() << ") "; |
522 | 0 | } |
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> |
529 | 3.24M | void LogMessage::CopyToEncodedBuffer(absl::string_view str) { |
530 | 3.24M | auto encoded_remaining_copy = data_->encoded_remaining; |
531 | 3.24M | auto start = EncodeMessageStart( |
532 | 3.24M | EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + str.size(), |
533 | 3.24M | &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 | 3.24M | if (EncodeStringTruncate(str_type == StringType::kLiteral |
538 | 3.24M | ? ValueTag::kStringLiteral |
539 | 3.24M | : ValueTag::kString, |
540 | 3.24M | str, &encoded_remaining_copy)) { |
541 | | // The string may have been truncated, but the field header fit. |
542 | 3.24M | EncodeMessageLength(start, &encoded_remaining_copy); |
543 | 3.24M | data_->encoded_remaining = encoded_remaining_copy; |
544 | 3.24M | } else { |
545 | | // The field header(s) did not fit; zero `encoded_remaining` so we don't |
546 | | // write anything else later. |
547 | 0 | data_->encoded_remaining.remove_suffix(data_->encoded_remaining.size()); |
548 | 0 | } |
549 | 3.24M | } void absl::log_internal::LogMessage::CopyToEncodedBuffer<(absl::log_internal::LogMessage::StringType)0>(absl::string_view) Line | Count | Source | 529 | 3.24M | void LogMessage::CopyToEncodedBuffer(absl::string_view str) { | 530 | 3.24M | auto encoded_remaining_copy = data_->encoded_remaining; | 531 | 3.24M | auto start = EncodeMessageStart( | 532 | 3.24M | EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + str.size(), | 533 | 3.24M | &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 | 3.24M | if (EncodeStringTruncate(str_type == StringType::kLiteral | 538 | 3.24M | ? ValueTag::kStringLiteral | 539 | 3.24M | : ValueTag::kString, | 540 | 3.24M | str, &encoded_remaining_copy)) { | 541 | | // The string may have been truncated, but the field header fit. | 542 | 3.24M | EncodeMessageLength(start, &encoded_remaining_copy); | 543 | 3.24M | data_->encoded_remaining = encoded_remaining_copy; | 544 | 3.24M | } else { | 545 | | // The field header(s) did not fit; zero `encoded_remaining` so we don't | 546 | | // write anything else later. | 547 | 0 | data_->encoded_remaining.remove_suffix(data_->encoded_remaining.size()); | 548 | 0 | } | 549 | 3.24M | } |
Unexecuted instantiation: void absl::log_internal::LogMessage::CopyToEncodedBuffer<(absl::log_internal::LogMessage::StringType)1>(absl::string_view) |
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> |
555 | 0 | void LogMessage::CopyToEncodedBuffer(char ch, size_t num) { |
556 | 0 | auto encoded_remaining_copy = data_->encoded_remaining; |
557 | 0 | auto value_start = EncodeMessageStart( |
558 | 0 | EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + num, |
559 | 0 | &encoded_remaining_copy); |
560 | 0 | auto str_start = EncodeMessageStart(str_type == StringType::kLiteral |
561 | 0 | ? ValueTag::kStringLiteral |
562 | 0 | : ValueTag::kString, |
563 | 0 | num, &encoded_remaining_copy); |
564 | 0 | if (str_start.data()) { |
565 | | // The field headers fit. |
566 | 0 | log_internal::AppendTruncated(ch, num, encoded_remaining_copy); |
567 | 0 | EncodeMessageLength(str_start, &encoded_remaining_copy); |
568 | 0 | EncodeMessageLength(value_start, &encoded_remaining_copy); |
569 | 0 | data_->encoded_remaining = encoded_remaining_copy; |
570 | 0 | } else { |
571 | | // The field header(s) did not fit; zero `encoded_remaining` so we don't |
572 | | // write anything else later. |
573 | 0 | data_->encoded_remaining.remove_suffix(data_->encoded_remaining.size()); |
574 | 0 | } |
575 | 0 | } Unexecuted instantiation: void absl::log_internal::LogMessage::CopyToEncodedBuffer<(absl::log_internal::LogMessage::StringType)0>(char, unsigned long) Unexecuted instantiation: void absl::log_internal::LogMessage::CopyToEncodedBuffer<(absl::log_internal::LogMessage::StringType)1>(char, unsigned long) |
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 | | |
581 | | LogMessageFatal::LogMessageFatal(const char* file, int line) |
582 | 0 | : LogMessage(file, line, absl::LogSeverity::kFatal) {} |
583 | | |
584 | | LogMessageFatal::LogMessageFatal(const char* file, int line, |
585 | | absl::string_view failure_msg) |
586 | 0 | : LogMessage(file, line, absl::LogSeverity::kFatal) { |
587 | 0 | *this << "Check failed: " << failure_msg << " "; |
588 | 0 | } |
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 |
596 | 0 | LogMessageFatal::~LogMessageFatal() { |
597 | 0 | Flush(); |
598 | 0 | FailWithoutStackTrace(); |
599 | 0 | } |
600 | | #if defined(_MSC_VER) && !defined(__clang__) |
601 | | #pragma warning(pop) |
602 | | #endif |
603 | | |
604 | | LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* file, int line) |
605 | 0 | : LogMessage(file, line, absl::LogSeverity::kFatal) { |
606 | 0 | SetFailQuietly(); |
607 | 0 | } |
608 | | |
609 | | LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* file, int line, |
610 | | absl::string_view failure_msg) |
611 | 0 | : LogMessage(file, line, absl::LogSeverity::kFatal) { |
612 | 0 | SetFailQuietly(); |
613 | 0 | *this << "Check failed: " << failure_msg << " "; |
614 | 0 | } |
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 |
622 | 0 | LogMessageQuietlyFatal::~LogMessageQuietlyFatal() { |
623 | 0 | Flush(); |
624 | 0 | FailQuietly(); |
625 | 0 | } |
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 |