varnishslog/
serde_types.rs

1use serde::{Serialize, Serializer};
2use serde::ser::{SerializeSeq, SerializeMap};
3use crate::access_log::record::LogEntry as VslLogEntry;
4use crate::access_log::record::AclResult as VslAclResult;
5
6use linked_hash_map::LinkedHashMap;
7
8pub trait EntryType: Serialize {
9    fn type_name(&self) -> &str;
10    fn remote_ip(&self) -> &str;
11    fn timestamp(&self) -> f64;
12    fn request_method(&self) -> Option<&str>;
13    fn request_url(&self) -> Option<&str>;
14    fn request_protocol(&self) -> Option<&str>;
15    fn response_status(&self) -> Option<u32>;
16    fn response_bytes(&self) -> Option<u64>;
17}
18
19#[derive(Serialize, Debug)]
20pub struct ClientAccess<'a, 'i> {
21    pub record_type: &'a str,
22    pub vxid: u32,
23    pub session: Option<SessionInfo<'a>>,
24    pub remote_address: Address<'a>,
25    pub start_timestamp: f64,
26    pub end_timestamp: Option<f64>,
27    pub handling: &'a str,
28    pub request: Option<HttpRequest<'a, 'i>>,
29    pub response: HttpResponse<'a, 'i>,
30    pub backend_access: Option<&'i BackendAccess<'a, 'i>>,
31    pub process_duration: Option<f64>,
32    pub fetch_duration: Option<f64>,
33    pub ttfb_duration: f64,
34    pub serve_duration: f64,
35    pub recv_header_bytes: u64,
36    pub recv_body_bytes: u64,
37    pub recv_total_bytes: u64,
38    pub sent_header_bytes: u64,
39    pub sent_body_bytes: u64,
40    pub sent_total_bytes: u64,
41    pub esi_count: usize,
42    pub compression: Option<Compression>,
43    pub restart_count: usize,
44    #[serde(skip_serializing_if="Option::is_none")]
45    pub restart_log: Option<Log<'a, 'i>>,
46    pub log: Log<'a, 'i>,
47    #[serde(skip_serializing_if="Option::is_none")]
48    pub request_header_index: Option<Index<'a, 'i>>,
49    #[serde(skip_serializing_if="Option::is_none")]
50    pub response_header_index: Option<Index<'a, 'i>>,
51}
52
53impl<'a: 'i, 'i> EntryType for ClientAccess<'a, 'i> {
54    fn type_name(&self) -> &str {
55        self.record_type
56    }
57    fn remote_ip(&self) -> &str {
58        self.remote_address.ip
59    }
60    fn timestamp(&self) -> f64 {
61        self.end_timestamp.unwrap_or(self.start_timestamp)
62    }
63    fn request_method(&self) -> Option<&str> {
64        self.request.as_ref().map(|request| request.method)
65    }
66    fn request_url(&self) -> Option<&str> {
67        self.request.as_ref().map(|request| request.url)
68    }
69    fn request_protocol(&self) -> Option<&str> {
70        self.request.as_ref().map(|request| request.protocol)
71    }
72    fn response_status(&self) -> Option<u32> {
73        Some(self.response.status)
74    }
75    fn response_bytes(&self) -> Option<u64> {
76        Some(self.sent_body_bytes)
77    }
78}
79
80#[derive(Serialize, Debug)]
81pub struct BackendAccess<'a, 'i> {
82    pub vxid: u32,
83    pub start_timestamp: Option<f64>,
84    pub end_timestamp: Option<f64>,
85    pub handling: &'a str,
86    pub request: HttpRequest<'a, 'i>,
87    pub response: Option<HttpResponse<'a, 'i>>,
88    pub send_duration: f64,
89    pub wait_duration: Option<f64>,
90    pub ttfb_duration: Option<f64>,
91    pub fetch_duration: Option<f64>,
92    pub sent_header_bytes: Option<u64>,
93    pub sent_body_bytes: Option<u64>,
94    pub sent_total_bytes: Option<u64>,
95    pub recv_header_bytes: Option<u64>,
96    pub recv_body_bytes: Option<u64>,
97    pub recv_total_bytes: Option<u64>,
98    pub retry: usize,
99    pub backend_connection: Option<BackendConnection<'a>>,
100    pub cache_object: Option<CacheObject<'a, 'i>>,
101    pub compression: Option<Compression>,
102    pub log: Log<'a, 'i>,
103    #[serde(skip_serializing_if="Option::is_none")]
104    pub request_header_index: Option<Index<'a, 'i>>,
105    #[serde(skip_serializing_if="Option::is_none")]
106    pub response_header_index: Option<Index<'a, 'i>>,
107    #[serde(skip_serializing_if="Option::is_none")]
108    pub cache_object_response_header_index: Option<Index<'a, 'i>>,
109    pub lru_nuked: u32,
110}
111
112#[derive(Serialize, Debug)]
113pub struct PipeSession<'a, 'i> {
114    pub record_type: &'a str,
115    pub vxid: u32,
116    pub remote_address: Address<'a>,
117    pub start_timestamp: f64,
118    pub end_timestamp: Option<f64>,
119    pub backend_connection: Option<BackendConnection<'a>>,
120    pub request: HttpRequest<'a, 'i>,
121    pub backend_request: HttpRequest<'a, 'i>,
122    pub process_duration: Option<f64>,
123    pub ttfb_duration: Option<f64>,
124    pub recv_total_bytes: u64,
125    pub sent_total_bytes: u64,
126    pub log: Log<'a, 'i>,
127    #[serde(skip_serializing_if="Option::is_none")]
128    pub request_header_index: Option<Index<'a, 'i>>,
129    #[serde(skip_serializing_if="Option::is_none")]
130    pub backend_request_header_index: Option<Index<'a, 'i>>,
131}
132
133impl<'a: 'i, 'i> EntryType for PipeSession<'a, 'i> {
134    fn type_name(&self) -> &str {
135        self.record_type
136    }
137    fn remote_ip(&self) -> &str {
138        self.remote_address.ip
139    }
140    fn timestamp(&self) -> f64 {
141        self.end_timestamp.unwrap_or(self.start_timestamp)
142    }
143    fn request_method(&self) -> Option<&str> {
144        Some(self.request.method)
145    }
146    fn request_url(&self) -> Option<&str> {
147        Some(self.request.url)
148    }
149    fn request_protocol(&self) -> Option<&str> {
150        Some(self.request.protocol)
151    }
152    fn response_status(&self) -> Option<u32> {
153        None
154    }
155    fn response_bytes(&self) -> Option<u64> {
156        Some(self.sent_total_bytes)
157    }
158}
159
160#[derive(Serialize, Debug)]
161pub struct Address<'a> {
162    pub ip: &'a str,
163    pub port: u16,
164}
165
166#[derive(Debug)]
167pub enum Headers<'a, 'i> {
168    Raw(&'a [(String, String)]),
169    Indexed(Index<'a, 'i>)
170}
171
172impl<'a: 'i, 'i> Serialize for Headers<'a, 'i> {
173    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
174        match self {
175            &Headers::Raw(slice) => slice.serialize(serializer),
176            &Headers::Indexed(ref index) => index.serialize(serializer),
177        }
178    }
179}
180
181#[derive(Serialize, Debug)]
182pub struct Proxy<'a> {
183    pub version: &'a str,
184    pub client_address: Address<'a>,
185    pub server_address: Address<'a>,
186}
187
188#[derive(Serialize, Debug)]
189pub struct SessionInfo<'a> {
190    pub vxid: u32,
191    pub open_timestamp: f64,
192    pub local_address: Option<Address<'a>>,
193    pub remote_address: Address<'a>,
194    pub proxy: Option<Proxy<'a>>,
195}
196
197#[derive(Serialize, Debug)]
198pub struct HttpRequest<'a, 'i> {
199    pub protocol: &'a str,
200    pub method: &'a str,
201    pub url: &'a str,
202    pub headers: Headers<'a, 'i>,
203}
204
205#[derive(Serialize, Debug)]
206pub struct HttpResponse<'a, 'i> {
207    pub status: u32,
208    pub reason: &'a str,
209    pub protocol: &'a str,
210    pub headers: Headers<'a, 'i>,
211}
212
213#[derive(Serialize, Debug)]
214pub struct Compression {
215    pub operation: &'static str,
216    pub bytes_in: u64,
217    pub bytes_out: u64,
218}
219
220#[derive(Serialize, Debug)]
221pub struct Log<'a, 'i> {
222    #[serde(skip_serializing_if="Option::is_none")]
223    pub raw_log: Option<RawLog<'a>>,
224    #[serde(skip_serializing_if="Option::is_none")]
225    pub vars: Option<LogVarsIndex<'a, 'i>>,
226    #[serde(skip_serializing_if="Option::is_none")]
227    pub messages: Option<LogMessages<'a, 'i>>,
228    #[serde(skip_serializing_if="Option::is_none")]
229    pub acl_matched: Option<LogMessages<'a, 'i>>,
230    #[serde(skip_serializing_if="Option::is_none")]
231    pub acl_not_matched: Option<LogMessages<'a, 'i>>,
232}
233
234#[derive(Debug)]
235pub struct RawLog<'a>(pub &'a [VslLogEntry]);
236
237#[derive(Serialize, Debug)]
238pub struct RawLogEntry<'a> {
239    pub entry_type: &'a str,
240    pub message: &'a str,
241    #[serde(skip_serializing_if="Option::is_none")]
242    pub detail: Option<&'a str>,
243}
244
245impl<'a> Serialize for RawLog<'a> {
246    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
247        let mut state = serializer.serialize_seq(Some(self.0.len()))?;
248        for log_entry in self.0 {
249            let (entry_type, message, detail) = match log_entry {
250                &VslLogEntry::Vcl(ref msg) => ("VCL", msg.as_str(), None),
251                &VslLogEntry::VclError(ref msg) => ("VCL Error", msg.as_str(), None),
252                &VslLogEntry::Debug(ref msg) => ("Debug", msg.as_str(), None),
253                &VslLogEntry::Error(ref msg) => ("Error", msg.as_str(), None),
254                &VslLogEntry::FetchError(ref msg) => ("Fetch Error", msg.as_str(), None),
255                &VslLogEntry::Warning(ref msg) => ("Warning", msg.as_str(), None),
256                &VslLogEntry::Acl(ref result, ref name, ref addr) => match result {
257                    &VslAclResult::Match => ("ACL Match", name.as_str(), addr.as_ref().map(String::as_str)),
258                    &VslAclResult::NoMatch => ("ACL No Match", name.as_str(), addr.as_ref().map(String::as_str)),
259                },
260            };
261
262            state.serialize_element(&RawLogEntry {
263                entry_type: entry_type,
264                message: message,
265                detail: detail,
266            })?;
267        }
268        state.end()
269    }
270}
271
272#[derive(Debug)]
273pub struct Index<'a, 'i>(pub &'i LinkedHashMap<String, Vec<&'a str>>);
274
275impl<'a: 'i, 'i> Serialize for Index<'a, 'i> {
276    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
277        let mut state = serializer.serialize_map(Some(self.0.len()))?;
278        for (ref key, ref values) in self.0 {
279            state.serialize_key(key)?;
280            state.serialize_value(values)?;
281        }
282        state.end()
283    }
284}
285
286#[derive(Debug)]
287pub struct LogVarsIndex<'a, 'i>(pub &'i LinkedHashMap<&'a str, &'a str>);
288
289impl<'a: 'i, 'i> Serialize for LogVarsIndex<'a, 'i> {
290    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
291        let mut state = serializer.serialize_map(Some(self.0.len()))?;
292        for (key, value) in self.0 {
293            state.serialize_key(key)?;
294            state.serialize_value(value)?;
295        }
296        state.end()
297    }
298}
299
300pub type LogMessages<'a, 'i> = &'i [&'a str];
301
302#[derive(Serialize, Debug)]
303pub struct CacheObject<'a, 'i> {
304    pub storage_type: &'a str,
305    pub storage_name: &'a str,
306    pub ttl_duration: Option<f64>,
307    pub grace_duration: Option<f64>,
308    pub keep_duration: Option<f64>,
309    pub since_timestamp: f64,
310    pub origin_timestamp: f64,
311    pub fetch_mode: Option<&'a str>,
312    pub fetch_streamed: Option<bool>,
313    pub response: Option<HttpResponse<'a, 'i>>,
314}
315
316#[derive(Serialize, Debug)]
317pub struct BackendConnection<'a> {
318    pub fd: isize,
319    pub name: &'a str,
320    pub remote_address: Option<Address<'a>>,
321    pub local_address: Address<'a>,
322}