better_fetch/plugins/
logger.rs1use async_trait::async_trait;
2use tracing::{error, info, info_span, warn};
3
4use crate::hooks::{ErrorContext, Hooks};
5use crate::plugin::Plugin;
6
7#[derive(Debug, Clone)]
9pub struct LoggerPlugin {
10 pub enabled: bool,
12 pub verbose: bool,
14}
15
16impl LoggerPlugin {
17 pub fn new() -> Self {
19 Self {
20 enabled: true,
21 verbose: false,
22 }
23 }
24
25 pub fn enabled(mut self, enabled: bool) -> Self {
27 self.enabled = enabled;
28 self
29 }
30
31 pub fn verbose(mut self, verbose: bool) -> Self {
33 self.verbose = verbose;
34 self
35 }
36}
37
38impl Default for LoggerPlugin {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44#[async_trait]
45impl Plugin for LoggerPlugin {
46 fn id(&self) -> &'static str {
48 "logger"
49 }
50
51 fn hooks(&self) -> Hooks {
52 let enabled = self.enabled;
53 let verbose = self.verbose;
54
55 Hooks::new()
56 .on_request(move |ctx| {
57 let enabled = enabled;
58 let verbose = verbose;
59 async move {
60 if enabled {
61 let span = info_span!(
62 "http.request",
63 method = %ctx.method,
64 url = %ctx.url,
65 retry_attempt = ctx.retry_attempt,
66 );
67 let _guard = span.enter();
68 if verbose {
69 info!(header_count = ctx.headers.len(), "better-fetch request");
70 } else {
71 info!("better-fetch request");
72 }
73 }
74 Ok(ctx)
75 }
76 })
77 .on_response_stream({
78 let enabled = self.enabled;
79 let verbose = self.verbose;
80 move |ctx| {
81 let enabled = enabled;
82 let verbose = verbose;
83 async move {
84 if enabled {
85 let span = info_span!(
86 "http.response",
87 status = %ctx.status,
88 url = %ctx.request.url,
89 streaming = true,
90 );
91 let _guard = span.enter();
92 if verbose {
93 info!(
94 header_count = ctx.headers.len(),
95 "better-fetch stream response"
96 );
97 } else {
98 info!("better-fetch stream response");
99 }
100 }
101 Ok(crate::hooks::StreamingResponseMeta {
102 status: ctx.status,
103 headers: ctx.headers,
104 })
105 }
106 }
107 })
108 .on_response({
109 let enabled = self.enabled;
110 let verbose = self.verbose;
111 move |ctx| {
112 let enabled = enabled;
113 let verbose = verbose;
114 async move {
115 if enabled {
116 let status = ctx.response.status();
117 let span = info_span!(
118 "http.response",
119 status = %status,
120 url = %ctx.request.url,
121 streaming = false,
122 );
123 let _guard = span.enter();
124 if verbose {
125 info!(
126 header_count = ctx.response.headers().len(),
127 "better-fetch response"
128 );
129 } else {
130 info!("better-fetch response");
131 }
132 }
133 Ok(ctx.response)
134 }
135 }
136 })
137 .on_retry({
138 let enabled = self.enabled;
139 move |ctx| {
140 let enabled = enabled;
141 async move {
142 if enabled {
143 warn!(
144 retry_attempt = ctx.request.retry_attempt,
145 next_attempt = ctx.request.retry_attempt + 1,
146 status = %ctx.response.status(),
147 url = %ctx.request.url,
148 "better-fetch retry"
149 );
150 }
151 }
152 }
153 })
154 .on_error({
155 let enabled = self.enabled;
156 move |ctx: ErrorContext| {
157 let enabled = enabled;
158 async move {
159 if enabled {
160 let status = ctx.response.as_ref().map(|r| r.status().as_u16());
161 let body_preview = ctx.response_body_preview(256);
162 error!(
163 error = %ctx.error,
164 url = %ctx.request.url,
165 ?status,
166 body_preview = body_preview.as_deref(),
167 retry_attempt = ctx.request.retry_attempt,
168 "better-fetch error"
169 );
170 }
171 }
172 }
173 })
174 }
175}