Skip to content

Commit

Permalink
New internal-use-only classes AsStructuredLiteralImpl and `AsStruct…
Browse files Browse the repository at this point in the history
…uredValueImpl`

PiperOrigin-RevId: 714130164
Change-Id: Ib76de9efeecf5344ed67ca27680937971d9a84e3
  • Loading branch information
Abseil Team authored and copybara-github committed Jan 10, 2025
1 parent 81d48b3 commit 69b5bd1
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 2 deletions.
3 changes: 3 additions & 0 deletions absl/log/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ absl_cc_library(
absl::log_internal_proto
absl::log_internal_log_sink_set
absl::log_internal_nullguard
absl::log_internal_structured_proto
absl::log_globals
absl::log_entry
absl::log_severity
Expand Down Expand Up @@ -666,9 +667,11 @@ absl_cc_library(
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::any_invocable
absl::config
absl::core_headers
absl::log_internal_message
absl::log_internal_structured_proto
absl::strings
)

Expand Down
28 changes: 27 additions & 1 deletion absl/log/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ load(

package(
default_visibility = [
"//absl/log:__pkg__",
":internal_users",
],
features = [
"header_modules",
Expand All @@ -34,6 +34,13 @@ package(

licenses(["notice"])

package_group(
name = "internal_users",
packages = [
"//absl/log",
],
)

package_group(
name = "structured_proto_users",
packages = [
Expand Down Expand Up @@ -183,6 +190,7 @@ cc_library(
":log_sink_set",
":nullguard",
":proto",
":structured_proto",
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
Expand Down Expand Up @@ -287,10 +295,16 @@ cc_library(
hdrs = ["structured.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
":internal_users",
":structured_proto_users",
],
deps = [
":log_message",
":structured_proto",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/functional:any_invocable",
"//absl/strings",
],
)
Expand Down Expand Up @@ -355,6 +369,10 @@ cc_library(
hdrs = ["test_helpers.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
":internal_users",
":structured_proto_users",
],
deps = [
":globals",
"//absl/base:config",
Expand All @@ -372,6 +390,10 @@ cc_library(
hdrs = ["test_matchers.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
":internal_users",
":structured_proto_users",
],
deps = [
":test_helpers",
"//absl/base:config",
Expand Down Expand Up @@ -402,6 +424,10 @@ cc_library(
hdrs = ["proto.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
":internal_users",
":structured_proto_users",
],
deps = [
"//absl/base",
"//absl/base:config",
Expand Down
42 changes: 42 additions & 0 deletions absl/log/internal/log_message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "absl/log/internal/log_format.h"
#include "absl/log/internal/log_sink_set.h"
#include "absl/log/internal/proto.h"
#include "absl/log/internal/structured_proto.h"
#include "absl/log/log_entry.h"
#include "absl/log/log_sink.h"
#include "absl/log/log_sink_registry.h"
Expand Down Expand Up @@ -632,6 +633,47 @@ template void LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>(
template void LogMessage::CopyToEncodedBuffer<
LogMessage::StringType::kNotLiteral>(char ch, size_t num);

template void LogMessage::CopyToEncodedBufferWithStructuredProtoField<
LogMessage::StringType::kLiteral>(StructuredProtoField field,
absl::string_view str);
template void LogMessage::CopyToEncodedBufferWithStructuredProtoField<
LogMessage::StringType::kNotLiteral>(StructuredProtoField field,
absl::string_view str);

template <LogMessage::StringType str_type>
void LogMessage::CopyToEncodedBufferWithStructuredProtoField(
StructuredProtoField field, absl::string_view str) {
auto encoded_remaining_copy = data_->encoded_remaining();
size_t encoded_field_size = BufferSizeForStructuredProtoField(field);
constexpr uint8_t tag_value = str_type == StringType::kLiteral
? ValueTag::kStringLiteral
: ValueTag::kString;
auto start = EncodeMessageStart(
EventTag::kValue,
encoded_field_size +
BufferSizeFor(tag_value, WireType::kLengthDelimited) + str.size(),
&encoded_remaining_copy);

// Write the encoded proto field.
if (!EncodeStructuredProtoField(field, encoded_remaining_copy)) {
// The header / field will not fit; zero `encoded_remaining()` so we
// don't write anything else later.
data_->encoded_remaining().remove_suffix(data_->encoded_remaining().size());
return;
}

// Write the string, truncating if necessary.
if (!EncodeStringTruncate(ValueTag::kString, str, &encoded_remaining_copy)) {
// The length of the string itself did not fit; zero `encoded_remaining()`
// so the value is not encoded at all.
data_->encoded_remaining().remove_suffix(data_->encoded_remaining().size());
return;
}

EncodeMessageLength(start, &encoded_remaining_copy);
data_->encoded_remaining() = encoded_remaining_copy;
}

// 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__)
Expand Down
14 changes: 14 additions & 0 deletions absl/log/internal/log_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "absl/base/log_severity.h"
#include "absl/base/nullability.h"
#include "absl/log/internal/nullguard.h"
#include "absl/log/internal/structured_proto.h"
#include "absl/log/log_entry.h"
#include "absl/log/log_sink.h"
#include "absl/strings/has_absl_stringify.h"
Expand All @@ -52,6 +53,8 @@ ABSL_NAMESPACE_BEGIN
namespace log_internal {
constexpr int kLogMessageBufferSize = 15000;

enum class StructuredStringType;

class LogMessage {
public:
struct InfoTag {};
Expand Down Expand Up @@ -217,6 +220,10 @@ class LogMessage {
struct LogMessageData; // Opaque type containing message state
friend class AsLiteralImpl;
friend class StringifySink;
template <StructuredStringType str_type>
friend class AsStructuredStringTypeImpl;
template <typename T>
friend class AsStructuredValueImpl;

// This streambuf writes directly into the structured logging buffer so that
// arbitrary types can be encoded as string data (using
Expand Down Expand Up @@ -247,6 +254,13 @@ class LogMessage {
template <StringType str_type>
void CopyToEncodedBuffer(char ch, size_t num) ABSL_ATTRIBUTE_NOINLINE;

// Copies `field` to the encoded buffer, then appends `str` after it
// (truncating `str` if necessary to fit).
template <StringType str_type>
void CopyToEncodedBufferWithStructuredProtoField(StructuredProtoField field,
absl::string_view str)
ABSL_ATTRIBUTE_NOINLINE;

// Returns `true` if the message is fatal or enabled debug-fatal.
bool IsFatal() const;

Expand Down
105 changes: 104 additions & 1 deletion absl/log/internal/structured.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@
#define ABSL_LOG_INTERNAL_STRUCTURED_H_

#include <ostream>
#include <string>

#include "absl/base/config.h"
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/functional/any_invocable.h"
#include "absl/log/internal/log_message.h"
#include "absl/log/internal/structured_proto.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"

namespace absl {
Expand Down Expand Up @@ -54,6 +58,105 @@ class ABSL_MUST_USE_RESULT AsLiteralImpl final {
}
};

enum class StructuredStringType {
kLiteral,
kNotLiteral,
};

// Structured log data for a string and associated structured proto field,
// both of which must outlive this object.
template <StructuredStringType str_type>
class ABSL_MUST_USE_RESULT AsStructuredStringTypeImpl final {
public:
constexpr AsStructuredStringTypeImpl(
absl::string_view str ABSL_ATTRIBUTE_LIFETIME_BOUND,
StructuredProtoField field ABSL_ATTRIBUTE_LIFETIME_BOUND)
: str_(str), field_(field) {}

private:
absl::string_view str_;
StructuredProtoField field_;

friend std::ostream& operator<<(std::ostream& os,
const AsStructuredStringTypeImpl& impl) {
return os << impl.str_;
}
void AddToMessage(LogMessage& m) const {
if (str_type == StructuredStringType::kLiteral) {
return m.CopyToEncodedBufferWithStructuredProtoField<
log_internal::LogMessage::StringType::kLiteral>(field_, str_);
} else {
return m.CopyToEncodedBufferWithStructuredProtoField<
log_internal::LogMessage::StringType::kNotLiteral>(field_, str_);
}
}
friend LogMessage& operator<<(LogMessage& m,
const AsStructuredStringTypeImpl& impl) {
impl.AddToMessage(m);
return m;
}
};

using AsStructuredLiteralImpl =
AsStructuredStringTypeImpl<StructuredStringType::kLiteral>;
using AsStructuredNotLiteralImpl =
AsStructuredStringTypeImpl<StructuredStringType::kNotLiteral>;

// Structured log data for a stringifyable type T and associated structured
// proto field, both of which must outlive this object.
template <typename T>
class ABSL_MUST_USE_RESULT AsStructuredValueImpl final {
public:
using ValueFormatter = absl::AnyInvocable<std::string(T) const>;

constexpr AsStructuredValueImpl(
T value ABSL_ATTRIBUTE_LIFETIME_BOUND,
StructuredProtoField field ABSL_ATTRIBUTE_LIFETIME_BOUND,
ValueFormatter value_formatter =
[](T value) { return absl::StrCat(value); })
: value_(value),
field_(field),
value_formatter_(std::move(value_formatter)) {}

private:
T value_;
StructuredProtoField field_;
ValueFormatter value_formatter_;

friend std::ostream& operator<<(std::ostream& os,
const AsStructuredValueImpl& impl) {
return os << impl.value_formatter_(impl.value_);
}
void AddToMessage(LogMessage& m) const {
m.CopyToEncodedBufferWithStructuredProtoField<
log_internal::LogMessage::StringType::kNotLiteral>(
field_, value_formatter_(value_));
}
friend LogMessage& operator<<(LogMessage& m,
const AsStructuredValueImpl& impl) {
impl.AddToMessage(m);
return m;
}
};

#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION

// Template deduction guide so `AsStructuredValueImpl(42, data)` works
// without specifying the template type.
template <typename T>
AsStructuredValueImpl(T value, StructuredProtoField field)
-> AsStructuredValueImpl<T>;

// Template deduction guide so `AsStructuredValueImpl(42, data, formatter)`
// works without specifying the template type.
template <typename T>
AsStructuredValueImpl(
T value, StructuredProtoField field,
typename AsStructuredValueImpl<T>::ValueFormatter value_formatter)
-> AsStructuredValueImpl<T>;

#endif // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION

} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
Expand Down

0 comments on commit 69b5bd1

Please sign in to comment.