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