#[derive(Debug)]
pub struct Duration(pub std::time::Duration);
impl serde::Serialize for Duration {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_u64(self.0.as_nanos() as u64)
}
}
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
pub enum SpanItem {
Log {
message: &'static str,
},
Field {
name: &'static str,
value: serde_json::Value,
},
TransientField {
name: &'static str,
value: serde_json::Value,
},
Query {
query: String,
bind: Option<String>,
result: Result<usize, String>,
},
Frame(Span),
}
#[derive(Serialize)]
pub struct Span {
pub id: String,
key: String,
pub items: Vec<(Duration, SpanItem)>,
pub success: Option<bool>,
pub result: Option<serde_json::Value>,
pub err: Option<String>,
#[serde(skip_serializing)]
pub created_on: std::time::Instant,
pub duration: Option<Duration>,
}
impl Clone for Span {
fn clone(&self) -> Self {
Span::new(&self.id)
}
}
impl std::fmt::Debug for Span {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Span")
.field("id", &self.id)
.field("key", &self.key)
.field("items", &self.items)
.field("success", &self.success)
.field("result", &self.result)
.field("err", &self.err)
.field("start_time", &self.created_on)
.field("duration", &self.duration)
.finish()
}
}
impl Span {
pub fn duration(&self) -> std::time::Duration {
self.duration
.as_ref()
.map(|v| v.0)
.unwrap_or_else(|| std::time::Instant::now().duration_since(self.created_on))
}
pub fn new(id: &str) -> Span {
Span {
id: id.to_owned(),
key: uuid::Uuid::new_v4().to_string(),
items: Vec::new(),
success: None,
result: None,
err: None,
created_on: std::time::Instant::now(),
duration: None,
}
}
pub(crate) fn set_id(&mut self, id: &str) {
self.id = id.to_string();
}
pub fn end(&mut self) -> &mut Self {
self.duration = Some(Duration(
std::time::Instant::now().duration_since(self.created_on),
));
self
}
pub fn set_result(&mut self, result: impl serde::Serialize) -> &mut Self {
self.result = Some(json!(result));
self
}
pub fn set_success(&mut self, is_success: bool) -> &mut Self {
self.success = Some(is_success);
self
}
pub fn set_err(&mut self, err: Option<String>) -> &mut Self {
self.err = err;
self
}
pub fn add_sub_frame(&mut self, created_on: std::time::Instant, frame: Span) {
self.items.push((
Duration(created_on.duration_since(self.created_on)),
SpanItem::Frame(frame),
));
}
pub fn get_key(&self) -> String {
self.key.clone()
}
pub fn add_log(&mut self, log: &'static str) {
self.items.push((
Duration(std::time::Instant::now().duration_since(self.created_on)),
SpanItem::Log { message: log },
))
}
pub fn add_breadcrumbs(&mut self, name: &'static str, value: serde_json::Value) {
self.items.push((
Duration(std::time::Instant::now().duration_since(self.created_on)),
SpanItem::Field { name, value },
))
}
pub fn add_transient_field(&mut self, name: &'static str, value: serde_json::Value) {
self.items.push((
Duration(std::time::Instant::now().duration_since(self.created_on)),
SpanItem::TransientField { name, value },
))
}
pub fn add_query(
&mut self,
query: String,
bind: Option<String>,
result: Result<usize, String>,
) {
self.items.push((
Duration(std::time::Instant::now().duration_since(self.created_on)),
SpanItem::Query {
query,
bind,
result,
},
))
}
}