blob: 623cdc6f94ffb1f77bbf7bed781f6ac8115865b2 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::time::SystemTime;
use crate::log::LogEvent;
use crate::segment_ref::SegmentRef;
use crate::Tag;
/// Span is one of the tracing concept, representing a time duration.
/// Span typically used in the certain scope, Typically, it represent a method invocation or a RPC.
pub trait Span {
/// Start the span with the current system time
fn start(&mut self);
/// Start the span by using given time point.
fn start_with_timestamp(&mut self, timestamp: SystemTime);
/// Add a new tag to the span
fn tag(&mut self, tag: Tag);
/// Add a log event to the span
fn log(&mut self, log: LogEvent);
/// Indicate error occurred during the span execution.
fn error_occurred(&mut self);
/// Set the component id represented by this span.
/// Component id is pre-definition in the SkyWalking OAP backend component-libraries.yml file.
/// Read [Component library settings](https://github.com/apache/skywalking/blob/master/docs/en/guides/Component-library-settings.md) documentation for more details
fn set_component_id(&mut self, component_id: i32);
/// End the span with the current system time.
/// End just means sealing the end time, still need to call Context::finish_span to officially finish span and archive it for further reporting.
fn end(&mut self);
/// End the span by using given time point.
/// End just means sealing the end time, still need to call Context::finish_span to officially finish span and archive it for further reporting.
fn end_with_timestamp(&mut self, timestamp: SystemTime);
/// All following are status reading methods.
/// Return true if the span has been set end time
fn is_ended(&self) -> bool;
/// Return true if the span is an entry span
fn is_entry(&self) -> bool;
/// Return true if the span is an exit span
fn is_exit(&self) -> bool;
/// Return span id.
fn span_id(&self) -> i32;
/// 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>,
logs: Vec<LogEvent>,
refs: Vec<SegmentRef>,
}
/// Tracing Span is only created inside TracingContext.
impl TracingSpan {
/// Create a new entry span
pub fn new_entry_span(operation_name: String, span_id: i32, parent_span_id: i32) -> TracingSpan {
let mut span = TracingSpan::_new(operation_name, span_id, parent_span_id);
span.is_entry = true;
span
}
/// Create a new exit span
pub fn new_exit_span(operation_name: String, span_id: i32, parent_span_id: i32, peer: String) -> TracingSpan {
let mut span = TracingSpan::_new(operation_name, span_id, parent_span_id);
span.is_exit = true;
span.peer = Some(peer);
span
}
/// Create a new local span
pub fn new_local_span(operation_name: String, span_id: i32, parent_span_id: i32) -> TracingSpan {
let span = TracingSpan::_new(operation_name, span_id, parent_span_id);
span
}
/// Create a span
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(),
logs: Vec::new(),
refs: Vec::new(),
}
}
pub fn _add_ref(&mut self, reference: SegmentRef) {
self.refs.push(reference);
}
}
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 tag(&mut self, tag: Tag) {
self.tags.push(tag);
}
fn log(&mut self, log: LogEvent) {
self.logs.push(log);
}
fn error_occurred(&mut self) {
self.error_occurred = true;
}
fn set_component_id(&mut self, component_id: i32) {
self.component_id = Some(component_id);
}
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(&self) -> bool {
self.end_time != 0
}
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 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::log::{EventField, LogEvent};
use crate::span::*;
use crate::Tag;
#[test]
fn test_span_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 span = TracingSpan::new_entry_span(String::from("op1"), 0, 1);
assert_eq!(span.is_entry(), true)
}
#[test]
fn test_span_with_tags() {
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")
}
#[test]
fn test_span_with_logs() {
let mut span = TracingSpan::_new(String::from("op1"), 0, -1);
span.log(LogEvent::new(123, Box::new([
{ EventField::new(String::from("event1"), String::from("event description")) },
{ EventField::new(String::from("event2"), String::from("event description")) },
])));
assert_eq!(span.logs.len(), 1);
}
}