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