blob: 623783e3699a2e724e9435d546b5b9d5667361e6 [file] [log] [blame]
use std::time::SystemTime;
use crate::Tag;
/// Span is one of the tracing concept, representing a time duration.
/// Typically, it represent a method invocation or a RPC.
pub trait Span {
fn start(&mut self);
fn start_with_timestamp(&mut self, timestamp: SystemTime);
fn is_entry(&self) -> bool;
fn is_exit(&self) -> bool;
fn span_id(&self) -> i32;
fn tag(&mut self, tag: Tag);
/// End means sealing the end time.
/// Still need to call Context::archive
fn end(&mut self);
fn end_with_timestamp(&mut self, timestamp: SystemTime);
fn is_ended(&mut self) -> bool;
/// Return the replicated existing tags.
fn tags(&self) -> Vec<Tag>;
}
pub struct TracingSpan {
/// The operation name represents the logic process of this span
operation_name: String,
span_id: i32,
parent_span_id: i32,
/// The timestamp of the span start time
start_time: u64,
/// The timestamp of the span end time
end_time: u64,
/// As an entry span
is_entry: bool,
/// As an exit span
is_exit: bool,
/// The peer network address when as an RPC related span.
/// Typically used in exit span, representing the target server address.
peer: Option<String>,
/// Tag this span in error status.
error_occurred: bool,
/// Component id is defined in the main repo to represent the library kind.
component_id: Option<i32>,
tags: Vec<Tag>,
}
impl TracingSpan {
/// Create a new entry span
pub fn new_entry_span(operation_name: String, span_id: i32, parent_span_id: i32) -> Box<dyn Span> {
let mut span = TracingSpan::_new(operation_name, span_id, parent_span_id);
span.is_entry = true;
Box::new(span)
}
/// Create a new exit span
pub fn new_exit_span(operation_name: String, span_id: i32, parent_span_id: i32) -> Box<dyn Span> {
let mut span = TracingSpan::_new(operation_name, span_id, parent_span_id);
span.is_exit = true;
Box::new(span)
}
/// Create a new local span
pub fn new_local_span(operation_name: String, span_id: i32, parent_span_id: i32) -> Box<dyn Span> {
let span = TracingSpan::_new(operation_name, span_id, parent_span_id);
Box::new(span)
}
/// Create a span and set the limited internal values
fn _new(operation_name: String, span_id: i32, parent_span_id: i32) -> Self {
TracingSpan {
operation_name,
span_id,
parent_span_id,
start_time: 0,
end_time: 0,
is_entry: false,
is_exit: false,
peer: None,
error_occurred: false,
component_id: None,
tags: Vec::new(),
}
}
}
impl Span for TracingSpan {
fn start(&mut self) {
self.start_time = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
Ok(n) => { n.as_millis() }
Err(_) => self.start_time as u128,
} as u64;
}
fn start_with_timestamp(&mut self, timestamp: SystemTime) {
self.start_time = match timestamp.duration_since(SystemTime::UNIX_EPOCH) {
Ok(n) => { n.as_millis() }
Err(_) => self.start_time as u128,
} as u64;
}
fn is_entry(&self) -> bool {
self.is_entry
}
fn is_exit(&self) -> bool {
self.is_exit
}
fn span_id(&self) -> i32 {
self.span_id
}
fn tag(&mut self, tag: Tag) {
self.tags.push(tag);
}
fn end(&mut self) {
self.end_time = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
Ok(n) => { n.as_millis() }
Err(_) => self.start_time as u128,
} as u64;
}
fn end_with_timestamp(&mut self, timestamp: SystemTime) {
self.end_time = match timestamp.duration_since(SystemTime::UNIX_EPOCH) {
Ok(n) => { n.as_millis() }
Err(_) => self.start_time as u128,
} as u64;
}
fn is_ended(&mut self) -> bool {
self.end_time != 0
}
fn tags(&self) -> Vec<Tag> {
let mut tags = Vec::new();
for t in &self.tags {
tags.push(t.clone());
};
tags
}
}
#[cfg(test)]
mod span_tests {
use std::time::SystemTime;
use crate::{Tag, TracingContext};
use crate::span::*;
#[test]
fn test_span_new() {
let mut context = TracingContext::new();
let mut span = TracingSpan::_new(String::from("op1"), 0, -1);
assert_eq!(span.parent_span_id, -1);
assert_eq!(span.span_id, 0);
assert_eq!(span.start_time, 0);
span.start();
assert_ne!(span.start_time, 0);
let mut span2 = TracingSpan::_new(String::from("op2"), 1, 0);
assert_eq!("op2", span2.operation_name);
assert_eq!(span2.parent_span_id, 0);
assert_eq!(span2.span_id, 1);
span2.start_with_timestamp(SystemTime::now());
assert_ne!(span2.start_time, 0);
}
#[test]
fn test_new_entry_span() {
let mut context = TracingContext::new();
let mut span = TracingSpan::new_entry_span(String::from("op1"), 0, 1);
assert_eq!(span.is_entry(), true)
}
#[test]
fn test_span_with_tags() {
let context = TracingContext::new();
let mut span = TracingSpan::new_entry_span(String::from("op1"), 0, 1);
span.tag(Tag::new(String::from("tag1"), String::from("value1")));
span.tag(Tag::new(String::from("tag2"), String::from("value2")));
let tags = span.tags();
assert_eq!(tags.len(), 2);
assert_eq!(tags.get(0).unwrap().key(), "tag1")
}
}