userver: userver/ugrpc/protobuf_logging.hpp Source File
Loading...
Searching...
No Matches
protobuf_logging.hpp
Go to the documentation of this file.
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
10USERVER_NAMESPACE_BEGIN
11
12namespace ugrpc {
13
14inline 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/// - Since Protobuf v35, when the character limit is reached serialization stops early instead of serializing the
21/// entire message (see the CPU warning below; `DebugString` always wastes CPU on serializing the entire message
22/// regardless).
23/// - When truncated, the string ends with `...(truncated)` marker to indicate that the output was cut off.
24///
25/// @param message The protobuf message to convert.
26/// @param limit Maximum size of the resulting string.
27/// Avoid setting this to very large values as it may cause OOM (Out of Memory) issues.
28/// @returns String representation of the message, truncated if necessary.
29///
30/// @warning The early-stop on reaching `limit` relies on the Protobuf `TextFormat` fix
31/// (https://github.com/protocolbuffers/protobuf/pull/26237), available since Protobuf v35. Before Protobuf v35 the
32/// @b entire message is serialized regardless of `limit`, and only then the result is truncated. For large messages
33/// this may consume a significant amount of CPU. If this serialization cost becomes a problem in the logging
34/// middleware, disable the middleware, see @ref scripts/docs/en/userver/grpc/middlewares_toggle.md
35///
36/// @warning This is a debug representation of protobuf that is unstable and should only be used for diagnostics.
37/// The order of keys in maps is unstable; the format itself can change even within a single run.
38/// You CANNOT parse back from this debug text representation.
39/// You CANNOT use it for equality match with reference values in gtest.
40std::string ToLimitedDebugString(const google::protobuf::Message& message, std::size_t limit);
41
42/// @brief Convert protobuf message to unlimited debug string for logging.
43///
44/// Differences from built-in `DebugString`:
45/// - Fields marked with `[debug_redact]` option are hidden (`DebugString` only does so since Protobuf v30).
46///
47/// @param message The protobuf message to convert.
48/// @returns String representation of the message.
49///
50/// @warning This is a debug representation of protobuf that is unstable and should only be used for diagnostics.
51/// The order of keys in maps is unstable; the format itself can change even within a single run.
52/// You CANNOT parse back from this debug text representation.
53/// You CANNOT use it for equality match with reference values in gtest.
54std::string ToUnlimitedDebugString(const google::protobuf::Message& message);
55
56/// @brief Get error details from `grpc::Status` for logging with size limit.
57/// @param status The `grpc::Status` to extract details from.
58/// @param max_size Maximum size of the error details part.
59/// Avoid setting this to very large values as it may cause OOM (Out of Memory) issues.
60/// @returns String representation of error details, formatted as "code: {code}, error message: {message}\nerror
61/// details:\n{details}". The error details part may be truncated if it exceeds max_size, in which case it ends with
62/// `...(truncated)` marker.
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.
68std::string ToLimitedDebugString(const grpc::Status& status, std::size_t max_size = kDefaultDebugStringLimit);
69
70/// @brief Get error details from `grpc::Status` for logging without size limit.
71/// @param status The `grpc::Status` to extract details from.
72/// @returns String representation of error details.
73///
74/// @warning This is a debug representation of protobuf that is unstable and should only be used for diagnostics.
75/// The order of keys in maps is unstable; the format itself can change even within a single run.
76/// You CANNOT parse back from this debug text representation.
77/// You CANNOT use it for equality match with reference values in gtest.
78std::string ToUnlimitedDebugString(const grpc::Status& status);
79
80} // namespace ugrpc
81
82USERVER_NAMESPACE_END
83
84namespace fmt {
85
86/// @brief `fmt::format` support for protobuf messages
87template <typename T>
88requires std::is_base_of_v<google::protobuf::Message, std::decay_t<T>>
89struct formatter<T> {
90 constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
91
92 template <typename FormatContext>
93 auto format(const T& message, FormatContext& ctx) const {
94 return fmt::format_to(
95 ctx.out(),
96 "{}",
97 USERVER_NAMESPACE::ugrpc::ToLimitedDebugString(message, USERVER_NAMESPACE::ugrpc::kDefaultDebugStringLimit)
98 );
99 }
100};
101
102} // namespace fmt