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}