mirror of
https://github.com/tokio-rs/tracing.git
synced 2025-09-30 06:20:38 +00:00

## Motivation As discussed in #308, there are a large number of crates in this repository, which can be confusing for users and can increase the maintainance burden for maintainers. Also, the `tracing-fmt` and `tracing-subscriber` crates both contain filtering implementations with similar behaviour and APIs, but `tracing-subscriber`'s filter module offers more advanced features (filtering on field values), and is usable with any subscriber implementation. Two separate filter implementations also has the potential to be confusing for users. ## Solution This branch moves most of the code from `tracing-fmt` into a module in `tracing-subscriber`, and changes the `tracing-fmt` builder APIs to use the `Filter` type in `tracing-subscriber`. The `tracing-subscriber/fmt` feature flag can be used to disable the formatting subscriber when it is not used. The `tracing-fmt` crate has been updated to re-export the APIs from `tracing-subscriber`, and marked as deprecated. Once we've published a new version of `tracing-subscriber` with the format APIs, we can publish a final release of `tracing-fmt` that will update the documentation & mark all APIs as deprecated, so that users know to move to the `tracing-subscriber` crate. Refs: #308 Signed-off-by: Eliza Weisman <eliza@buoyant.io>
151 lines
4.4 KiB
Rust
151 lines
4.4 KiB
Rust
#![deny(rust_2018_idioms)]
|
|
|
|
use bytes::{Bytes, IntoBuf};
|
|
use futures::*;
|
|
use http::Request;
|
|
use tokio::executor::DefaultExecutor;
|
|
use tokio::net::TcpListener;
|
|
use tower_h2::{Body, RecvBody, Server};
|
|
use tower_service::Service;
|
|
use tracing_futures::Instrument;
|
|
use tracing_tower::InstrumentMake;
|
|
|
|
type Response = http::Response<RspBody>;
|
|
|
|
struct RspBody(Option<Bytes>);
|
|
|
|
impl RspBody {
|
|
fn new(body: Bytes) -> Self {
|
|
RspBody(Some(body))
|
|
}
|
|
|
|
fn empty() -> Self {
|
|
RspBody(None)
|
|
}
|
|
}
|
|
|
|
impl Body for RspBody {
|
|
type Data = <Bytes as IntoBuf>::Buf;
|
|
type Error = h2::Error;
|
|
|
|
fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> {
|
|
let data = self.0.take().and_then(|b| {
|
|
if b.is_empty() {
|
|
None
|
|
} else {
|
|
Some(b.into_buf())
|
|
}
|
|
});
|
|
Ok(Async::Ready(data))
|
|
}
|
|
|
|
fn poll_trailers(&mut self) -> Poll<Option<http::HeaderMap>, Self::Error> {
|
|
Ok(None.into())
|
|
}
|
|
}
|
|
|
|
const ROOT: &'static str = "/";
|
|
|
|
#[derive(Debug)]
|
|
struct Svc;
|
|
impl Service<Request<RecvBody>> for Svc {
|
|
type Response = Response;
|
|
type Error = h2::Error;
|
|
type Future = future::FutureResult<Response, Self::Error>;
|
|
|
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
|
Ok(Async::Ready(()))
|
|
}
|
|
|
|
fn call(&mut self, req: Request<RecvBody>) -> Self::Future {
|
|
tracing::trace!(message = "received request", request.headers = ?req.headers());
|
|
let mut rsp = http::Response::builder();
|
|
rsp.version(http::Version::HTTP_2);
|
|
|
|
let uri = req.uri();
|
|
let rsp = if uri.path() != ROOT {
|
|
let body = RspBody::empty();
|
|
tracing::warn!(rsp.error = %"unrecognized path", request.path = ?uri.path());
|
|
rsp.status(404).body(body).unwrap()
|
|
} else {
|
|
let body = RspBody::new("heyo!".into());
|
|
rsp.status(200).body(body).unwrap()
|
|
};
|
|
|
|
tracing::debug!(rsp.status = %rsp.status(), message = "sending response...");
|
|
future::ok(rsp)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct NewSvc;
|
|
impl tower_service::Service<()> for NewSvc {
|
|
type Response = Svc;
|
|
type Error = ::std::io::Error;
|
|
type Future = future::FutureResult<Svc, Self::Error>;
|
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
|
Ok(Async::Ready(()))
|
|
}
|
|
|
|
fn call(&mut self, _target: ()) -> Self::Future {
|
|
future::ok(Svc)
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
// Set the default subscriber to record all traces emitted by this example
|
|
// and by the `tracing_tower` library's helpers.
|
|
let subscriber = tracing_subscriber::FmtSubscriber::builder()
|
|
.with_filter("h2_server=trace,tracing_tower=trace")
|
|
.finish();
|
|
let _ = tracing::subscriber::set_global_default(subscriber);
|
|
|
|
let addr = "[::1]:8888".parse().unwrap();
|
|
let bind = TcpListener::bind(&addr).expect("bind");
|
|
|
|
// Construct a span for the server task, annotated with the listening IP
|
|
// address and port.
|
|
let span = tracing::trace_span!("server", ip = %addr.ip(), port = addr.port());
|
|
|
|
let server = lazy(|| {
|
|
let executor = DefaultExecutor::current();
|
|
|
|
// Enrich the `MakeService` with a wrapper so that each request is
|
|
// traced with its own span.
|
|
let new_svc = NewSvc.with_traced_requests(tracing_tower::http::debug_request);
|
|
let h2 = Server::new(new_svc, Default::default(), executor);
|
|
|
|
tracing::info!("listening");
|
|
|
|
bind.incoming()
|
|
.fold(h2, |mut h2, sock| {
|
|
// Construct a new span for each accepted connection.
|
|
let addr = sock.peer_addr().expect("can't get addr");
|
|
let span = tracing::trace_span!("conn", ip = %addr.ip(), port = addr.port());
|
|
let _enter = span.enter();
|
|
|
|
tracing::debug!("accepted connection");
|
|
|
|
if let Err(e) = sock.set_nodelay(true) {
|
|
return Err(e);
|
|
}
|
|
|
|
let serve = h2
|
|
.serve(sock)
|
|
.map_err(|error| tracing::error!(message = "h2 error", %error))
|
|
.map(|_| {
|
|
tracing::trace!("finished serving connection");
|
|
})
|
|
.instrument(span.clone());
|
|
tokio::spawn(serve);
|
|
|
|
Ok(h2)
|
|
})
|
|
.map_err(|error| tracing::error!(message = "serve error", %error))
|
|
.map(|_| {})
|
|
})
|
|
.instrument(span);
|
|
|
|
tokio::run(server);
|
|
}
|