diff --git a/opentracing-api/src/lib.rs b/opentracing-api/src/lib.rs index ac6ec50..a8500a3 100644 --- a/opentracing-api/src/lib.rs +++ b/opentracing-api/src/lib.rs @@ -3,7 +3,9 @@ mod context; mod tag; mod field; +mod span; pub use context::SpanContext; -pub use tag::{ParseTagsError, Tags}; +pub use tag::{ParseTagsError, TagValue, Tags}; pub use field::{Fields, ParseFieldsError}; +pub use span::{FinishedSpan, Span}; diff --git a/opentracing-api/src/span.rs b/opentracing-api/src/span.rs new file mode 100644 index 0000000..0e75c8c --- /dev/null +++ b/opentracing-api/src/span.rs @@ -0,0 +1,61 @@ +use SpanContext; +use TagValue; + +/// The `Span` represents the OpenTracing specification's Span contract. +pub trait Span<'a> { + /// The associated `SpanContext`. + type Context: SpanContext<'a>; + + /// Retrieve the associated `SpanContext`. + /// + /// This may be called any time, including after `finish`. + fn context(&self) -> &Self::Context; + + /// Sets a key:value tag on the `Span`. + fn set_tag(&mut self, key: &str, value: TagValue); + + /// Returns a tag value if set, none otherwise + fn tag(&self, key: &str) -> Option<&'a TagValue>; + + /// Record an event at the current walltime timestamp. + fn log(&mut self, event: String); + + /// Record an event at the given walltime timestamp. + fn log_at(&mut self, timestamp: u64, event: String); + + /// Sets a baggage item in the Span (and its SpanContext) as a key/value pair. + fn set_baggage_item(&mut self, key: &str, value: String); + + /// the value of the baggage item identified by the given key, or None if no such item + /// could be found. + fn baggage_item(&self, key: &str) -> Option<&'a String>; + + /// Sets the string name for the logical operation this span represents. + fn set_operation_name(&mut self, name: &str); + + /// Returns the operation name if set, None otherwise. + fn operation_name(&self) -> Option<&'a str>; + + /// Sets the end timestamp to now and finishes (records) the span. + fn finish(self) -> FinishedSpan; + + /// Sets an explicit end timestamp and finishes (records) the span. + fn finish_at(self, timestamp: u64) -> FinishedSpan; +} + +pub struct FinishedSpan { + context: C, +} + +impl<'a, C> FinishedSpan +where + C: SpanContext<'a>, +{ + pub fn new(context: C) -> Self { + FinishedSpan { context } + } + + pub fn context(&self) -> &C { + &self.context + } +} diff --git a/opentracing-api/src/tag.rs b/opentracing-api/src/tag.rs index 9f3123d..194c968 100644 --- a/opentracing-api/src/tag.rs +++ b/opentracing-api/src/tag.rs @@ -171,6 +171,25 @@ impl fmt::Display for ParseTagsError { } } +/// Tags Values per spec can be Strings, Booleans or Numerics. +/// +/// Note that isize and usize are not included here since they +/// are only meant to be used as pointers-sized types only. +pub enum TagValue { + String(String), + Boolean(bool), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + U8(u8), + U16(u16), + U32(u32), + U64(u64), + F32(f32), + F64(f64), +} + #[cfg(test)] mod tests { diff --git a/opentracing-mock/src/lib.rs b/opentracing-mock/src/lib.rs index d912641..dadd78b 100644 --- a/opentracing-mock/src/lib.rs +++ b/opentracing-mock/src/lib.rs @@ -4,9 +4,9 @@ extern crate opentracing_api; -use opentracing_api::SpanContext; use std::collections::HashMap; use std::collections::hash_map::Iter as HashMapIter; +use opentracing_api::{FinishedSpan, Span, SpanContext, TagValue}; pub struct MockSpanContext { baggage: HashMap, @@ -14,9 +14,14 @@ pub struct MockSpanContext { impl MockSpanContext { /// Create a new `MockSpanContext` with the given baggage. - pub fn new(baggage: HashMap) -> Self { + fn new(baggage: HashMap) -> Self { MockSpanContext { baggage } } + + /// Create a new `MockSpanContext` with empty baggage. + fn empty() -> Self { + MockSpanContext::new(HashMap::new()) + } } impl<'a> SpanContext<'a> for MockSpanContext { @@ -27,6 +32,66 @@ impl<'a> SpanContext<'a> for MockSpanContext { } } +pub struct MockSpan { + ctx: MockSpanContext, +} + +impl MockSpan { + pub fn new() -> Self { + Self { + ctx: MockSpanContext::empty(), + } + } +} + +impl<'a> Span<'a> for MockSpan { + type Context = MockSpanContext; + + fn context(&self) -> &Self::Context { + &self.ctx + } + + fn set_tag(&mut self, _key: &str, _value: TagValue) { + unimplemented!() + } + + fn tag(&self, _key: &str) -> Option<&'a TagValue> { + unimplemented!() + } + + fn log(&mut self, _event: String) { + unimplemented!() + } + + fn log_at(&mut self, _timestamp: u64, _event: String) { + unimplemented!() + } + + fn set_baggage_item(&mut self, _key: &str, _value: String) { + unimplemented!() + } + + fn baggage_item(&self, _key: &str) -> Option<&'a String> { + unimplemented!() + } + + fn set_operation_name(&mut self, _name: &str) { + unimplemented!() + } + + fn operation_name(&self) -> Option<&'a str> { + unimplemented!() + } + + fn finish(self) -> FinishedSpan { + unimplemented!() + } + + fn finish_at(self, _timestamp: u64) -> FinishedSpan { + unimplemented!() + } +} + #[cfg(test)] mod tests { diff --git a/opentracing-noop/src/lib.rs b/opentracing-noop/src/lib.rs index abf365c..17cfe3a 100644 --- a/opentracing-noop/src/lib.rs +++ b/opentracing-noop/src/lib.rs @@ -4,7 +4,7 @@ extern crate opentracing_api; -use opentracing_api::SpanContext; +use opentracing_api::{FinishedSpan, Span, SpanContext, TagValue}; use std::iter::{empty, Empty}; /// The `NoopSpanContext` just returns an empty iterator on @@ -25,6 +25,56 @@ impl<'a> SpanContext<'a> for NoopSpanContext { } } +pub struct NoopSpan { + ctx: NoopSpanContext, +} + +impl NoopSpan { + pub fn new() -> Self { + Self { + ctx: NoopSpanContext::default(), + } + } +} + +impl<'a> Span<'a> for NoopSpan { + type Context = NoopSpanContext; + + fn context(&self) -> &Self::Context { + &self.ctx + } + + fn set_tag(&mut self, _key: &str, _value: TagValue) {} + + fn tag(&self, _key: &str) -> Option<&'a TagValue> { + None + } + + fn log(&mut self, _event: String) {} + + fn log_at(&mut self, _timestamp: u64, _event: String) {} + + fn set_baggage_item(&mut self, _key: &str, _value: String) {} + + fn baggage_item(&self, _key: &str) -> Option<&'a String> { + None + } + + fn set_operation_name(&mut self, _name: &str) {} + + fn operation_name(&self) -> Option<&'a str> { + None + } + + fn finish(self) -> FinishedSpan { + self.finish_at(0) + } + + fn finish_at(self, _timestamp: u64) -> FinishedSpan { + FinishedSpan::new(self.ctx) + } +} + #[cfg(test)] mod tests {