aboutsummaryrefslogtreecommitdiff
path: root/absl/log/internal/log_message.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/log/internal/log_message.h')
-rw-r--r--absl/log/internal/log_message.h106
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.