Skip to main content

better_fetch/plugins/
logger.rs

1use async_trait::async_trait;
2use tracing::{error, info, warn};
3
4use crate::hooks::{ErrorContext, Hooks};
5use crate::plugin::Plugin;
6
7/// Tracing-based logger plugin (request, response, retry, error).
8#[derive(Debug, Clone)]
9pub struct LoggerPlugin {
10    /// When `false`, hooks are registered but do not log.
11    pub enabled: bool,
12    /// When `true`, includes method and URL on each line.
13    pub verbose: bool,
14}
15
16impl LoggerPlugin {
17    /// Creates a plugin with logging enabled.
18    pub fn new() -> Self {
19        Self {
20            enabled: true,
21            verbose: false,
22        }
23    }
24
25    /// Enables or disables log output.
26    pub fn enabled(mut self, enabled: bool) -> Self {
27        self.enabled = enabled;
28        self
29    }
30
31    /// Enables verbose log fields.
32    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    /// Plugin id: `"logger"`.
47    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                        if verbose {
62                            info!(
63                                method = %ctx.method,
64                                url = %ctx.url,
65                                "better-fetch request"
66                            );
67                        } else {
68                            info!(url = %ctx.url, "better-fetch request");
69                        }
70                    }
71                    Ok(ctx)
72                }
73            })
74            .on_response_stream({
75                let enabled = self.enabled;
76                let verbose = self.verbose;
77                move |ctx| {
78                    let enabled = enabled;
79                    let verbose = verbose;
80                    async move {
81                        if enabled {
82                            if verbose {
83                                info!(
84                                    status = %ctx.status,
85                                    url = %ctx.request.url,
86                                    "better-fetch stream response"
87                                );
88                            } else {
89                                info!(status = %ctx.status, "better-fetch stream response");
90                            }
91                        }
92                        Ok(crate::hooks::StreamingResponseMeta {
93                            status: ctx.status,
94                            headers: ctx.headers,
95                        })
96                    }
97                }
98            })
99            .on_response({
100                let enabled = self.enabled;
101                let verbose = self.verbose;
102                move |ctx| {
103                    let enabled = enabled;
104                    let verbose = verbose;
105                    async move {
106                        if enabled {
107                            let status = ctx.response.status();
108                            if verbose {
109                                info!(
110                                    status = %status,
111                                    url = %ctx.request.url,
112                                    "better-fetch response"
113                                );
114                            } else {
115                                info!(status = %status, "better-fetch response");
116                            }
117                        }
118                        Ok(ctx.response)
119                    }
120                }
121            })
122            .on_retry({
123                let enabled = self.enabled;
124                move |ctx| {
125                    let enabled = enabled;
126                    async move {
127                        if enabled {
128                            warn!(
129                                retry_attempt = ctx.request.retry_attempt,
130                                next_attempt = ctx.request.retry_attempt + 1,
131                                status = %ctx.response.status(),
132                                url = %ctx.request.url,
133                                "better-fetch retry"
134                            );
135                        }
136                    }
137                }
138            })
139            .on_error({
140                let enabled = self.enabled;
141                move |ctx: ErrorContext| {
142                    let enabled = enabled;
143                    async move {
144                        if enabled {
145                            error!(
146                                error = %ctx.error,
147                                url = %ctx.request.url,
148                                "better-fetch error"
149                            );
150                        }
151                    }
152                }
153            })
154    }
155}