1use std::collections::{BTreeMap, HashMap};
4
5use actix_web::{
6 dev::{Payload, RequestHead},
7 Error, FromRequest, HttpMessage, HttpRequest,
8};
9use futures::{future, future::Ready};
10use serde::{
11 ser::{SerializeMap, Serializer},
12 Serialize,
13};
14use serde_json::value::Value;
15
16#[derive(Clone, Debug, Default)]
17pub struct Tags {
18 pub tags: HashMap<String, String>,
19 pub extra: HashMap<String, String>,
20}
21
22impl Serialize for Tags {
23 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
24 where
25 S: Serializer,
26 {
27 let mut seq = serializer.serialize_map(Some(self.tags.len()))?;
28 for tag in self.tags.clone() {
29 if !tag.1.is_empty() {
30 seq.serialize_entry(&tag.0, &tag.1)?;
31 }
32 }
33 seq.end()
34 }
35}
36
37#[allow(dead_code)]
38fn insert_if_not_empty(label: &str, val: &str, tags: &mut HashMap<String, String>) {
39 if !val.is_empty() {
40 tags.insert(label.to_owned(), val.to_owned());
41 }
42}
43
44impl Tags {
45 #![allow(unused)] pub fn from_request_head(req_head: &RequestHead) -> Tags {
48 req_head.into()
49 }
50
51 pub fn with_tags(tags: HashMap<String, String>) -> Tags {
52 if tags.is_empty() {
53 return Tags::default();
54 }
55 Tags {
56 tags,
57 extra: HashMap::new(),
58 }
59 }
60
61 pub fn get(&self, label: &str) -> String {
62 let none = "None".to_owned();
63 self.tags.get(label).map(String::from).unwrap_or(none)
64 }
65
66 pub fn extend(&mut self, tags: HashMap<String, String>) {
67 self.tags.extend(tags);
68 }
69
70 pub fn tag_tree(self) -> BTreeMap<String, String> {
71 let mut result = BTreeMap::new();
72
73 for (k, v) in self.tags {
74 result.insert(k.clone(), v.clone());
75 }
76 result
77 }
78
79 pub fn extra_tree(self) -> BTreeMap<String, Value> {
80 let mut result = BTreeMap::new();
81
82 for (k, v) in self.extra {
83 result.insert(k.clone(), Value::from(v));
84 }
85 result
86 }
87}
88
89impl slog::KV for Tags {
90 fn serialize(
91 &self,
92 _record: &slog::Record<'_>,
93 serializer: &mut dyn slog::Serializer,
94 ) -> slog::Result {
95 for (key, val) in &self.tags {
96 serializer.emit_str(slog::Key::from(key.clone()), val)?;
97 }
98 Ok(())
99 }
100}
101
102impl FromRequest for Tags {
103 type Error = Error;
104 type Future = Ready<Result<Self, Self::Error>>;
105
106 fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
107 let tags = {
108 let exts = req.extensions();
109 match exts.get::<Tags>() {
110 Some(t) => t.clone(),
111 None => Tags::from_request_head(req.head()),
112 }
113 };
114
115 future::ok(tags)
116 }
117}
118
119impl From<&RequestHead> for Tags {
120 fn from(req_head: &RequestHead) -> Self {
121 let mut tags = HashMap::new();
122 tags.insert("uri.method".to_owned(), req_head.method.to_string());
123 Tags {
124 tags,
125 extra: HashMap::new(),
126 }
127 }
128}
129
130impl From<Tags> for BTreeMap<String, String> {
131 fn from(tags: Tags) -> BTreeMap<String, String> {
132 let mut result = BTreeMap::new();
133
134 for (k, v) in tags.tags {
135 result.insert(k.clone(), v.clone());
136 }
137
138 result
139 }
140}