summaryrefslogtreecommitdiff
path: root/absl/log/internal/log_message.h
diff options
context:
space:
mode:
authorGravatar Phoebe Liang <phoebeliang@google.com>2022-11-02 15:27:54 -0700
committerGravatar Copybara-Service <copybara-worker@google.com>2022-11-02 15:28:46 -0700
commite6044634dd7caec2d79a13aecc9e765023768757 (patch)
tree3ffe2c00f4b5e49da4f4e7d9e50c64999f318408 /absl/log/internal/log_message.h
parent1649c037c556bdaca7241bc0113275506bdb9638 (diff)
Support logging of user-defined types that implement `AbslStringify()`
If a user-defined type has `AbslStringify()` defined, it will always be used for logging over `operator<<`. `HasAbslStringify` now uses the empty class `UnimplementedSink` for its checks instead of `StringifySink` in order to make it work in cases involving other sinks. PiperOrigin-RevId: 485710377 Change-Id: Ibdd916151c7abc3269c35fbe79b772867f3d25e1
Diffstat (limited to 'absl/log/internal/log_message.h')
-rw-r--r--absl/log/internal/log_message.h48
1 files changed, 45 insertions, 3 deletions
diff --git a/absl/log/internal/log_message.h b/absl/log/internal/log_message.h
index 37a267c0..992bb630 100644
--- a/absl/log/internal/log_message.h
+++ b/absl/log/internal/log_message.h
@@ -41,6 +41,7 @@
#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"
@@ -153,8 +154,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
@@ -205,12 +215,44 @@ class LogMessage {
std::ostream stream_;
};
+// 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_ << std::string(count, ch); }
+
+ void Append(absl::string_view v) { message_ << v; }
+
+ // 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,
+ typename std::enable_if<strings_internal::HasAbslStringify<T>::value,
+ int>::type>
+LogMessage& LogMessage::operator<<(const T& v) {
+ StringifySink sink(*this);
+ // Replace with public API.
+ AbslStringify(sink, v);
+ return *this;
+}
+
// 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;