start adding tracing spans to internals (#478)

We've adopted `tracing` for diagnostics, but currently, it is just being
used as a drop-in replacement for the `log` crate. Ideally, we would
want to start emitting more structured diagnostics, using `tracing`'s
`Span`s and structured key-value fields.

A lot of the logging in `h2` is already written in a style that imitates
the formatting of structured key-value logs, but as textual log
messages. Migrating the logs to structured `tracing` events therefore is
pretty easy to do. I've also started adding spans, mostly in the read
path.

Finally, I've updated the tests to use `tracing` rather than
`env_logger`. The tracing setup happens in a macro, so that a span for
each test with the test's name can be generated and entered. This will
make the test output easier to read if multiple tests are run
concurrently with `--nocapture`.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
This commit is contained in:
Eliza Weisman
2020-08-17 17:29:22 -07:00
committed by GitHub
parent d3c2bba18b
commit fc7f63f641
25 changed files with 363 additions and 257 deletions

View File

@@ -128,6 +128,7 @@ use std::task::{Context, Poll};
use std::time::Duration;
use std::{convert, fmt, io, mem};
use tokio::io::{AsyncRead, AsyncWrite};
use tracing_futures::{Instrument, Instrumented};
/// In progress HTTP/2.0 connection handshake future.
///
@@ -149,6 +150,8 @@ pub struct Handshake<T, B: Buf = Bytes> {
builder: Builder,
/// The current state of the handshake.
state: Handshaking<T, B>,
/// Span tracking the handshake
span: tracing::Span,
}
/// Accepts inbound HTTP/2.0 streams on a connection.
@@ -290,9 +293,9 @@ impl<B: Buf + fmt::Debug> fmt::Debug for SendPushedResponse<B> {
/// Stages of an in-progress handshake.
enum Handshaking<T, B: Buf> {
/// State 1. Connection is flushing pending SETTINGS frame.
Flushing(Flush<T, Prioritized<B>>),
Flushing(Instrumented<Flush<T, Prioritized<B>>>),
/// State 2. Connection is waiting for the client preface.
ReadingPreface(ReadPreface<T, Prioritized<B>>),
ReadingPreface(Instrumented<ReadPreface<T, Prioritized<B>>>),
/// Dummy state for `mem::replace`.
Empty,
}
@@ -359,6 +362,9 @@ where
B: Buf + 'static,
{
fn handshake2(io: T, builder: Builder) -> Handshake<T, B> {
let span = tracing::trace_span!("server_handshake", io = %std::any::type_name::<T>());
let entered = span.enter();
// Create the codec.
let mut codec = Codec::new(io);
@@ -378,7 +384,13 @@ where
// Create the handshake future.
let state = Handshaking::from(codec);
Handshake { builder, state }
drop(entered);
Handshake {
builder,
state,
span,
}
}
/// Accept the next incoming request on this connection.
@@ -1179,7 +1191,9 @@ where
type Output = Result<Connection<T, B>, crate::Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
tracing::trace!("Handshake::poll(); state={:?};", self.state);
let span = self.span.clone(); // XXX(eliza): T_T
let _e = span.enter();
tracing::trace!(state = ?self.state);
use crate::server::Handshaking::*;
self.state = if let Flushing(ref mut flush) = self.state {
@@ -1188,11 +1202,11 @@ where
// for the client preface.
let codec = match Pin::new(flush).poll(cx)? {
Poll::Pending => {
tracing::trace!("Handshake::poll(); flush.poll()=Pending");
tracing::trace!(flush.poll = %"Pending");
return Poll::Pending;
}
Poll::Ready(flushed) => {
tracing::trace!("Handshake::poll(); flush.poll()=Ready");
tracing::trace!(flush.poll = %"Ready");
flushed
}
};
@@ -1229,7 +1243,7 @@ where
},
);
tracing::trace!("Handshake::poll(); connection established!");
tracing::trace!("connection established!");
let mut c = Connection { connection };
if let Some(sz) = self.builder.initial_target_connection_window_size {
c.set_target_window_size(sz);
@@ -1290,14 +1304,14 @@ impl Peer {
use PushPromiseHeaderError::*;
match e {
NotSafeAndCacheable => tracing::debug!(
"convert_push_message: method {} is not safe and cacheable; promised_id={:?}",
?promised_id,
"convert_push_message: method {} is not safe and cacheable",
request.method(),
promised_id,
),
InvalidContentLength(e) => tracing::debug!(
"convert_push_message; promised request has invalid content-length {:?}; promised_id={:?}",
?promised_id,
"convert_push_message; promised request has invalid content-length {:?}",
e,
promised_id,
),
}
return Err(UserError::MalformedHeaders);
@@ -1328,6 +1342,8 @@ impl Peer {
impl proto::Peer for Peer {
type Poll = Request<()>;
const NAME: &'static str = "Server";
fn is_server() -> bool {
true
}
@@ -1471,7 +1487,7 @@ where
{
#[inline]
fn from(flush: Flush<T, Prioritized<B>>) -> Self {
Handshaking::Flushing(flush)
Handshaking::Flushing(flush.instrument(tracing::trace_span!("flush")))
}
}
@@ -1482,7 +1498,7 @@ where
{
#[inline]
fn from(read: ReadPreface<T, Prioritized<B>>) -> Self {
Handshaking::ReadingPreface(read)
Handshaking::ReadingPreface(read.instrument(tracing::trace_span!("read_preface")))
}
}