diff options
Diffstat (limited to 'absl/log/internal')
-rw-r--r-- | absl/log/internal/BUILD.bazel | 7 | ||||
-rw-r--r-- | absl/log/internal/check_op.cc | 20 | ||||
-rw-r--r-- | absl/log/internal/check_op.h | 84 | ||||
-rw-r--r-- | absl/log/internal/conditions.h | 4 | ||||
-rw-r--r-- | absl/log/internal/log_impl.h | 46 | ||||
-rw-r--r-- | absl/log/internal/log_message.cc | 151 | ||||
-rw-r--r-- | absl/log/internal/log_message.h | 27 | ||||
-rw-r--r-- | absl/log/internal/nullstream.h | 11 | ||||
-rw-r--r-- | absl/log/internal/strip.h | 36 | ||||
-rw-r--r-- | absl/log/internal/test_matchers.cc | 9 | ||||
-rw-r--r-- | absl/log/internal/test_matchers.h | 2 |
11 files changed, 282 insertions, 115 deletions
diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel index 1be13499..2dbf337a 100644 --- a/absl/log/internal/BUILD.bazel +++ b/absl/log/internal/BUILD.bazel @@ -266,6 +266,7 @@ cc_library( deps = [ ":log_message", ":nullstream", + "//absl/base:core_headers", "//absl/base:log_severity", ], ) @@ -384,7 +385,9 @@ cc_library( hdrs = ["vlog_config.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = ["//absl/log:__subpackages__"], + visibility = [ + "//absl/log:__subpackages__", + ], deps = [ "//absl/base", "//absl/base:config", @@ -400,7 +403,7 @@ cc_library( cc_binary( name = "vlog_config_benchmark", - testonly = 1, + testonly = True, srcs = ["vlog_config_benchmark.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, diff --git a/absl/log/internal/check_op.cc b/absl/log/internal/check_op.cc index f4b67647..23c4a3b2 100644 --- a/absl/log/internal/check_op.cc +++ b/absl/log/internal/check_op.cc @@ -16,6 +16,10 @@ #include <string.h> +#include <ostream> + +#include "absl/strings/string_view.h" + #ifdef _MSC_VER #define strcasecmp _stricmp #else @@ -113,6 +117,22 @@ DEFINE_CHECK_STROP_IMPL(CHECK_STRCASEEQ, strcasecmp, true) DEFINE_CHECK_STROP_IMPL(CHECK_STRCASENE, strcasecmp, false) #undef DEFINE_CHECK_STROP_IMPL +namespace detect_specialization { + +StringifySink::StringifySink(std::ostream& os) : os_(os) {} + +void StringifySink::Append(absl::string_view text) { os_ << text; } + +void StringifySink::Append(size_t length, char ch) { + for (size_t i = 0; i < length; ++i) os_.put(ch); +} + +void AbslFormatFlush(StringifySink* sink, absl::string_view text) { + sink->Append(text); +} + +} // namespace detect_specialization + } // namespace log_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/log/internal/check_op.h b/absl/log/internal/check_op.h index 11f0f407..21592207 100644 --- a/absl/log/internal/check_op.h +++ b/absl/log/internal/check_op.h @@ -24,9 +24,11 @@ #include <stdint.h> +#include <cstddef> #include <ostream> #include <sstream> #include <string> +#include <type_traits> #include <utility> #include "absl/base/attributes.h" @@ -35,6 +37,8 @@ #include "absl/log/internal/nullguard.h" #include "absl/log/internal/nullstream.h" #include "absl/log/internal/strip.h" +#include "absl/strings/has_absl_stringify.h" +#include "absl/strings/string_view.h" // `ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL` wraps string literals that // should be stripped when `ABSL_MIN_LOG_LEVEL` exceeds `kFatal`. @@ -58,13 +62,13 @@ #endif #define ABSL_LOG_INTERNAL_CHECK_OP(name, op, val1, val1_text, val2, val2_text) \ - while ( \ - ::std::string* absl_log_internal_check_op_result ABSL_ATTRIBUTE_UNUSED = \ - ::absl::log_internal::name##Impl( \ - ::absl::log_internal::GetReferenceableValue(val1), \ - ::absl::log_internal::GetReferenceableValue(val2), \ - ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val1_text \ - " " #op " " val2_text))) \ + while (::std::string* absl_log_internal_check_op_result \ + ABSL_LOG_INTERNAL_ATTRIBUTE_UNUSED_IF_STRIP_LOG = \ + ::absl::log_internal::name##Impl( \ + ::absl::log_internal::GetReferenceableValue(val1), \ + ::absl::log_internal::GetReferenceableValue(val2), \ + ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \ + val1_text " " #op " " val2_text))) \ ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \ ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_op_result).InternalStream() #define ABSL_LOG_INTERNAL_QCHECK_OP(name, op, val1, val1_text, val2, \ @@ -287,6 +291,44 @@ decltype(detect_specialization::operator<<(std::declval<std::ostream&>(), std::declval<const T&>())) Detect(char); +// A sink for AbslStringify which redirects everything to a std::ostream. +class StringifySink { + public: + explicit StringifySink(std::ostream& os ABSL_ATTRIBUTE_LIFETIME_BOUND); + + void Append(absl::string_view text); + void Append(size_t length, char ch); + friend void AbslFormatFlush(StringifySink* sink, absl::string_view text); + + private: + std::ostream& os_; +}; + +// Wraps a type implementing AbslStringify, and implements operator<<. +template <typename T> +class StringifyToStreamWrapper { + public: + explicit StringifyToStreamWrapper(const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND) + : v_(v) {} + + friend std::ostream& operator<<(std::ostream& os, + const StringifyToStreamWrapper& wrapper) { + StringifySink sink(os); + AbslStringify(sink, wrapper.v_); + return os; + } + + private: + const T& v_; +}; + +// This overload triggers when T implements AbslStringify. +// StringifyToStreamWrapper is used to allow MakeCheckOpString to use +// operator<<. +template <typename T> +std::enable_if_t<HasAbslStringify<T>::value, + StringifyToStreamWrapper<T>> +Detect(...); // Ellipsis has lowest preference when int passed. } // namespace detect_specialization template <typename T> @@ -342,20 +384,20 @@ ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void*); // `(int, int)` override works around the issue that the compiler will not // instantiate the template version of the function on values of unnamed enum // type. -#define ABSL_LOG_INTERNAL_CHECK_OP_IMPL(name, op) \ - template <typename T1, typename T2> \ - inline constexpr ::std::string* name##Impl(const T1& v1, const T2& v2, \ - const char* exprtext) { \ - using U1 = CheckOpStreamType<T1>; \ - using U2 = CheckOpStreamType<T2>; \ - return ABSL_PREDICT_TRUE(v1 op v2) \ - ? nullptr \ - : ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, v1, v2, \ - exprtext); \ - } \ - inline constexpr ::std::string* name##Impl(int v1, int v2, \ - const char* exprtext) { \ - return name##Impl<int, int>(v1, v2, exprtext); \ +#define ABSL_LOG_INTERNAL_CHECK_OP_IMPL(name, op) \ + template <typename T1, typename T2> \ + inline constexpr ::std::string* name##Impl(const T1& v1, const T2& v2, \ + const char* exprtext) { \ + using U1 = CheckOpStreamType<T1>; \ + using U2 = CheckOpStreamType<T2>; \ + return ABSL_PREDICT_TRUE(v1 op v2) \ + ? nullptr \ + : ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, U1(v1), \ + U2(v2), exprtext); \ + } \ + inline constexpr ::std::string* name##Impl(int v1, int v2, \ + const char* exprtext) { \ + return name##Impl<int, int>(v1, v2, exprtext); \ } ABSL_LOG_INTERNAL_CHECK_OP_IMPL(Check_EQ, ==) diff --git a/absl/log/internal/conditions.h b/absl/log/internal/conditions.h index 645f3c23..9dc15db4 100644 --- a/absl/log/internal/conditions.h +++ b/absl/log/internal/conditions.h @@ -230,8 +230,8 @@ class LogEveryNSecState final { // Helper routines to abort the application quietly -ABSL_ATTRIBUTE_NORETURN inline void AbortQuietly() { abort(); } -ABSL_ATTRIBUTE_NORETURN inline void ExitQuietly() { _exit(1); } +[[noreturn]] inline void AbortQuietly() { abort(); } +[[noreturn]] inline void ExitQuietly() { _exit(1); } } // namespace log_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/log/internal/log_impl.h b/absl/log/internal/log_impl.h index 99de6dbb..a67f2f31 100644 --- a/absl/log/internal/log_impl.h +++ b/absl/log/internal/log_impl.h @@ -35,14 +35,14 @@ #ifndef NDEBUG #define ABSL_LOG_INTERNAL_DLOG_IMPL(severity) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true) \ - ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #else #define ABSL_LOG_INTERNAL_DLOG_IMPL(severity) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, false) \ - ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #endif -// The `switch` ensures that this expansion is the begnning of a statement (as +// The `switch` ensures that this expansion is the beginning of a statement (as // opposed to an expression). The use of both `case 0` and `default` is to // suppress a compiler warning. #define ABSL_LOG_INTERNAL_VLOG_IMPL(verbose_level) \ @@ -58,7 +58,7 @@ switch (const int absl_logging_internal_verbose_level = (verbose_level)) \ case 0: \ default: \ - ABSL_LOG_INTERNAL_LOG_IF_IMPL( \ + ABSL_LOG_INTERNAL_DLOG_IF_IMPL( \ _INFO, ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level)) \ .WithVerbosity(absl_logging_internal_verbose_level) #else @@ -66,7 +66,7 @@ switch (const int absl_logging_internal_verbose_level = (verbose_level)) \ case 0: \ default: \ - ABSL_LOG_INTERNAL_LOG_IF_IMPL( \ + ABSL_LOG_INTERNAL_DLOG_IF_IMPL( \ _INFO, false && ABSL_VLOG_IS_ON(absl_logging_internal_verbose_level)) \ .WithVerbosity(absl_logging_internal_verbose_level) #endif @@ -82,11 +82,11 @@ #ifndef NDEBUG #define ABSL_LOG_INTERNAL_DLOG_IF_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, condition) \ - ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #else #define ABSL_LOG_INTERNAL_DLOG_IF_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, false && (condition)) \ - ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #endif // ABSL_LOG_EVERY_N @@ -132,36 +132,36 @@ #ifndef NDEBUG #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(severity, n) \ ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ - (EveryN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + (EveryN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(severity, n) \ ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ - (FirstN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + (FirstN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(severity) \ ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ - (EveryPow2) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + (EveryPow2) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ - (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #else // def NDEBUG #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(severity, n) \ ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ - (EveryN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + (EveryN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(severity, n) \ ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ - (FirstN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + (FirstN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(severity) \ ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ - (EveryPow2) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + (EveryPow2) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ - (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #endif // def NDEBUG #define ABSL_LOG_INTERNAL_VLOG_EVERY_N_IMPL(verbose_level, n) \ @@ -243,40 +243,40 @@ #ifndef NDEBUG #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryN, n) \ - ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(FirstN, n) \ - ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryPow2) \ - ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(severity, condition, \ n_seconds) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryNSec, \ n_seconds) \ - ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #else // def NDEBUG #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ - EveryN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + EveryN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ - FirstN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + FirstN, n) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ - EveryPow2) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + EveryPow2) ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(severity, condition, \ n_seconds) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ EveryNSec, n_seconds) \ - ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() + ABSL_LOGGING_INTERNAL_DLOG##severity.InternalStream() #endif // def NDEBUG #endif // ABSL_LOG_INTERNAL_LOG_IMPL_H_ diff --git a/absl/log/internal/log_message.cc b/absl/log/internal/log_message.cc index 10ac2453..4e9b08af 100644 --- a/absl/log/internal/log_message.cc +++ b/absl/log/internal/log_message.cc @@ -27,6 +27,7 @@ #include <algorithm> #include <array> #include <atomic> +#include <ios> #include <memory> #include <ostream> #include <string> @@ -67,7 +68,14 @@ namespace log_internal { namespace { // message `logging.proto.Event` enum EventTag : uint8_t { + kFileName = 2, + kFileLine = 3, + kTimeNsecs = 4, + kSeverity = 5, + kThreadId = 6, kValue = 7, + kSequenceNumber = 9, + kThreadName = 10, }; // message `logging.proto.Value` @@ -100,6 +108,23 @@ bool PrintValue(absl::Span<char>& dst, absl::Span<const char> buf) { return true; } +// See `logging.proto.Severity` +int32_t ProtoSeverity(absl::LogSeverity severity, int verbose_level) { + switch (severity) { + case absl::LogSeverity::kInfo: + if (verbose_level == absl::LogEntry::kNoVerbosityLevel) return 800; + return 600 - verbose_level; + case absl::LogSeverity::kWarning: + return 900; + case absl::LogSeverity::kError: + return 950; + case absl::LogSeverity::kFatal: + return 1100; + default: + return 800; + } +} + absl::string_view Basename(absl::string_view filepath) { #ifdef _WIN32 size_t path = filepath.find_last_of("/\\"); @@ -145,26 +170,37 @@ struct LogMessage::LogMessageData final { // A `logging.proto.Event` proto message is built into `encoded_buf`. std::array<char, kLogMessageBufferSize> encoded_buf; - // `encoded_remaining` is the suffix of `encoded_buf` that has not been filled - // yet. If a datum to be encoded does not fit into `encoded_remaining` and - // cannot be truncated to fit, the size of `encoded_remaining` will be zeroed - // to prevent encoding of any further data. Note that in this case its data() - // pointer will not point past the end of `encoded_buf`. - absl::Span<char> encoded_remaining; + // `encoded_remaining()` is the suffix of `encoded_buf` that has not been + // filled yet. If a datum to be encoded does not fit into + // `encoded_remaining()` and cannot be truncated to fit, the size of + // `encoded_remaining()` will be zeroed to prevent encoding of any further + // data. Note that in this case its `data()` pointer will not point past the + // end of `encoded_buf`. + // The first use of `encoded_remaining()` is our chance to record metadata + // after any modifications (e.g. by `AtLocation()`) but before any data have + // been recorded. We want to record metadata before data so that data are + // preferentially truncated if we run out of buffer. + absl::Span<char>& encoded_remaining() { + if (encoded_remaining_actual_do_not_use_directly.data() == nullptr) { + encoded_remaining_actual_do_not_use_directly = + absl::MakeSpan(encoded_buf); + InitializeEncodingAndFormat(); + } + return encoded_remaining_actual_do_not_use_directly; + } + absl::Span<char> encoded_remaining_actual_do_not_use_directly; // A formatted string message is built in `string_buf`. std::array<char, kLogMessageBufferSize> string_buf; + void InitializeEncodingAndFormat(); void FinalizeEncodingAndFormat(); }; LogMessage::LogMessageData::LogMessageData(const char* file, int line, absl::LogSeverity severity, absl::Time timestamp) - : extra_sinks_only(false), - manipulated(nullptr), - // This `absl::MakeSpan` silences spurious -Wuninitialized from GCC: - encoded_remaining(absl::MakeSpan(encoded_buf)) { + : extra_sinks_only(false), manipulated(nullptr) { // Legacy defaults for LOG's ostream: manipulated.setf(std::ios_base::showbase | std::ios_base::boolalpha); entry.full_filename_ = file; @@ -177,13 +213,25 @@ LogMessage::LogMessageData::LogMessageData(const char* file, int line, entry.tid_ = absl::base_internal::GetCachedTID(); } +void LogMessage::LogMessageData::InitializeEncodingAndFormat() { + EncodeStringTruncate(EventTag::kFileName, entry.source_filename(), + &encoded_remaining()); + EncodeVarint(EventTag::kFileLine, entry.source_line(), &encoded_remaining()); + EncodeVarint(EventTag::kTimeNsecs, absl::ToUnixNanos(entry.timestamp()), + &encoded_remaining()); + EncodeVarint(EventTag::kSeverity, + ProtoSeverity(entry.log_severity(), entry.verbosity()), + &encoded_remaining()); + EncodeVarint(EventTag::kThreadId, entry.tid(), &encoded_remaining()); +} + void LogMessage::LogMessageData::FinalizeEncodingAndFormat() { - // Note that `encoded_remaining` may have zero size without pointing past the - // end of `encoded_buf`, so the difference between `data()` pointers is used - // to compute the size of `encoded_data`. + // Note that `encoded_remaining()` may have zero size without pointing past + // the end of `encoded_buf`, so the difference between `data()` pointers is + // used to compute the size of `encoded_data`. absl::Span<const char> encoded_data( encoded_buf.data(), - static_cast<size_t>(encoded_remaining.data() - encoded_buf.data())); + static_cast<size_t>(encoded_remaining().data() - encoded_buf.data())); // `string_remaining` is the suffix of `string_buf` that has not been filled // yet. absl::Span<char> string_remaining(string_buf); @@ -211,7 +259,6 @@ void LogMessage::LogMessageData::FinalizeEncodingAndFormat() { if (PrintValue(string_remaining, field.bytes_value())) continue; break; } - break; } auto chars_written = static_cast<size_t>(string_remaining.data() - string_buf.data()); @@ -413,7 +460,7 @@ void LogMessage::Flush() { data_->FinalizeEncodingAndFormat(); data_->entry.encoding_ = absl::string_view(data_->encoded_buf.data(), - static_cast<size_t>(data_->encoded_remaining.data() - + static_cast<size_t>(data_->encoded_remaining().data() - data_->encoded_buf.data())); SendToLog(); } @@ -421,7 +468,7 @@ void LogMessage::Flush() { void LogMessage::SetFailQuietly() { data_->fail_quietly = true; } LogMessage::OstreamView::OstreamView(LogMessageData& message_data) - : data_(message_data), encoded_remaining_copy_(data_.encoded_remaining) { + : data_(message_data), encoded_remaining_copy_(data_.encoded_remaining()) { // This constructor sets the `streambuf` up so that streaming into an attached // ostream encodes string data in-place. To do that, we write appropriate // headers into the buffer using a copy of the buffer view so that we can @@ -444,8 +491,8 @@ LogMessage::OstreamView::~OstreamView() { if (!string_start_.data()) { // The second field header didn't fit. Whether the first one did or not, we // shouldn't commit `encoded_remaining_copy_`, and we also need to zero the - // size of `data_->encoded_remaining` so that no more data are encoded. - data_.encoded_remaining.remove_suffix(data_.encoded_remaining.size()); + // size of `data_->encoded_remaining()` so that no more data are encoded. + data_.encoded_remaining().remove_suffix(data_.encoded_remaining().size()); return; } const absl::Span<const char> contents(pbase(), @@ -454,7 +501,7 @@ LogMessage::OstreamView::~OstreamView() { encoded_remaining_copy_.remove_prefix(contents.size()); EncodeMessageLength(string_start_, &encoded_remaining_copy_); EncodeMessageLength(message_start_, &encoded_remaining_copy_); - data_.encoded_remaining = encoded_remaining_copy_; + data_.encoded_remaining() = encoded_remaining_copy_; } std::ostream& LogMessage::OstreamView::stream() { return data_.manipulated; } @@ -521,13 +568,13 @@ void LogMessage::LogBacktraceIfNeeded() { view.stream() << ") "; } -// Encodes into `data_->encoded_remaining` a partial `logging.proto.Event` +// Encodes into `data_->encoded_remaining()` a partial `logging.proto.Event` // containing the specified string data using a `Value` field appropriate to // `str_type`. Truncates `str` if necessary, but emits nothing and marks the // buffer full if even the field headers do not fit. template <LogMessage::StringType str_type> void LogMessage::CopyToEncodedBuffer(absl::string_view str) { - auto encoded_remaining_copy = data_->encoded_remaining; + auto encoded_remaining_copy = data_->encoded_remaining(); auto start = EncodeMessageStart( EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + str.size(), &encoded_remaining_copy); @@ -540,11 +587,11 @@ void LogMessage::CopyToEncodedBuffer(absl::string_view str) { str, &encoded_remaining_copy)) { // The string may have been truncated, but the field header fit. EncodeMessageLength(start, &encoded_remaining_copy); - data_->encoded_remaining = encoded_remaining_copy; + data_->encoded_remaining() = encoded_remaining_copy; } else { - // The field header(s) did not fit; zero `encoded_remaining` so we don't + // The field header(s) did not fit; zero `encoded_remaining()` so we don't // write anything else later. - data_->encoded_remaining.remove_suffix(data_->encoded_remaining.size()); + data_->encoded_remaining().remove_suffix(data_->encoded_remaining().size()); } } template void LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>( @@ -553,7 +600,7 @@ template void LogMessage::CopyToEncodedBuffer< LogMessage::StringType::kNotLiteral>(absl::string_view str); template <LogMessage::StringType str_type> void LogMessage::CopyToEncodedBuffer(char ch, size_t num) { - auto encoded_remaining_copy = data_->encoded_remaining; + auto encoded_remaining_copy = data_->encoded_remaining(); auto value_start = EncodeMessageStart( EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + num, &encoded_remaining_copy); @@ -566,11 +613,11 @@ void LogMessage::CopyToEncodedBuffer(char ch, size_t num) { log_internal::AppendTruncated(ch, num, encoded_remaining_copy); EncodeMessageLength(str_start, &encoded_remaining_copy); EncodeMessageLength(value_start, &encoded_remaining_copy); - data_->encoded_remaining = encoded_remaining_copy; + data_->encoded_remaining() = encoded_remaining_copy; } else { - // The field header(s) did not fit; zero `encoded_remaining` so we don't + // The field header(s) did not fit; zero `encoded_remaining()` so we don't // write anything else later. - data_->encoded_remaining.remove_suffix(data_->encoded_remaining.size()); + data_->encoded_remaining().remove_suffix(data_->encoded_remaining().size()); } } template void LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>( @@ -578,6 +625,13 @@ template void LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>( template void LogMessage::CopyToEncodedBuffer< LogMessage::StringType::kNotLiteral>(char ch, size_t num); +// We intentionally don't return from these destructors. Disable MSVC's warning +// about the destructor never returning as we do so intentionally here. +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(push) +#pragma warning(disable : 4722) +#endif + LogMessageFatal::LogMessageFatal(const char* file, int line) : LogMessage(file, line, absl::LogSeverity::kFatal) {} @@ -587,19 +641,29 @@ LogMessageFatal::LogMessageFatal(const char* file, int line, *this << "Check failed: " << failure_msg << " "; } -// ABSL_ATTRIBUTE_NORETURN doesn't seem to work on destructors with msvc, so -// disable msvc's warning about the d'tor never returning. -#if defined(_MSC_VER) && !defined(__clang__) -#pragma warning(push) -#pragma warning(disable : 4722) -#endif LogMessageFatal::~LogMessageFatal() { Flush(); FailWithoutStackTrace(); } -#if defined(_MSC_VER) && !defined(__clang__) -#pragma warning(pop) -#endif + +LogMessageDebugFatal::LogMessageDebugFatal(const char* file, int line) + : LogMessage(file, line, absl::LogSeverity::kFatal) {} + +LogMessageDebugFatal::~LogMessageDebugFatal() { + Flush(); + FailWithoutStackTrace(); +} + +LogMessageQuietlyDebugFatal::LogMessageQuietlyDebugFatal(const char* file, + int line) + : LogMessage(file, line, absl::LogSeverity::kFatal) { + SetFailQuietly(); +} + +LogMessageQuietlyDebugFatal::~LogMessageQuietlyDebugFatal() { + Flush(); + FailQuietly(); +} LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* file, int line) : LogMessage(file, line, absl::LogSeverity::kFatal) { @@ -608,17 +672,10 @@ LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* file, int line) LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* file, int line, absl::string_view failure_msg) - : LogMessage(file, line, absl::LogSeverity::kFatal) { - SetFailQuietly(); - *this << "Check failed: " << failure_msg << " "; + : LogMessageQuietlyFatal(file, line) { + *this << "Check failed: " << failure_msg << " "; } -// ABSL_ATTRIBUTE_NORETURN doesn't seem to work on destructors with msvc, so -// disable msvc's warning about the d'tor never returning. -#if defined(_MSC_VER) && !defined(__clang__) -#pragma warning(push) -#pragma warning(disable : 4722) -#endif LogMessageQuietlyFatal::~LogMessageQuietlyFatal() { Flush(); FailQuietly(); diff --git a/absl/log/internal/log_message.h b/absl/log/internal/log_message.h index 4ecb8a14..0c067da9 100644 --- a/absl/log/internal/log_message.h +++ b/absl/log/internal/log_message.h @@ -187,11 +187,11 @@ class LogMessage { protected: // Call `abort()` or similar to perform `LOG(FATAL)` crash. It is assumed // that the caller has already generated and written the trace as appropriate. - ABSL_ATTRIBUTE_NORETURN static void FailWithoutStackTrace(); + [[noreturn]] static void FailWithoutStackTrace(); // Similar to `FailWithoutStackTrace()`, but without `abort()`. Terminates // the process with an error exit code. - ABSL_ATTRIBUTE_NORETURN static void FailQuietly(); + [[noreturn]] static void FailQuietly(); // Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s. // This might as well be inlined into `~LogMessage` except that @@ -354,15 +354,34 @@ class LogMessageFatal final : public LogMessage { LogMessageFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD; LogMessageFatal(const char* file, int line, absl::string_view failure_msg) ABSL_ATTRIBUTE_COLD; - ABSL_ATTRIBUTE_NORETURN ~LogMessageFatal(); + [[noreturn]] ~LogMessageFatal(); }; +// `LogMessageDebugFatal` ensures the process will exit in failure after logging +// this message. It matches LogMessageFatal but is not [[noreturn]] as it's used +// for DLOG(FATAL) variants. +class LogMessageDebugFatal final : public LogMessage { + public: + LogMessageDebugFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD; + ~LogMessageDebugFatal(); +}; + +class LogMessageQuietlyDebugFatal final : public LogMessage { + public: + // DLOG(QFATAL) calls this instead of LogMessageQuietlyFatal to make sure the + // destructor is not [[noreturn]] even if this is always FATAL as this is only + // invoked when DLOG() is enabled. + LogMessageQuietlyDebugFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD; + ~LogMessageQuietlyDebugFatal(); +}; + +// Used for LOG(QFATAL) to make sure it's properly understood as [[noreturn]]. class LogMessageQuietlyFatal final : public LogMessage { public: LogMessageQuietlyFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD; LogMessageQuietlyFatal(const char* file, int line, absl::string_view failure_msg) ABSL_ATTRIBUTE_COLD; - ABSL_ATTRIBUTE_NORETURN ~LogMessageQuietlyFatal(); + [[noreturn]] ~LogMessageQuietlyFatal(); }; } // namespace log_internal diff --git a/absl/log/internal/nullstream.h b/absl/log/internal/nullstream.h index 9266852e..973e91ab 100644 --- a/absl/log/internal/nullstream.h +++ b/absl/log/internal/nullstream.h @@ -117,16 +117,7 @@ class NullStreamMaybeFatal final : public NullStream { class NullStreamFatal final : public NullStream { public: NullStreamFatal() = default; - // ABSL_ATTRIBUTE_NORETURN doesn't seem to work on destructors with msvc, so - // disable msvc's warning about the d'tor never returning. -#if defined(_MSC_VER) && !defined(__clang__) -#pragma warning(push) -#pragma warning(disable : 4722) -#endif - ABSL_ATTRIBUTE_NORETURN ~NullStreamFatal() { _exit(1); } -#if defined(_MSC_VER) && !defined(__clang__) -#pragma warning(pop) -#endif + [[noreturn]] ~NullStreamFatal() { _exit(1); } }; } // namespace log_internal diff --git a/absl/log/internal/strip.h b/absl/log/internal/strip.h index f8d27869..3e550104 100644 --- a/absl/log/internal/strip.h +++ b/absl/log/internal/strip.h @@ -20,6 +20,7 @@ #ifndef ABSL_LOG_INTERNAL_STRIP_H_ #define ABSL_LOG_INTERNAL_STRIP_H_ +#include "absl/base/attributes.h" // IWYU pragma: keep #include "absl/base/log_severity.h" #include "absl/log/internal/log_message.h" #include "absl/log/internal/nullstream.h" @@ -29,6 +30,16 @@ // of defines comes in three flavors: vanilla, plus two variants that strip some // logging in subtly different ways for subtly different reasons (see below). #if defined(STRIP_LOG) && STRIP_LOG + +// Attribute for marking variables used in implementation details of logging +// macros as unused, but only when `STRIP_LOG` is defined. +// With `STRIP_LOG` on, not marking them triggers `-Wunused-but-set-variable`, +// With `STRIP_LOG` off, marking them triggers `-Wused-but-marked-unused`. +// +// TODO(b/290784225): Replace this macro with attribute [[maybe_unused]] when +// Abseil stops supporting C++14. +#define ABSL_LOG_INTERNAL_ATTRIBUTE_UNUSED_IF_STRIP_LOG ABSL_ATTRIBUTE_UNUSED + #define ABSL_LOGGING_INTERNAL_LOG_INFO ::absl::log_internal::NullStream() #define ABSL_LOGGING_INTERNAL_LOG_WARNING ::absl::log_internal::NullStream() #define ABSL_LOGGING_INTERNAL_LOG_ERROR ::absl::log_internal::NullStream() @@ -38,10 +49,21 @@ ::absl::log_internal::NullStreamMaybeFatal(::absl::kLogDebugFatal) #define ABSL_LOGGING_INTERNAL_LOG_LEVEL(severity) \ ::absl::log_internal::NullStreamMaybeFatal(absl_log_internal_severity) + +// Fatal `DLOG`s expand a little differently to avoid being `[[noreturn]]`. +#define ABSL_LOGGING_INTERNAL_DLOG_FATAL \ + ::absl::log_internal::NullStreamMaybeFatal(::absl::LogSeverity::kFatal) +#define ABSL_LOGGING_INTERNAL_DLOG_QFATAL \ + ::absl::log_internal::NullStreamMaybeFatal(::absl::LogSeverity::kFatal) + #define ABSL_LOG_INTERNAL_CHECK(failure_message) ABSL_LOGGING_INTERNAL_LOG_FATAL #define ABSL_LOG_INTERNAL_QCHECK(failure_message) \ ABSL_LOGGING_INTERNAL_LOG_QFATAL + #else // !defined(STRIP_LOG) || !STRIP_LOG + +#define ABSL_LOG_INTERNAL_ATTRIBUTE_UNUSED_IF_STRIP_LOG + #define ABSL_LOGGING_INTERNAL_LOG_INFO \ ::absl::log_internal::LogMessage( \ __FILE__, __LINE__, ::absl::log_internal::LogMessage::InfoTag{}) @@ -60,6 +82,13 @@ #define ABSL_LOGGING_INTERNAL_LOG_LEVEL(severity) \ ::absl::log_internal::LogMessage(__FILE__, __LINE__, \ absl_log_internal_severity) + +// Fatal `DLOG`s expand a little differently to avoid being `[[noreturn]]`. +#define ABSL_LOGGING_INTERNAL_DLOG_FATAL \ + ::absl::log_internal::LogMessageDebugFatal(__FILE__, __LINE__) +#define ABSL_LOGGING_INTERNAL_DLOG_QFATAL \ + ::absl::log_internal::LogMessageQuietlyDebugFatal(__FILE__, __LINE__) + // These special cases dispatch to special-case constructors that allow us to // avoid an extra function call and shrink non-LTO binaries by a percent or so. #define ABSL_LOG_INTERNAL_CHECK(failure_message) \ @@ -69,4 +98,11 @@ failure_message) #endif // !defined(STRIP_LOG) || !STRIP_LOG +// This part of a non-fatal `DLOG`s expands the same as `LOG`. +#define ABSL_LOGGING_INTERNAL_DLOG_INFO ABSL_LOGGING_INTERNAL_LOG_INFO +#define ABSL_LOGGING_INTERNAL_DLOG_WARNING ABSL_LOGGING_INTERNAL_LOG_WARNING +#define ABSL_LOGGING_INTERNAL_DLOG_ERROR ABSL_LOGGING_INTERNAL_LOG_ERROR +#define ABSL_LOGGING_INTERNAL_DLOG_DFATAL ABSL_LOGGING_INTERNAL_LOG_DFATAL +#define ABSL_LOGGING_INTERNAL_DLOG_LEVEL ABSL_LOGGING_INTERNAL_LOG_LEVEL + #endif // ABSL_LOG_INTERNAL_STRIP_H_ diff --git a/absl/log/internal/test_matchers.cc b/absl/log/internal/test_matchers.cc index 8c6515c4..042083d8 100644 --- a/absl/log/internal/test_matchers.cc +++ b/absl/log/internal/test_matchers.cc @@ -26,6 +26,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/log/internal/test_helpers.h" +#include "absl/log/log_entry.h" #include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" @@ -131,11 +132,9 @@ Matcher<const absl::LogEntry&> Timestamp( return Property("timestamp", &absl::LogEntry::timestamp, timestamp); } -Matcher<const absl::LogEntry&> TimestampInMatchWindow() { - return Property("timestamp", &absl::LogEntry::timestamp, - AllOf(Ge(absl::Now()), Truly([](absl::Time arg) { - return arg <= absl::Now(); - }))); +Matcher<absl::Time> InMatchWindow() { + return AllOf(Ge(absl::Now()), + Truly([](absl::Time arg) { return arg <= absl::Now(); })); } Matcher<const absl::LogEntry&> ThreadID( diff --git a/absl/log/internal/test_matchers.h b/absl/log/internal/test_matchers.h index fc653a91..906eda24 100644 --- a/absl/log/internal/test_matchers.h +++ b/absl/log/internal/test_matchers.h @@ -62,7 +62,7 @@ namespace log_internal { const ::testing::Matcher<absl::Time>& timestamp); // Matches if the `LogEntry`'s timestamp falls after the instantiation of this // matcher and before its execution, as is normal when used with EXPECT_CALL. -::testing::Matcher<const absl::LogEntry&> TimestampInMatchWindow(); +::testing::Matcher<absl::Time> InMatchWindow(); ::testing::Matcher<const absl::LogEntry&> ThreadID( const ::testing::Matcher<absl::LogEntry::tid_t>&); ::testing::Matcher<const absl::LogEntry&> TextMessageWithPrefixAndNewline( |