1use super::{
2 DefaultMakeSpan, DefaultOnBodyChunk, DefaultOnEos, DefaultOnFailure, DefaultOnRequest,
3 DefaultOnResponse, GrpcMakeClassifier, HttpMakeClassifier, MakeSpan, OnBodyChunk, OnEos,
4 OnFailure, OnRequest, OnResponse, ResponseBody, ResponseFuture, TraceLayer,
5};
6use crate::classify::{
7 GrpcErrorsAsFailures, MakeClassifier, ServerErrorsAsFailures, SharedClassifier,
8};
9use http::{Request, Response};
10use http_body::Body;
11use std::{
12 fmt,
13 task::{Context, Poll},
14 time::Instant,
15};
16use tower_service::Service;
17
18#[derive(Debug, Clone, Copy)]
25pub struct Trace<
26 S,
27 M,
28 MakeSpan = DefaultMakeSpan,
29 OnRequest = DefaultOnRequest,
30 OnResponse = DefaultOnResponse,
31 OnBodyChunk = DefaultOnBodyChunk,
32 OnEos = DefaultOnEos,
33 OnFailure = DefaultOnFailure,
34> {
35 pub(crate) inner: S,
36 pub(crate) make_classifier: M,
37 pub(crate) make_span: MakeSpan,
38 pub(crate) on_request: OnRequest,
39 pub(crate) on_response: OnResponse,
40 pub(crate) on_body_chunk: OnBodyChunk,
41 pub(crate) on_eos: OnEos,
42 pub(crate) on_failure: OnFailure,
43}
44
45impl<S, M> Trace<S, M> {
46 pub fn new(inner: S, make_classifier: M) -> Self
48 where
49 M: MakeClassifier,
50 {
51 Self {
52 inner,
53 make_classifier,
54 make_span: DefaultMakeSpan::new(),
55 on_request: DefaultOnRequest::default(),
56 on_response: DefaultOnResponse::default(),
57 on_body_chunk: DefaultOnBodyChunk::default(),
58 on_eos: DefaultOnEos::default(),
59 on_failure: DefaultOnFailure::default(),
60 }
61 }
62
63 pub fn layer(make_classifier: M) -> TraceLayer<M>
67 where
68 M: MakeClassifier,
69 {
70 TraceLayer::new(make_classifier)
71 }
72}
73
74impl<S, M, MakeSpan, OnRequest, OnResponse, OnBodyChunk, OnEos, OnFailure>
75 Trace<S, M, MakeSpan, OnRequest, OnResponse, OnBodyChunk, OnEos, OnFailure>
76{
77 define_inner_service_accessors!();
78
79 pub fn on_request<NewOnRequest>(
85 self,
86 new_on_request: NewOnRequest,
87 ) -> Trace<S, M, MakeSpan, NewOnRequest, OnResponse, OnBodyChunk, OnEos, OnFailure> {
88 Trace {
89 on_request: new_on_request,
90 inner: self.inner,
91 on_failure: self.on_failure,
92 on_eos: self.on_eos,
93 on_body_chunk: self.on_body_chunk,
94 make_span: self.make_span,
95 on_response: self.on_response,
96 make_classifier: self.make_classifier,
97 }
98 }
99
100 pub fn on_response<NewOnResponse>(
106 self,
107 new_on_response: NewOnResponse,
108 ) -> Trace<S, M, MakeSpan, OnRequest, NewOnResponse, OnBodyChunk, OnEos, OnFailure> {
109 Trace {
110 on_response: new_on_response,
111 inner: self.inner,
112 on_request: self.on_request,
113 on_failure: self.on_failure,
114 on_body_chunk: self.on_body_chunk,
115 on_eos: self.on_eos,
116 make_span: self.make_span,
117 make_classifier: self.make_classifier,
118 }
119 }
120
121 pub fn on_body_chunk<NewOnBodyChunk>(
127 self,
128 new_on_body_chunk: NewOnBodyChunk,
129 ) -> Trace<S, M, MakeSpan, OnRequest, OnResponse, NewOnBodyChunk, OnEos, OnFailure> {
130 Trace {
131 on_body_chunk: new_on_body_chunk,
132 on_eos: self.on_eos,
133 make_span: self.make_span,
134 inner: self.inner,
135 on_failure: self.on_failure,
136 on_request: self.on_request,
137 on_response: self.on_response,
138 make_classifier: self.make_classifier,
139 }
140 }
141
142 pub fn on_eos<NewOnEos>(
148 self,
149 new_on_eos: NewOnEos,
150 ) -> Trace<S, M, MakeSpan, OnRequest, OnResponse, OnBodyChunk, NewOnEos, OnFailure> {
151 Trace {
152 on_eos: new_on_eos,
153 make_span: self.make_span,
154 inner: self.inner,
155 on_failure: self.on_failure,
156 on_request: self.on_request,
157 on_body_chunk: self.on_body_chunk,
158 on_response: self.on_response,
159 make_classifier: self.make_classifier,
160 }
161 }
162
163 pub fn on_failure<NewOnFailure>(
169 self,
170 new_on_failure: NewOnFailure,
171 ) -> Trace<S, M, MakeSpan, OnRequest, OnResponse, OnBodyChunk, OnEos, NewOnFailure> {
172 Trace {
173 on_failure: new_on_failure,
174 inner: self.inner,
175 make_span: self.make_span,
176 on_body_chunk: self.on_body_chunk,
177 on_request: self.on_request,
178 on_eos: self.on_eos,
179 on_response: self.on_response,
180 make_classifier: self.make_classifier,
181 }
182 }
183
184 pub fn make_span_with<NewMakeSpan>(
191 self,
192 new_make_span: NewMakeSpan,
193 ) -> Trace<S, M, NewMakeSpan, OnRequest, OnResponse, OnBodyChunk, OnEos, OnFailure> {
194 Trace {
195 make_span: new_make_span,
196 inner: self.inner,
197 on_failure: self.on_failure,
198 on_request: self.on_request,
199 on_body_chunk: self.on_body_chunk,
200 on_response: self.on_response,
201 on_eos: self.on_eos,
202 make_classifier: self.make_classifier,
203 }
204 }
205}
206
207impl<S>
208 Trace<
209 S,
210 HttpMakeClassifier,
211 DefaultMakeSpan,
212 DefaultOnRequest,
213 DefaultOnResponse,
214 DefaultOnBodyChunk,
215 DefaultOnEos,
216 DefaultOnFailure,
217 >
218{
219 pub fn new_for_http(inner: S) -> Self {
222 Self {
223 inner,
224 make_classifier: SharedClassifier::new(ServerErrorsAsFailures::default()),
225 make_span: DefaultMakeSpan::new(),
226 on_request: DefaultOnRequest::default(),
227 on_response: DefaultOnResponse::default(),
228 on_body_chunk: DefaultOnBodyChunk::default(),
229 on_eos: DefaultOnEos::default(),
230 on_failure: DefaultOnFailure::default(),
231 }
232 }
233}
234
235impl<S>
236 Trace<
237 S,
238 GrpcMakeClassifier,
239 DefaultMakeSpan,
240 DefaultOnRequest,
241 DefaultOnResponse,
242 DefaultOnBodyChunk,
243 DefaultOnEos,
244 DefaultOnFailure,
245 >
246{
247 pub fn new_for_grpc(inner: S) -> Self {
250 Self {
251 inner,
252 make_classifier: SharedClassifier::new(GrpcErrorsAsFailures::default()),
253 make_span: DefaultMakeSpan::new(),
254 on_request: DefaultOnRequest::default(),
255 on_response: DefaultOnResponse::default(),
256 on_body_chunk: DefaultOnBodyChunk::default(),
257 on_eos: DefaultOnEos::default(),
258 on_failure: DefaultOnFailure::default(),
259 }
260 }
261}
262
263impl<
264 S,
265 ReqBody,
266 ResBody,
267 M,
268 OnRequestT,
269 OnResponseT,
270 OnFailureT,
271 OnBodyChunkT,
272 OnEosT,
273 MakeSpanT,
274 > Service<Request<ReqBody>>
275 for Trace<S, M, MakeSpanT, OnRequestT, OnResponseT, OnBodyChunkT, OnEosT, OnFailureT>
276where
277 S: Service<Request<ReqBody>, Response = Response<ResBody>>,
278 ReqBody: Body,
279 ResBody: Body,
280 ResBody::Error: fmt::Display + 'static,
281 S::Error: fmt::Display + 'static,
282 M: MakeClassifier,
283 M::Classifier: Clone,
284 MakeSpanT: MakeSpan<ReqBody>,
285 OnRequestT: OnRequest<ReqBody>,
286 OnResponseT: OnResponse<ResBody> + Clone,
287 OnBodyChunkT: OnBodyChunk<ResBody::Data> + Clone,
288 OnEosT: OnEos + Clone,
289 OnFailureT: OnFailure<M::FailureClass> + Clone,
290{
291 type Response =
292 Response<ResponseBody<ResBody, M::ClassifyEos, OnBodyChunkT, OnEosT, OnFailureT>>;
293 type Error = S::Error;
294 type Future =
295 ResponseFuture<S::Future, M::Classifier, OnResponseT, OnBodyChunkT, OnEosT, OnFailureT>;
296
297 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
298 self.inner.poll_ready(cx)
299 }
300
301 fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
302 let start = Instant::now();
303
304 let span = self.make_span.make_span(&req);
305
306 let classifier = self.make_classifier.make_classifier(&req);
307
308 let future = {
309 let _guard = span.enter();
310 self.on_request.on_request(&req, &span);
311 self.inner.call(req)
312 };
313
314 ResponseFuture {
315 inner: future,
316 span,
317 classifier: Some(classifier),
318 on_response: Some(self.on_response.clone()),
319 on_body_chunk: Some(self.on_body_chunk.clone()),
320 on_eos: Some(self.on_eos.clone()),
321 on_failure: Some(self.on_failure.clone()),
322 start,
323 }
324 }
325}