Skip to content

Commit

Permalink
New class StructuredProtoField
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 711892840
Change-Id: I2321e83e2939d21836ba1df335b2e97366594076
  • Loading branch information
Abseil Team authored and copybara-github committed Jan 4, 2025
1 parent bdc9a7b commit 51b7426
Show file tree
Hide file tree
Showing 6 changed files with 421 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMake/AbseilDll.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ set(ABSL_INTERNAL_DLL_FILES
"log/internal/proto.cc"
"log/internal/strip.h"
"log/internal/structured.h"
"log/internal/structured_proto.cc"
"log/internal/structured_proto.h"
"log/internal/vlog_config.cc"
"log/internal/vlog_config.h"
"log/internal/voidify.h"
Expand Down
38 changes: 38 additions & 0 deletions absl/log/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,44 @@ absl_cc_library(
absl::strings
)

absl_cc_library(
NAME
log_internal_structured_proto
SRCS
"internal/structured_proto.cc"
HDRS
"internal/structured_proto.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::log_internal_proto
absl::config
absl::span
absl::strings
absl::variant
PUBLIC
)

absl_cc_test(
NAME
log_internal_structured_proto_test
SRCS
"internal/structured_proto_test.cc"
COPTS
${ABSL_TEST_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::config
absl::log_internal_structured_proto
absl::span
absl::string_view
absl::utility
GTest::gmock_main
)

absl_cc_library(
NAME
log_structured
Expand Down
39 changes: 39 additions & 0 deletions absl/log/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ package(

licenses(["notice"])

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

cc_library(
name = "check_impl",
hdrs = ["check_impl.h"],
Expand Down Expand Up @@ -288,6 +295,38 @@ cc_library(
],
)

cc_library(
name = "structured_proto",
srcs = ["structured_proto.cc"],
hdrs = ["structured_proto.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
":structured_proto_users",
],
deps = [
":proto",
"//absl/base:config",
"//absl/strings",
"//absl/types:span",
"//absl/types:variant",
],
)

cc_test(
name = "structured_proto_test",
srcs = ["structured_proto_test.cc"],
deps = [
":structured_proto",
"//absl/base:config",
"//absl/strings:string_view",
"//absl/types:span",
"//absl/utility",
"@googletest//:gtest",
"@googletest//:gtest_main",
],
)

cc_library(
name = "test_actions",
testonly = True,
Expand Down
115 changes: 115 additions & 0 deletions absl/log/internal/structured_proto.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//
// Copyright 2024 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "absl/log/internal/structured_proto.h"

#include <cstdint>

#include "absl/base/config.h"
#include "absl/log/internal/proto.h"
#include "absl/types/span.h"
#include "absl/types/variant.h"

namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {

namespace {

// Handles protobuf-encoding a type contained inside
// `StructuredProtoField::Varint`.
struct VarintEncoderVisitor final {
template <typename T>
bool operator()(T value) const {
return EncodeVarint(field_number, value, &buf);
}

uint64_t field_number;
absl::Span<char>& buf;
};

// Handles protobuf-encoding a type contained inside
// `StructuredProtoField::I64`.
struct I64EncoderVisitor final {
bool operator()(uint64_t value) const {
return Encode64Bit(field_number, value, &buf);
}

bool operator()(int64_t value) const {
return Encode64Bit(field_number, value, &buf);
}

bool operator()(double value) const {
return EncodeDouble(field_number, value, &buf);
}

uint64_t field_number;
absl::Span<char>& buf;
};

// Handles protobuf-encoding a type contained inside
// `StructuredProtoField::I32`.
struct I32EncoderVisitor final {
bool operator()(uint32_t value) const {
return Encode32Bit(field_number, value, &buf);
}

bool operator()(int32_t value) const {
return Encode32Bit(field_number, value, &buf);
}

bool operator()(float value) const {
return EncodeFloat(field_number, value, &buf);
}

uint64_t field_number;
absl::Span<char>& buf;
};

// Handles protobuf-encoding a type contained inside `StructuredProtoField`.
struct EncoderVisitor final {
bool operator()(StructuredProtoField::Varint varint) {
return absl::visit(VarintEncoderVisitor{field_number, buf}, varint);
}

bool operator()(StructuredProtoField::I64 i64) {
return absl::visit(I64EncoderVisitor{field_number, buf}, i64);
}

bool operator()(StructuredProtoField::LengthDelimited length_delimited) {
// No need for a visitor, since `StructuredProtoField::LengthDelimited` is
// just `absl::Span<const char>`.
return EncodeBytes(field_number, length_delimited, &buf);
}

bool operator()(StructuredProtoField::I32 i32) {
return absl::visit(I32EncoderVisitor{field_number, buf}, i32);
}

uint64_t field_number;
absl::Span<char>& buf;
};

} // namespace

bool EncodeStructuredProtoField(StructuredProtoField field,
absl::Span<char>& buf) {
return absl::visit(EncoderVisitor{field.field_number, buf}, field.value);
}

} // namespace log_internal

ABSL_NAMESPACE_END
} // namespace absl
107 changes: 107 additions & 0 deletions absl/log/internal/structured_proto.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright 2024 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: log/internal/structured_proto.h
// -----------------------------------------------------------------------------

#ifndef ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_
#define ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_

#include <cstddef>
#include <cstdint>

#include "absl/base/config.h"
#include "absl/log/internal/proto.h"
#include "absl/types/span.h"
#include "absl/types/variant.h"

namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {

// Sum type holding a single valid protobuf field suitable for encoding.
struct StructuredProtoField final {
// Numeric type encoded with varint encoding:
// https://protobuf.dev/programming-guides/encoding/#varints
using Varint = absl::variant<uint64_t, int64_t, uint32_t, int32_t, bool>;

// Fixed-length 64-bit integer encoding:
// https://protobuf.dev/programming-guides/encoding/#non-varints
using I64 = absl::variant<uint64_t, int64_t, double>;

// Length-delimited record type (string, sub-message):
// https://protobuf.dev/programming-guides/encoding/#length-types
using LengthDelimited = absl::Span<const char>;

// Fixed-length 32-bit integer encoding:
// https://protobuf.dev/programming-guides/encoding/#non-varints
using I32 = absl::variant<uint32_t, int32_t, float>;

// Valid record type:
// https://protobuf.dev/programming-guides/encoding/#structure
using Value = absl::variant<Varint, I64, LengthDelimited, I32>;

// Field number for the protobuf value.
uint64_t field_number;

// Value to encode.
Value value;
};

// Estimates the number of bytes needed to encode `field` using
// protobuf encoding.
//
// The returned value might be larger than the actual number of bytes needed.
inline size_t BufferSizeForStructuredProtoField(StructuredProtoField field) {
// Visitor to estimate the number of bytes of one of the types contained
// inside `StructuredProtoField`.
struct BufferSizeVisitor final {
size_t operator()(StructuredProtoField::Varint /*unused*/) {
return BufferSizeFor(field_number, WireType::kVarint);
}

size_t operator()(StructuredProtoField::I64 /*unused*/) {
return BufferSizeFor(field_number, WireType::k64Bit);
}

size_t operator()(StructuredProtoField::LengthDelimited length_delimited) {
return BufferSizeFor(field_number, WireType::kLengthDelimited) +
length_delimited.size();
}

size_t operator()(StructuredProtoField::I32 /*unused*/) {
return BufferSizeFor(field_number, WireType::k32Bit);
}

uint64_t field_number;
};

return absl::visit(BufferSizeVisitor{field.field_number}, field.value);
}

// Encodes `field` into `buf` using protobuf encoding.
//
// On success, returns `true` and advances `buf` to the end of
// the bytes consumed.
//
// On failure (if `buf` was too small), returns `false`.
bool EncodeStructuredProtoField(StructuredProtoField field,
absl::Span<char>& buf);

} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_
Loading

0 comments on commit 51b7426

Please sign in to comment.