Skip to content

Commit d4e8362

Browse files
committed
feat: add debug spans for decoding requests
Closes: hyperium#1759
1 parent c783652 commit d4e8362

File tree

2 files changed

+64
-16
lines changed

2 files changed

+64
-16
lines changed

tonic/src/codec/compression.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,8 @@ impl CompressionEncoding {
160160
}
161161

162162
#[allow(missing_docs)]
163-
#[cfg(any(feature = "gzip", feature = "zstd"))]
164-
pub(crate) fn as_str(&self) -> &'static str {
165-
match self {
163+
pub(crate) const fn as_str(&self) -> &'static str {
164+
match *self {
166165
#[cfg(feature = "gzip")]
167166
CompressionEncoding::Gzip => "gzip",
168167
#[cfg(feature = "zstd")]
@@ -171,11 +170,11 @@ impl CompressionEncoding {
171170
}
172171

173172
#[cfg(any(feature = "gzip", feature = "zstd"))]
174-
pub(crate) fn into_header_value(self) -> http::HeaderValue {
173+
pub(crate) const fn into_header_value(self) -> http::HeaderValue {
175174
http::HeaderValue::from_static(self.as_str())
176175
}
177176

178-
pub(crate) fn encodings() -> &'static [Self] {
177+
pub(crate) const fn encodings() -> &'static [Self] {
179178
&[
180179
#[cfg(feature = "gzip")]
181180
CompressionEncoding::Gzip,

tonic/src/codec/decode.rs

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,47 @@ struct StreamingInner {
3535

3636
impl<T> Unpin for Streaming<T> {}
3737

38-
#[derive(Debug, Clone, Copy)]
38+
#[derive(Debug, Clone)]
3939
enum State {
40-
ReadHeader,
40+
ReadHeader {
41+
span: Option<tracing::Span>,
42+
},
4143
ReadBody {
44+
span: tracing::Span,
4245
compression: Option<CompressionEncoding>,
4346
len: usize,
4447
},
4548
Error,
4649
}
4750

51+
impl State {
52+
fn read_header() -> Self {
53+
Self::ReadHeader { span: None }
54+
}
55+
56+
fn read_body(compression: Option<CompressionEncoding>, len: usize) -> Self {
57+
let span = tracing::debug_span!(
58+
"read_body",
59+
compression = compression.map(|c| c.as_str()),
60+
compressed.bytes = compression.is_some().then_some(len),
61+
uncompressed.bytes = compression.is_none().then_some(len),
62+
);
63+
Self::ReadBody {
64+
span,
65+
compression,
66+
len,
67+
}
68+
}
69+
70+
fn span(&self) -> Option<&tracing::Span> {
71+
match self {
72+
Self::ReadHeader { span } => span.as_ref(),
73+
Self::ReadBody { span, .. } => Some(span),
74+
Self::Error => None,
75+
}
76+
}
77+
}
78+
4879
#[derive(Debug, PartialEq, Eq)]
4980
enum Direction {
5081
Request,
@@ -124,7 +155,7 @@ impl<T> Streaming<T> {
124155
.map_data(|mut buf| buf.copy_to_bytes(buf.remaining()))
125156
.map_err(|err| Status::map_error(err.into()))
126157
.boxed_unsync(),
127-
state: State::ReadHeader,
158+
state: State::read_header(),
128159
direction,
129160
buf: BytesMut::with_capacity(buffer_size),
130161
trailers: None,
@@ -141,7 +172,15 @@ impl StreamingInner {
141172
&mut self,
142173
buffer_settings: BufferSettings,
143174
) -> Result<Option<DecodeBuf<'_>>, Status> {
144-
if let State::ReadHeader = self.state {
175+
if let State::ReadHeader { span } = &mut self.state {
176+
let span = span.get_or_insert_with(|| {
177+
tracing::debug_span!(
178+
"read_header",
179+
compression = tracing::field::Empty,
180+
body.bytes = tracing::field::Empty,
181+
)
182+
});
183+
let _guard = span.enter();
145184
if self.buf.remaining() < HEADER_SIZE {
146185
return Ok(None);
147186
}
@@ -150,7 +189,8 @@ impl StreamingInner {
150189
0 => None,
151190
1 => {
152191
{
153-
if self.encoding.is_some() {
192+
if let Some(ce) = self.encoding {
193+
span.record("compression", ce.as_str());
154194
self.encoding
155195
} else {
156196
// https://grpc.github.io/grpc/core/md_doc_compression.html
@@ -176,6 +216,7 @@ impl StreamingInner {
176216
};
177217

178218
let len = self.buf.get_u32() as usize;
219+
span.record("body.bytes", len);
179220
let limit = self
180221
.max_message_size
181222
.unwrap_or(DEFAULT_MAX_RECV_MESSAGE_SIZE);
@@ -190,14 +231,19 @@ impl StreamingInner {
190231
}
191232

192233
self.buf.reserve(len);
234+
drop(_guard);
193235

194-
self.state = State::ReadBody {
195-
compression: compression_encoding,
196-
len,
197-
}
236+
self.state = State::read_body(compression_encoding, len)
198237
}
199238

200-
if let State::ReadBody { len, compression } = self.state {
239+
if let State::ReadBody {
240+
len,
241+
span,
242+
compression,
243+
} = &self.state
244+
{
245+
let (len, compression) = (*len, *compression);
246+
let _guard = span.enter();
201247
// if we haven't read enough of the message then return and keep
202248
// reading
203249
if self.buf.remaining() < len || self.buf.len() < len {
@@ -227,6 +273,7 @@ impl StreamingInner {
227273
return Err(Status::new(Code::Internal, message));
228274
}
229275
let decompressed_len = self.decompress_buf.len();
276+
span.record("uncompressed.bytes", decompressed_len);
230277
DecodeBuf::new(&mut self.decompress_buf, decompressed_len)
231278
} else {
232279
DecodeBuf::new(&mut self.buf, len)
@@ -240,13 +287,15 @@ impl StreamingInner {
240287

241288
// Returns Some(()) if data was found or None if the loop in `poll_next` should break
242289
fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Result<Option<()>, Status>> {
290+
let _guard = self.state.span().map(|s| s.enter());
243291
let chunk = match ready!(Pin::new(&mut self.body).poll_data(cx)) {
244292
Some(Ok(d)) => Some(d),
245293
Some(Err(status)) => {
246294
if self.direction == Direction::Request && status.code() == Code::Cancelled {
247295
return Poll::Ready(Ok(None));
248296
}
249297

298+
drop(_guard);
250299
let _ = std::mem::replace(&mut self.state, State::Error);
251300
debug!("decoder inner stream error: {:?}", status);
252301
return Poll::Ready(Err(status));
@@ -376,7 +425,7 @@ impl<T> Streaming<T> {
376425
match self.inner.decode_chunk(self.decoder.buffer_settings())? {
377426
Some(mut decode_buf) => match self.decoder.decode(&mut decode_buf)? {
378427
Some(msg) => {
379-
self.inner.state = State::ReadHeader;
428+
self.inner.state = State::read_header();
380429
Ok(Some(msg))
381430
}
382431
None => Ok(None),

0 commit comments

Comments
 (0)