diff options
Diffstat (limited to 'absl/log/internal/log_message.h')
-rw-r--r-- | absl/log/internal/log_message.h | 106 |
1 files changed, 87 insertions, 19 deletions
diff --git a/absl/log/internal/log_message.h b/absl/log/internal/log_message.h index 37a267c0..3744276b 100644 --- a/absl/log/internal/log_message.h +++ b/absl/log/internal/log_message.h @@ -37,17 +37,16 @@ #include "absl/base/config.h" #include "absl/base/internal/errno_saver.h" #include "absl/base/log_severity.h" -#include "absl/log/internal/config.h" #include "absl/log/internal/nullguard.h" #include "absl/log/log_entry.h" #include "absl/log/log_sink.h" +#include "absl/strings/internal/has_absl_stringify.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace log_internal { - constexpr int kLogMessageBufferSize = 15000; class LogMessage { @@ -130,6 +129,10 @@ class LogMessage { LogMessage& operator<<(bool v) { return operator<< <bool>(v); } // clang-format on + // These overloads are more efficient since no `ostream` is involved. + LogMessage& operator<<(const std::string& v); + LogMessage& operator<<(absl::string_view v); + // Handle stream manipulators e.g. std::endl. LogMessage& operator<<(std::ostream& (*m)(std::ostream& os)); LogMessage& operator<<(std::ios_base& (*m)(std::ios_base& os)); @@ -153,8 +156,17 @@ class LogMessage { template <int SIZE> LogMessage& operator<<(char (&buf)[SIZE]) ABSL_ATTRIBUTE_NOINLINE; - // Default: uses `ostream` logging to convert `v` to a string. - template <typename T> + // Types that support `AbslStringify()` are serialized that way. + template <typename T, + typename std::enable_if< + strings_internal::HasAbslStringify<T>::value, int>::type = 0> + LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE; + + // Types that don't support `AbslStringify()` but do support streaming into a + // `std::ostream&` are serialized that way. + template <typename T, + typename std::enable_if< + !strings_internal::HasAbslStringify<T>::value, int>::type = 0> LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE; // Note: We explicitly do not support `operator<<` for non-const references @@ -180,6 +192,37 @@ class LogMessage { private: struct LogMessageData; // Opaque type containing message state + friend class AsLiteralImpl; + friend class StringifySink; + + // This streambuf writes directly into the structured logging buffer so that + // arbitrary types can be encoded as string data (using + // `operator<<(std::ostream &, ...)` without any extra allocation or copying. + // Space is reserved before the data to store the length field, which is + // filled in by `~OstreamView`. + class OstreamView final : public std::streambuf { + public: + explicit OstreamView(LogMessageData& message_data); + ~OstreamView() override; + OstreamView(const OstreamView&) = delete; + OstreamView& operator=(const OstreamView&) = delete; + std::ostream& stream(); + + private: + LogMessageData& data_; + absl::Span<char> encoded_remaining_copy_; + absl::Span<char> message_start_; + absl::Span<char> string_start_; + }; + + enum class StringType { + kLiteral, + kNotLiteral, + }; + void CopyToEncodedBuffer(absl::string_view str, + StringType str_type) ABSL_ATTRIBUTE_NOINLINE; + void CopyToEncodedBuffer(char ch, size_t num, + StringType str_type) ABSL_ATTRIBUTE_NOINLINE; // Returns `true` if the message is fatal or enabled debug-fatal. bool IsFatal() const; @@ -201,35 +244,62 @@ class LogMessage { // We keep the data in a separate struct so that each instance of `LogMessage` // uses less stack space. std::unique_ptr<LogMessageData> data_; +}; + +// Helper class so that `AbslStringify()` can modify the LogMessage. +class StringifySink final { + public: + explicit StringifySink(LogMessage& message) : message_(message) {} + + void Append(size_t count, char ch) { + message_.CopyToEncodedBuffer(ch, count, + LogMessage::StringType::kNotLiteral); + } + + void Append(absl::string_view v) { + message_.CopyToEncodedBuffer(v, LogMessage::StringType::kNotLiteral); + } - std::ostream stream_; + // For types that implement `AbslStringify` using `absl::Format()`. + friend void AbslFormatFlush(StringifySink* sink, absl::string_view v) { + sink->Append(v); + } + + private: + LogMessage& message_; }; // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE` -template <typename T> +template <typename T, + typename std::enable_if<strings_internal::HasAbslStringify<T>::value, + int>::type> LogMessage& LogMessage::operator<<(const T& v) { - stream_ << log_internal::NullGuard<T>().Guard(v); - return *this; -} -inline LogMessage& LogMessage::operator<<( - std::ostream& (*m)(std::ostream& os)) { - stream_ << m; + StringifySink sink(*this); + // Replace with public API. + AbslStringify(sink, v); return *this; } -inline LogMessage& LogMessage::operator<<( - std::ios_base& (*m)(std::ios_base& os)) { - stream_ << m; + +// Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE` +template <typename T, + typename std::enable_if<!strings_internal::HasAbslStringify<T>::value, + int>::type> +LogMessage& LogMessage::operator<<(const T& v) { + OstreamView view(*data_); + view.stream() << log_internal::NullGuard<T>().Guard(v); return *this; } + template <int SIZE> LogMessage& LogMessage::operator<<(const char (&buf)[SIZE]) { - stream_ << buf; + CopyToEncodedBuffer(buf, StringType::kLiteral); return *this; } + // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE` template <int SIZE> LogMessage& LogMessage::operator<<(char (&buf)[SIZE]) { - stream_ << buf; + CopyToEncodedBuffer(buf, StringType::kNotLiteral); return *this; } // We instantiate these specializations in the library's TU to save space in @@ -256,8 +326,6 @@ extern template LogMessage& LogMessage::operator<<(const void* const& v); extern template LogMessage& LogMessage::operator<<(const float& v); extern template LogMessage& LogMessage::operator<<(const double& v); extern template LogMessage& LogMessage::operator<<(const bool& v); -extern template LogMessage& LogMessage::operator<<(const std::string& v); -extern template LogMessage& LogMessage::operator<<(const absl::string_view& v); // `LogMessageFatal` ensures the process will exit in failure after logging this // message. |