Skip to content

Commit 69b5bd1

Browse files
Abseil Teamcopybara-github
authored andcommitted
New internal-use-only classes AsStructuredLiteralImpl and AsStructuredValueImpl
PiperOrigin-RevId: 714130164 Change-Id: Ib76de9efeecf5344ed67ca27680937971d9a84e3
1 parent 81d48b3 commit 69b5bd1

File tree

5 files changed

+190
-2
lines changed

5 files changed

+190
-2
lines changed

absl/log/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ absl_cc_library(
206206
absl::log_internal_proto
207207
absl::log_internal_log_sink_set
208208
absl::log_internal_nullguard
209+
absl::log_internal_structured_proto
209210
absl::log_globals
210211
absl::log_entry
211212
absl::log_severity
@@ -666,9 +667,11 @@ absl_cc_library(
666667
LINKOPTS
667668
${ABSL_DEFAULT_LINKOPTS}
668669
DEPS
670+
absl::any_invocable
669671
absl::config
670672
absl::core_headers
671673
absl::log_internal_message
674+
absl::log_internal_structured_proto
672675
absl::strings
673676
)
674677

absl/log/internal/BUILD.bazel

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ load(
2323

2424
package(
2525
default_visibility = [
26-
"//absl/log:__pkg__",
26+
":internal_users",
2727
],
2828
features = [
2929
"header_modules",
@@ -34,6 +34,13 @@ package(
3434

3535
licenses(["notice"])
3636

37+
package_group(
38+
name = "internal_users",
39+
packages = [
40+
"//absl/log",
41+
],
42+
)
43+
3744
package_group(
3845
name = "structured_proto_users",
3946
packages = [
@@ -183,6 +190,7 @@ cc_library(
183190
":log_sink_set",
184191
":nullguard",
185192
":proto",
193+
":structured_proto",
186194
"//absl/base",
187195
"//absl/base:config",
188196
"//absl/base:core_headers",
@@ -287,10 +295,16 @@ cc_library(
287295
hdrs = ["structured.h"],
288296
copts = ABSL_DEFAULT_COPTS,
289297
linkopts = ABSL_DEFAULT_LINKOPTS,
298+
visibility = [
299+
":internal_users",
300+
":structured_proto_users",
301+
],
290302
deps = [
291303
":log_message",
304+
":structured_proto",
292305
"//absl/base:config",
293306
"//absl/base:core_headers",
307+
"//absl/functional:any_invocable",
294308
"//absl/strings",
295309
],
296310
)
@@ -355,6 +369,10 @@ cc_library(
355369
hdrs = ["test_helpers.h"],
356370
copts = ABSL_DEFAULT_COPTS,
357371
linkopts = ABSL_DEFAULT_LINKOPTS,
372+
visibility = [
373+
":internal_users",
374+
":structured_proto_users",
375+
],
358376
deps = [
359377
":globals",
360378
"//absl/base:config",
@@ -372,6 +390,10 @@ cc_library(
372390
hdrs = ["test_matchers.h"],
373391
copts = ABSL_DEFAULT_COPTS,
374392
linkopts = ABSL_DEFAULT_LINKOPTS,
393+
visibility = [
394+
":internal_users",
395+
":structured_proto_users",
396+
],
375397
deps = [
376398
":test_helpers",
377399
"//absl/base:config",
@@ -402,6 +424,10 @@ cc_library(
402424
hdrs = ["proto.h"],
403425
copts = ABSL_DEFAULT_COPTS,
404426
linkopts = ABSL_DEFAULT_LINKOPTS,
427+
visibility = [
428+
":internal_users",
429+
":structured_proto_users",
430+
],
405431
deps = [
406432
"//absl/base",
407433
"//absl/base:config",

absl/log/internal/log_message.cc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "absl/log/internal/log_format.h"
4949
#include "absl/log/internal/log_sink_set.h"
5050
#include "absl/log/internal/proto.h"
51+
#include "absl/log/internal/structured_proto.h"
5152
#include "absl/log/log_entry.h"
5253
#include "absl/log/log_sink.h"
5354
#include "absl/log/log_sink_registry.h"
@@ -632,6 +633,47 @@ template void LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>(
632633
template void LogMessage::CopyToEncodedBuffer<
633634
LogMessage::StringType::kNotLiteral>(char ch, size_t num);
634635

636+
template void LogMessage::CopyToEncodedBufferWithStructuredProtoField<
637+
LogMessage::StringType::kLiteral>(StructuredProtoField field,
638+
absl::string_view str);
639+
template void LogMessage::CopyToEncodedBufferWithStructuredProtoField<
640+
LogMessage::StringType::kNotLiteral>(StructuredProtoField field,
641+
absl::string_view str);
642+
643+
template <LogMessage::StringType str_type>
644+
void LogMessage::CopyToEncodedBufferWithStructuredProtoField(
645+
StructuredProtoField field, absl::string_view str) {
646+
auto encoded_remaining_copy = data_->encoded_remaining();
647+
size_t encoded_field_size = BufferSizeForStructuredProtoField(field);
648+
constexpr uint8_t tag_value = str_type == StringType::kLiteral
649+
? ValueTag::kStringLiteral
650+
: ValueTag::kString;
651+
auto start = EncodeMessageStart(
652+
EventTag::kValue,
653+
encoded_field_size +
654+
BufferSizeFor(tag_value, WireType::kLengthDelimited) + str.size(),
655+
&encoded_remaining_copy);
656+
657+
// Write the encoded proto field.
658+
if (!EncodeStructuredProtoField(field, encoded_remaining_copy)) {
659+
// The header / field will not fit; zero `encoded_remaining()` so we
660+
// don't write anything else later.
661+
data_->encoded_remaining().remove_suffix(data_->encoded_remaining().size());
662+
return;
663+
}
664+
665+
// Write the string, truncating if necessary.
666+
if (!EncodeStringTruncate(ValueTag::kString, str, &encoded_remaining_copy)) {
667+
// The length of the string itself did not fit; zero `encoded_remaining()`
668+
// so the value is not encoded at all.
669+
data_->encoded_remaining().remove_suffix(data_->encoded_remaining().size());
670+
return;
671+
}
672+
673+
EncodeMessageLength(start, &encoded_remaining_copy);
674+
data_->encoded_remaining() = encoded_remaining_copy;
675+
}
676+
635677
// We intentionally don't return from these destructors. Disable MSVC's warning
636678
// about the destructor never returning as we do so intentionally here.
637679
#if defined(_MSC_VER) && !defined(__clang__)

absl/log/internal/log_message.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "absl/base/log_severity.h"
4242
#include "absl/base/nullability.h"
4343
#include "absl/log/internal/nullguard.h"
44+
#include "absl/log/internal/structured_proto.h"
4445
#include "absl/log/log_entry.h"
4546
#include "absl/log/log_sink.h"
4647
#include "absl/strings/has_absl_stringify.h"
@@ -52,6 +53,8 @@ ABSL_NAMESPACE_BEGIN
5253
namespace log_internal {
5354
constexpr int kLogMessageBufferSize = 15000;
5455

56+
enum class StructuredStringType;
57+
5558
class LogMessage {
5659
public:
5760
struct InfoTag {};
@@ -217,6 +220,10 @@ class LogMessage {
217220
struct LogMessageData; // Opaque type containing message state
218221
friend class AsLiteralImpl;
219222
friend class StringifySink;
223+
template <StructuredStringType str_type>
224+
friend class AsStructuredStringTypeImpl;
225+
template <typename T>
226+
friend class AsStructuredValueImpl;
220227

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

257+
// Copies `field` to the encoded buffer, then appends `str` after it
258+
// (truncating `str` if necessary to fit).
259+
template <StringType str_type>
260+
void CopyToEncodedBufferWithStructuredProtoField(StructuredProtoField field,
261+
absl::string_view str)
262+
ABSL_ATTRIBUTE_NOINLINE;
263+
250264
// Returns `true` if the message is fatal or enabled debug-fatal.
251265
bool IsFatal() const;
252266

absl/log/internal/structured.h

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@
2020
#define ABSL_LOG_INTERNAL_STRUCTURED_H_
2121

2222
#include <ostream>
23+
#include <string>
2324

24-
#include "absl/base/config.h"
2525
#include "absl/base/attributes.h"
26+
#include "absl/base/config.h"
27+
#include "absl/functional/any_invocable.h"
2628
#include "absl/log/internal/log_message.h"
29+
#include "absl/log/internal/structured_proto.h"
30+
#include "absl/strings/str_cat.h"
2731
#include "absl/strings/string_view.h"
2832

2933
namespace absl {
@@ -54,6 +58,105 @@ class ABSL_MUST_USE_RESULT AsLiteralImpl final {
5458
}
5559
};
5660

61+
enum class StructuredStringType {
62+
kLiteral,
63+
kNotLiteral,
64+
};
65+
66+
// Structured log data for a string and associated structured proto field,
67+
// both of which must outlive this object.
68+
template <StructuredStringType str_type>
69+
class ABSL_MUST_USE_RESULT AsStructuredStringTypeImpl final {
70+
public:
71+
constexpr AsStructuredStringTypeImpl(
72+
absl::string_view str ABSL_ATTRIBUTE_LIFETIME_BOUND,
73+
StructuredProtoField field ABSL_ATTRIBUTE_LIFETIME_BOUND)
74+
: str_(str), field_(field) {}
75+
76+
private:
77+
absl::string_view str_;
78+
StructuredProtoField field_;
79+
80+
friend std::ostream& operator<<(std::ostream& os,
81+
const AsStructuredStringTypeImpl& impl) {
82+
return os << impl.str_;
83+
}
84+
void AddToMessage(LogMessage& m) const {
85+
if (str_type == StructuredStringType::kLiteral) {
86+
return m.CopyToEncodedBufferWithStructuredProtoField<
87+
log_internal::LogMessage::StringType::kLiteral>(field_, str_);
88+
} else {
89+
return m.CopyToEncodedBufferWithStructuredProtoField<
90+
log_internal::LogMessage::StringType::kNotLiteral>(field_, str_);
91+
}
92+
}
93+
friend LogMessage& operator<<(LogMessage& m,
94+
const AsStructuredStringTypeImpl& impl) {
95+
impl.AddToMessage(m);
96+
return m;
97+
}
98+
};
99+
100+
using AsStructuredLiteralImpl =
101+
AsStructuredStringTypeImpl<StructuredStringType::kLiteral>;
102+
using AsStructuredNotLiteralImpl =
103+
AsStructuredStringTypeImpl<StructuredStringType::kNotLiteral>;
104+
105+
// Structured log data for a stringifyable type T and associated structured
106+
// proto field, both of which must outlive this object.
107+
template <typename T>
108+
class ABSL_MUST_USE_RESULT AsStructuredValueImpl final {
109+
public:
110+
using ValueFormatter = absl::AnyInvocable<std::string(T) const>;
111+
112+
constexpr AsStructuredValueImpl(
113+
T value ABSL_ATTRIBUTE_LIFETIME_BOUND,
114+
StructuredProtoField field ABSL_ATTRIBUTE_LIFETIME_BOUND,
115+
ValueFormatter value_formatter =
116+
[](T value) { return absl::StrCat(value); })
117+
: value_(value),
118+
field_(field),
119+
value_formatter_(std::move(value_formatter)) {}
120+
121+
private:
122+
T value_;
123+
StructuredProtoField field_;
124+
ValueFormatter value_formatter_;
125+
126+
friend std::ostream& operator<<(std::ostream& os,
127+
const AsStructuredValueImpl& impl) {
128+
return os << impl.value_formatter_(impl.value_);
129+
}
130+
void AddToMessage(LogMessage& m) const {
131+
m.CopyToEncodedBufferWithStructuredProtoField<
132+
log_internal::LogMessage::StringType::kNotLiteral>(
133+
field_, value_formatter_(value_));
134+
}
135+
friend LogMessage& operator<<(LogMessage& m,
136+
const AsStructuredValueImpl& impl) {
137+
impl.AddToMessage(m);
138+
return m;
139+
}
140+
};
141+
142+
#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
143+
144+
// Template deduction guide so `AsStructuredValueImpl(42, data)` works
145+
// without specifying the template type.
146+
template <typename T>
147+
AsStructuredValueImpl(T value, StructuredProtoField field)
148+
-> AsStructuredValueImpl<T>;
149+
150+
// Template deduction guide so `AsStructuredValueImpl(42, data, formatter)`
151+
// works without specifying the template type.
152+
template <typename T>
153+
AsStructuredValueImpl(
154+
T value, StructuredProtoField field,
155+
typename AsStructuredValueImpl<T>::ValueFormatter value_formatter)
156+
-> AsStructuredValueImpl<T>;
157+
158+
#endif // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
159+
57160
} // namespace log_internal
58161
ABSL_NAMESPACE_END
59162
} // namespace absl

0 commit comments

Comments
 (0)