rivet_logger/processors/
web.rs1use std::collections::BTreeMap;
2
3use crate::logger::{BoxError, LogRecord, LogValue, Processor};
4
5pub struct Web {
6 server_data: BTreeMap<String, String>,
7 extra_fields: BTreeMap<String, String>,
8}
9
10impl Web {
11 pub fn new(
12 server_data: Option<BTreeMap<String, String>>,
13 extra_fields: Option<BTreeMap<String, String>>,
14 ) -> Self {
15 let server_data = server_data.unwrap_or_else(default_server_data);
16
17 let mut default_fields = default_extra_fields();
18 if server_data.contains_key("UNIQUE_ID") {
19 default_fields.insert("unique_id".to_string(), "UNIQUE_ID".to_string());
20 }
21
22 Self {
23 server_data,
24 extra_fields: extra_fields.unwrap_or(default_fields),
25 }
26 }
27
28 pub fn add_extra_field(
29 &mut self,
30 extra_name: impl Into<String>,
31 server_name: impl Into<String>,
32 ) {
33 self.extra_fields
34 .insert(extra_name.into(), server_name.into());
35 }
36}
37
38impl Default for Web {
39 fn default() -> Self {
40 Self::new(None, None)
41 }
42}
43
44impl Processor for Web {
45 fn process(&self, mut record: LogRecord) -> Result<LogRecord, BoxError> {
46 if !self.server_data.contains_key("REQUEST_URI") {
47 return Ok(record);
48 }
49
50 for (extra_name, server_name) in &self.extra_fields {
51 let value = self
52 .server_data
53 .get(server_name)
54 .map(|value| LogValue::String(value.clone()))
55 .unwrap_or(LogValue::Null);
56 record.extra.insert(extra_name.clone(), value);
57 }
58
59 Ok(record)
60 }
61}
62
63fn default_server_data() -> BTreeMap<String, String> {
64 std::env::vars().collect()
65}
66
67fn default_extra_fields() -> BTreeMap<String, String> {
68 BTreeMap::from([
69 ("url".to_string(), "REQUEST_URI".to_string()),
70 ("ip".to_string(), "REMOTE_ADDR".to_string()),
71 ("http_method".to_string(), "REQUEST_METHOD".to_string()),
72 ("server".to_string(), "SERVER_NAME".to_string()),
73 ("referrer".to_string(), "HTTP_REFERER".to_string()),
74 ])
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::logger::{Level, LogRecord};
81 use time::OffsetDateTime;
82
83 #[test]
84 fn adds_default_web_fields_when_request_uri_exists() {
85 let mut server_data = BTreeMap::new();
86 server_data.insert("REQUEST_URI".to_string(), "/status".to_string());
87 server_data.insert("REQUEST_METHOD".to_string(), "GET".to_string());
88 let processor = Web::new(Some(server_data), None);
89 let record = LogRecord {
90 datetime: OffsetDateTime::now_utc(),
91 channel: "test".to_string(),
92 level: Level::Info,
93 message: "msg".to_string(),
94 context: BTreeMap::new(),
95 extra: BTreeMap::new(),
96 };
97
98 let processed = processor.process(record).expect("processor should run");
99 assert!(processed.extra.contains_key("url"));
100 assert!(processed.extra.contains_key("http_method"));
101 }
102}