1use serde::Serialize;
2use std::{convert::Infallible, fmt, str::FromStr};
3use tracing_core::Level;
4
5#[cfg_attr(
8 all(tracing_unstable, feature = "valuable"),
9 derive(valuable::Valuable)
10)]
11#[derive(Debug, Default, Serialize)]
12#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
13pub enum LogSeverity {
14 #[default]
16 Default,
17 Debug,
19 Info,
21 Notice,
23 Warning,
25 Error,
27 Critical,
29 Alert,
31 Emergency,
33}
34
35impl fmt::Display for LogSeverity {
36 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
37 let output = match self {
38 Self::Default => "DEFAULT",
39 Self::Debug => "DEBUG",
40 Self::Info => "INFO",
41 Self::Notice => "NOTICE",
42 Self::Warning => "WARNING",
43 Self::Error => "ERROR",
44 Self::Critical => "CRITICAL",
45 Self::Alert => "ALERT",
46 Self::Emergency => "EMERGENCY",
47 };
48
49 formatter.write_str(output)
50 }
51}
52
53impl From<&Level> for LogSeverity {
54 fn from(level: &Level) -> Self {
55 match level {
56 &Level::DEBUG | &Level::TRACE => Self::Debug,
57 &Level::INFO => Self::Info,
58 &Level::WARN => Self::Warning,
59 &Level::ERROR => Self::Error,
60 }
61 }
62}
63
64impl FromStr for LogSeverity {
65 type Err = Infallible;
66
67 fn from_str(string: &str) -> Result<Self, Self::Err> {
68 let severity = match string.to_lowercase().as_str() {
69 "debug" | "trace" => Self::Debug,
70 "info" => Self::Info,
71 "notice" => Self::Notice,
72 "warn" | "warning" => Self::Warning,
73 "error" => Self::Error,
74 "critical" => Self::Critical,
75 "alert" => Self::Alert,
76 "emergency" => Self::Emergency,
77 _ => Self::Default,
78 };
79
80 Ok(severity)
81 }
82}
83
84impl From<serde_json::Value> for LogSeverity {
85 fn from(json: serde_json::Value) -> Self {
86 if let Some(str) = json.as_str() {
88 return Self::from_str(str).unwrap_or(Self::Default);
89 }
90
91 #[cfg(all(tracing_unstable, feature = "valuable"))]
93 if let Some(map) = json.as_object() {
94 if let Some(key) = map.keys().next() {
95 return Self::from_str(key).unwrap_or(Self::Default);
96 }
97 }
98
99 Self::Default
100 }
101}
102
103#[cfg_attr(docsrs, doc(cfg(feature = "valuable")))]
106#[cfg(any(docsrs, all(tracing_unstable, feature = "valuable")))]
107#[derive(Default)]
108pub struct HttpRequest {
109 pub request_method: Option<http::Method>,
111 pub request_url: Option<url::Url>,
113 pub request_size: Option<u32>,
115 pub response_size: Option<u32>,
117 pub status: Option<http::StatusCode>,
119 pub user_agent: Option<String>,
121 pub remote_ip: Option<std::net::IpAddr>,
123 pub server_ip: Option<std::net::IpAddr>,
125 pub referer: Option<url::Url>,
127 pub latency: Option<std::time::Duration>,
129 pub cache_lookup: Option<bool>,
131 pub cache_hit: Option<bool>,
133 pub cache_validated_with_origin_server: Option<bool>,
135 pub cache_fill_bytes: Option<u32>,
137 pub protocol: Option<String>,
139}
140
141#[cfg_attr(docsrs, doc(cfg(feature = "valuable")))]
142#[cfg(any(docsrs, all(tracing_unstable, feature = "valuable")))]
143impl HttpRequest {
144 pub fn new() -> Self {
146 Self::default()
147 }
148}
149
150#[cfg(all(tracing_unstable, feature = "valuable"))]
151static HTTP_REQUEST_FIELDS: &[valuable::NamedField<'static>] = &[
152 valuable::NamedField::new("requestMethod"),
153 valuable::NamedField::new("requestUrl"),
154 valuable::NamedField::new("requestSize"),
155 valuable::NamedField::new("responseSize"),
156 valuable::NamedField::new("status"),
157 valuable::NamedField::new("userAgent"),
158 valuable::NamedField::new("remoteIp"),
159 valuable::NamedField::new("serverIp"),
160 valuable::NamedField::new("referer"),
161 valuable::NamedField::new("latency"),
162 valuable::NamedField::new("cacheLookup"),
163 valuable::NamedField::new("cacheHit"),
164 valuable::NamedField::new("cacheValidatedWithOriginServer"),
165 valuable::NamedField::new("cacheFillBytes"),
166 valuable::NamedField::new("protocol"),
167];
168
169#[cfg_attr(docsrs, doc(cfg(feature = "valuable")))]
170#[cfg(any(docsrs, all(tracing_unstable, feature = "valuable")))]
171impl valuable::Valuable for HttpRequest {
172 fn as_value(&self) -> valuable::Value<'_> {
173 valuable::Value::Structable(self)
174 }
175
176 fn visit(&self, visit: &mut dyn valuable::Visit) {
177 let request_method = self
178 .request_method
179 .as_ref()
180 .map(|method| method.to_string());
181 let request_url = self.request_url.as_ref().map(|url| url.to_string());
182 let status = self.status.map(|status| status.as_u16());
183 let user_agent = &self.user_agent;
184 let remote_ip = self.remote_ip.map(|ip| ip.to_string());
185 let server_ip = self.server_ip.map(|ip| ip.to_string());
186 let referer = self.referer.as_ref().map(|url| url.to_string());
187 let latency = self
188 .latency
189 .map(|latency| format!("{}s", latency.as_secs_f32()));
190
191 let (fields, values): (Vec<_>, Vec<_>) = HTTP_REQUEST_FIELDS
192 .iter()
193 .zip(
194 [
195 request_method.as_ref().map(valuable::Valuable::as_value),
196 request_url.as_ref().map(valuable::Valuable::as_value),
197 self.request_size.as_ref().map(valuable::Valuable::as_value),
198 self.response_size
199 .as_ref()
200 .map(valuable::Valuable::as_value),
201 status.as_ref().map(valuable::Valuable::as_value),
202 user_agent.as_ref().map(valuable::Valuable::as_value),
203 remote_ip.as_ref().map(valuable::Valuable::as_value),
204 server_ip.as_ref().map(valuable::Valuable::as_value),
205 referer.as_ref().map(valuable::Valuable::as_value),
206 latency.as_ref().map(valuable::Valuable::as_value),
207 self.cache_lookup.as_ref().map(valuable::Valuable::as_value),
208 self.cache_hit.as_ref().map(valuable::Valuable::as_value),
209 self.cache_validated_with_origin_server
210 .as_ref()
211 .map(valuable::Valuable::as_value),
212 self.cache_fill_bytes
213 .as_ref()
214 .map(valuable::Valuable::as_value),
215 self.protocol.as_ref().map(valuable::Valuable::as_value),
216 ]
217 .iter(),
218 )
219 .filter_map(|(field, value)| value.map(|value| (field, value)))
220 .unzip();
221
222 visit.visit_named_fields(&valuable::NamedValues::new(&fields, &values));
223 }
224}
225
226#[cfg_attr(docsrs, doc(cfg(feature = "valuable")))]
227#[cfg(any(docsrs, all(tracing_unstable, feature = "valuable")))]
228impl valuable::Structable for HttpRequest {
229 fn definition(&self) -> valuable::StructDef<'_> {
230 valuable::StructDef::new_dynamic("HttpRequest", valuable::Fields::Named(&[]))
231 }
232}
233
234#[cfg_attr(docsrs, doc(cfg(feature = "opentelemetry")))]
238#[cfg(any(docsrs, feature = "opentelemetry"))]
239#[derive(Clone)]
240pub struct CloudTraceConfiguration {
241 pub project_id: String,
245}