Skip to content

Commit fe9130c

Browse files
author
mvkab
committed
feat grpc: publish logging functions for google::protobuf::Message and grpc::Status
commit_hash:622fdaa5419b3e8e551175cab67b6867ff9420ff
1 parent af2442f commit fe9130c

File tree

15 files changed

+360
-102
lines changed

15 files changed

+360
-102
lines changed

.mapping.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2202,6 +2202,7 @@
22022202
"grpc/include/userver/ugrpc/impl/statistics_storage.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/statistics_storage.hpp",
22032203
"grpc/include/userver/ugrpc/impl/to_string.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/to_string.hpp",
22042204
"grpc/include/userver/ugrpc/proto_json.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/proto_json.hpp",
2205+
"grpc/include/userver/ugrpc/protobuf_logging.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/protobuf_logging.hpp",
22052206
"grpc/include/userver/ugrpc/protobuf_visit.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/protobuf_visit.hpp",
22062207
"grpc/include/userver/ugrpc/server/call_context.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/server/call_context.hpp",
22072208
"grpc/include/userver/ugrpc/server/component_list.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/server/component_list.hpp",
@@ -2324,8 +2325,6 @@
23242325
"grpc/src/ugrpc/impl/logging.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/logging.cpp",
23252326
"grpc/src/ugrpc/impl/logging.hpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/logging.hpp",
23262327
"grpc/src/ugrpc/impl/protobuf_collector.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/protobuf_collector.cpp",
2327-
"grpc/src/ugrpc/impl/protobuf_utils.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/protobuf_utils.cpp",
2328-
"grpc/src/ugrpc/impl/protobuf_utils.hpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/protobuf_utils.hpp",
23292328
"grpc/src/ugrpc/impl/queue_runner.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/queue_runner.cpp",
23302329
"grpc/src/ugrpc/impl/rpc_metadata.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/rpc_metadata.cpp",
23312330
"grpc/src/ugrpc/impl/rpc_metadata.hpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/rpc_metadata.hpp",
@@ -2334,6 +2333,7 @@
23342333
"grpc/src/ugrpc/impl/statistics_scope.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/statistics_scope.cpp",
23352334
"grpc/src/ugrpc/impl/statistics_storage.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/statistics_storage.cpp",
23362335
"grpc/src/ugrpc/proto_json.cpp":"taxi/uservices/userver/grpc/src/ugrpc/proto_json.cpp",
2336+
"grpc/src/ugrpc/protobuf_logging.cpp":"taxi/uservices/userver/grpc/src/ugrpc/protobuf_logging.cpp",
23372337
"grpc/src/ugrpc/protobuf_visit.cpp":"taxi/uservices/userver/grpc/src/ugrpc/protobuf_visit.cpp",
23382338
"grpc/src/ugrpc/server/call_context.cpp":"taxi/uservices/userver/grpc/src/ugrpc/server/call_context.cpp",
23392339
"grpc/src/ugrpc/server/component_list.cpp":"taxi/uservices/userver/grpc/src/ugrpc/server/component_list.cpp",
@@ -2403,6 +2403,7 @@
24032403
"grpc/tests/metadata_test.cpp":"taxi/uservices/userver/grpc/tests/metadata_test.cpp",
24042404
"grpc/tests/proto_json.cpp":"taxi/uservices/userver/grpc/tests/proto_json.cpp",
24052405
"grpc/tests/protobuf_collector_test.cpp":"taxi/uservices/userver/grpc/tests/protobuf_collector_test.cpp",
2406+
"grpc/tests/protobuf_logging_test.cpp":"taxi/uservices/userver/grpc/tests/protobuf_logging_test.cpp",
24062407
"grpc/tests/protobuf_utils_test.cpp":"taxi/uservices/userver/grpc/tests/protobuf_utils_test.cpp",
24072408
"grpc/tests/protobuf_visit_test.cpp":"taxi/uservices/userver/grpc/tests/protobuf_visit_test.cpp",
24082409
"grpc/tests/retry_test.cpp":"taxi/uservices/userver/grpc/tests/retry_test.cpp",

grpc/benchmarks/logging.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
#include <benchmark/benchmark.h>
22

3+
#include <userver/ugrpc/protobuf_logging.hpp>
34
#include <userver/utils/log.hpp>
45

5-
#include <ugrpc/impl/protobuf_utils.hpp>
6-
76
#include <tests/logging.pb.h>
87

98
USERVER_NAMESPACE_BEGIN
@@ -53,7 +52,7 @@ void BenchCustomLimit(benchmark::State& state) {
5352
// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
5453
for (auto _ : state) {
5554
{
56-
auto log = impl::ToLimitedDebugString(kMessage, 1024);
55+
auto log = ugrpc::ToLimitedDebugString(kMessage, 1024);
5756
benchmark::DoNotOptimize(log);
5857
}
5958
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#pragma once
2+
3+
/// @file
4+
/// @brief Public API for protobuf logging utilities.
5+
6+
#include <fmt/format.h>
7+
#include <google/protobuf/message.h>
8+
#include <grpcpp/support/status.h>
9+
10+
USERVER_NAMESPACE_BEGIN
11+
12+
namespace ugrpc {
13+
14+
inline constexpr std::size_t kDefaultDebugStringLimit = 1024;
15+
16+
/// @brief Convert protobuf message to limited debug string for logging.
17+
///
18+
/// Differences from built-in `DebugString`:
19+
/// - Fields marked with `[debug_redact]` option are hidden (`DebugString` only does so since Protobuf v30).
20+
/// - When the character limit is reached, serialization stops immediately (`DebugString` still wastes CPU on
21+
/// serializing the entire message regardless).
22+
///
23+
/// @param message The protobuf message to convert.
24+
/// @param limit Maximum size of the resulting string.
25+
/// Avoid setting this to very large values as it may cause OOM (Out of Memory) issues.
26+
/// @returns String representation of the message, truncated if necessary.
27+
///
28+
/// @warning This is a debug representation of protobuf that is unstable and should only be used for diagnostics.
29+
/// The order of keys in maps is unstable; the format itself can change even within a single run.
30+
/// You CANNOT parse back from this debug text representation.
31+
/// You CANNOT use it for equality match with reference values in gtest.
32+
std::string ToLimitedDebugString(const google::protobuf::Message& message, std::size_t limit);
33+
34+
/// @brief Convert protobuf message to unlimited debug string for logging.
35+
///
36+
/// Differences from built-in `DebugString`:
37+
/// - Fields marked with `[debug_redact]` option are hidden (`DebugString` only does so since Protobuf v30).
38+
///
39+
/// @param message The protobuf message to convert.
40+
/// @returns String representation of the message.
41+
///
42+
/// @warning This is a debug representation of protobuf that is unstable and should only be used for diagnostics.
43+
/// The order of keys in maps is unstable; the format itself can change even within a single run.
44+
/// You CANNOT parse back from this debug text representation.
45+
/// You CANNOT use it for equality match with reference values in gtest.
46+
std::string ToUnlimitedDebugString(const google::protobuf::Message& message);
47+
48+
/// @brief Get error details from `grpc::Status` for logging with size limit.
49+
/// @param status The `grpc::Status` to extract details from.
50+
/// @param max_size Maximum size of the resulting string.
51+
/// Avoid setting this to very large values as it may cause OOM (Out of Memory) issues.
52+
/// @returns String representation of error details, truncated if necessary.
53+
///
54+
/// @warning This is a debug representation of protobuf that is unstable and should only be used for diagnostics.
55+
/// The order of keys in maps is unstable; the format itself can change even within a single run.
56+
/// You CANNOT parse back from this debug text representation.
57+
/// You CANNOT use it for equality match with reference values in gtest.
58+
std::string ToLimitedDebugString(const grpc::Status& status, std::size_t max_size = kDefaultDebugStringLimit);
59+
60+
/// @brief Get error details from `grpc::Status` for logging without size limit.
61+
/// @param status The `grpc::Status` to extract details from.
62+
/// @returns String representation of error details.
63+
///
64+
/// @warning This is a debug representation of protobuf that is unstable and should only be used for diagnostics.
65+
/// The order of keys in maps is unstable; the format itself can change even within a single run.
66+
/// You CANNOT parse back from this debug text representation.
67+
/// You CANNOT use it for equality match with reference values in gtest.
68+
std::string ToUnlimitedDebugString(const grpc::Status& status);
69+
70+
} // namespace ugrpc
71+
72+
USERVER_NAMESPACE_END
73+
74+
namespace fmt {
75+
76+
/// @brief `fmt::format` support for protobuf messages
77+
template <typename T>
78+
struct formatter<T, typename std::enable_if_t<std::is_base_of_v<google::protobuf::Message, std::decay_t<T>>, char>> {
79+
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
80+
81+
template <typename FormatContext>
82+
auto format(const T& message, FormatContext& ctx) const {
83+
return fmt::format_to(
84+
ctx.out(),
85+
"{}",
86+
USERVER_NAMESPACE::ugrpc::ToLimitedDebugString(message, USERVER_NAMESPACE::ugrpc::kDefaultDebugStringLimit)
87+
);
88+
}
89+
};
90+
91+
} // namespace fmt

grpc/src/ugrpc/client/middlewares/log/middleware.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <userver/logging/level.hpp>
44
#include <userver/logging/log_extra.hpp>
55
#include <userver/tracing/tags.hpp>
6+
#include <userver/ugrpc/protobuf_logging.hpp>
67
#include <userver/ugrpc/status_codes.hpp>
78

89
#include <ugrpc/impl/logging.hpp>
@@ -17,7 +18,7 @@ std::string GetMessageForLogging(const google::protobuf::Message& message, const
1718
if (!logging::ShouldLog(settings.msg_log_level)) {
1819
return "";
1920
}
20-
return ugrpc::impl::GetMessageForLogging(message, settings.max_msg_size);
21+
return ugrpc::ToLimitedDebugString(message, settings.max_msg_size);
2122
}
2223

2324
class SpanLogger {
@@ -91,7 +92,7 @@ void Middleware::PostFinish(MiddlewareCallContext& context, const grpc::Status&
9192
logger.Log(settings_.msg_log_level, "gRPC response stream finished", logging::LogExtra{});
9293
}
9394
} else {
94-
auto error_details = ugrpc::impl::GetErrorDetailsForLogging(status);
95+
auto error_details = ugrpc::ToUnlimitedDebugString(status);
9596
logging::LogExtra extra{
9697
{ugrpc::impl::kTypeTag, "error_status"},
9798
{ugrpc::impl::kCodeTag, ugrpc::ToString(status.error_code())},

grpc/src/ugrpc/impl/logging.cpp

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
11
#include <ugrpc/impl/logging.hpp>
22

3-
#include <fmt/format.h>
4-
5-
#include <userver/logging/log.hpp>
6-
7-
#include <userver/ugrpc/status_codes.hpp>
8-
#include <userver/ugrpc/status_utils.hpp>
9-
10-
#include <ugrpc/impl/protobuf_utils.hpp>
11-
123
USERVER_NAMESPACE_BEGIN
134

145
namespace ugrpc::impl {
@@ -19,28 +10,6 @@ const std::string kComponentTag{"grpc_component"};
1910
const std::string kMessageMarshalledLenTag{"grpc_message_marshalled_len"};
2011
const std::string kTypeTag{"grpc_type"};
2112

22-
std::string GetMessageForLogging(const google::protobuf::Message& message, std::size_t max_size) {
23-
return ugrpc::impl::ToLimitedDebugString(message, max_size);
24-
}
25-
26-
std::string GetErrorDetailsForLogging(const grpc::Status& status) {
27-
if (status.ok()) {
28-
return "";
29-
}
30-
31-
const auto gstatus = ugrpc::ToGoogleRpcStatus(status);
32-
return gstatus.has_value()
33-
? fmt::format(
34-
"code: {}, error message: {}\nerror details:\n{}",
35-
ugrpc::ToString(status.error_code()),
36-
status.error_message(),
37-
ugrpc::GetGStatusLimitedMessage(*gstatus)
38-
)
39-
: fmt::format(
40-
"code: {}, error message: {}", ugrpc::ToString(status.error_code()), status.error_message()
41-
);
42-
}
43-
4413
} // namespace ugrpc::impl
4514

4615
USERVER_NAMESPACE_END

grpc/src/ugrpc/impl/logging.hpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
#pragma once
2-
32
#include <string>
43

5-
#include <google/protobuf/message.h>
6-
#include <grpcpp/support/status.h>
7-
84
USERVER_NAMESPACE_BEGIN
95

106
namespace ugrpc::impl {
@@ -15,10 +11,6 @@ extern const std::string kComponentTag;
1511
extern const std::string kMessageMarshalledLenTag;
1612
extern const std::string kTypeTag;
1713

18-
std::string GetMessageForLogging(const google::protobuf::Message& message, std::size_t max_size);
19-
20-
std::string GetErrorDetailsForLogging(const grpc::Status& status);
21-
2214
} // namespace ugrpc::impl
2315

2416
USERVER_NAMESPACE_END

grpc/src/ugrpc/impl/protobuf_utils.hpp

Lines changed: 0 additions & 13 deletions
This file was deleted.

grpc/src/ugrpc/impl/protobuf_utils.cpp renamed to grpc/src/ugrpc/protobuf_logging.cpp

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1-
#include <ugrpc/impl/protobuf_utils.hpp>
2-
3-
#include <exception>
4-
#include <memory>
5-
#include <unordered_set>
1+
#include <userver/ugrpc/protobuf_logging.hpp>
62

73
#include <google/protobuf/descriptor.pb.h>
8-
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
94
#include <google/protobuf/text_format.h>
10-
#include <grpcpp/support/config.h>
115
#include <boost/container/small_vector.hpp>
126

137
#include <userver/compiler/thread_local.hpp>
8+
#include <userver/ugrpc/status_codes.hpp>
9+
#include <userver/ugrpc/status_utils.hpp>
1410
#include <userver/utils/assert.hpp>
1511
#include <userver/utils/numeric_cast.hpp>
1612

@@ -189,31 +185,89 @@ compiler::ThreadLocal kDebugStringPrinter = [] { return DebugStringPrinter{}; };
189185

190186
} // namespace
191187

188+
void Print(const google::protobuf::Message& message, google::protobuf::io::ZeroCopyOutputStream& output_stream) {
189+
auto printer = kDebugStringPrinter.Use();
190+
printer->RegisterDebugRedactPrinters(*message.GetDescriptor());
191+
printer->Print(message, output_stream);
192+
}
193+
194+
} // namespace ugrpc::impl
195+
196+
namespace ugrpc {
197+
192198
std::string ToLimitedDebugString(const google::protobuf::Message& message, std::size_t limit) {
193199
boost::container::small_vector<char, 1024> output_buffer{limit, boost::container::default_init};
194200
google::protobuf::io::ArrayOutputStream output_stream{output_buffer.data(), utils::numeric_cast<int>(limit)};
195201

196-
auto printer = kDebugStringPrinter.Use();
202+
auto printer = impl::kDebugStringPrinter.Use();
197203
printer->RegisterDebugRedactPrinters(*message.GetDescriptor());
198204

199205
#if defined(ARCADIA_ROOT) || GOOGLE_PROTOBUF_VERSION >= 6031002
200206
// Throw `LimitReachedException` on limit reached to stop printing immediately, otherwise TextFormat will continue
201207
// to walk the whole message and apply noop printing.
202-
LimitingOutputStream limiting_output_stream{output_stream};
208+
impl::LimitingOutputStream limiting_output_stream{output_stream};
203209
try {
204-
printer->Print(message, limiting_output_stream);
205-
} catch (const LimitingOutputStream::LimitReachedException& /*ex*/) {
210+
impl::Print(message, limiting_output_stream);
211+
} catch (const impl::LimitingOutputStream::LimitReachedException& /*ex*/) {
206212
// Buffer limit has been reached.
207213
}
208214
#else
209215
// For old protobuf, we cannot apply hard limits when printing messages, because its TextFormat is not
210216
// exception-safe. https://github.com/protocolbuffers/protobuf/commit/be875d0aaf37dbe6948717ea621278e75e89c9c7
211-
printer->Print(message, output_stream);
217+
impl::Print(message, output_stream);
212218
#endif
219+
std::string returned_str = std::string{output_buffer.data(), static_cast<std::size_t>(output_stream.ByteCount())};
220+
if (returned_str.empty() && limit >= 7) return "<EMPTY>";
221+
return returned_str;
222+
}
213223

214-
return std::string{output_buffer.data(), static_cast<std::size_t>(output_stream.ByteCount())};
224+
std::string ToUnlimitedDebugString(const google::protobuf::Message& message) {
225+
grpc::string result;
226+
google::protobuf::io::StringOutputStream output_stream(&result);
227+
impl::Print(message, output_stream);
228+
std::string returned_str = std::string(result);
229+
if (returned_str.empty()) return "<EMPTY>";
230+
return returned_str;
215231
}
216232

217-
} // namespace ugrpc::impl
233+
std::string ToLimitedDebugString(const grpc::Status& status, std::size_t max_size) {
234+
if (status.ok()) {
235+
return "OK";
236+
}
237+
238+
const auto gstatus = ugrpc::ToGoogleRpcStatus(status);
239+
if (gstatus.has_value()) {
240+
const std::string details_string = ugrpc::ToLimitedDebugString(*gstatus, max_size);
241+
return fmt::format(
242+
"code: {}, error message: {}\nerror details:\n{}",
243+
ugrpc::ToString(status.error_code()),
244+
status.error_message(),
245+
details_string
246+
);
247+
} else {
248+
return fmt::format("code: {}, error message: {}", ugrpc::ToString(status.error_code()), status.error_message());
249+
}
250+
}
251+
252+
std::string ToUnlimitedDebugString(const grpc::Status& status) {
253+
if (status.ok()) {
254+
return "OK";
255+
}
256+
257+
const auto gstatus = ugrpc::ToGoogleRpcStatus(status);
258+
if (gstatus.has_value()) {
259+
const std::string details_string = ugrpc::ToUnlimitedDebugString(*gstatus);
260+
return fmt::format(
261+
"code: {}, error message: {}\nerror details:\n{}",
262+
ugrpc::ToString(status.error_code()),
263+
status.error_message(),
264+
details_string
265+
);
266+
} else {
267+
return fmt::format("code: {}, error message: {}", ugrpc::ToString(status.error_code()), status.error_message());
268+
}
269+
}
270+
271+
} // namespace ugrpc
218272

219273
USERVER_NAMESPACE_END

grpc/src/ugrpc/protobuf_visit.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
#include <userver/utils/assert.hpp>
88
#include <userver/utils/impl/internal_tag.hpp>
99

10-
#include <ugrpc/impl/protobuf_utils.hpp>
1110
#include <userver/ugrpc/impl/protobuf_collector.hpp>
12-
#include <userver/ugrpc/protobuf_visit.hpp>
11+
#include <userver/ugrpc/protobuf_logging.hpp>
1312

1413
USERVER_NAMESPACE_BEGIN
1514

0 commit comments

Comments
 (0)