Skip to content

Commit

Permalink
WIP: Span
Browse files Browse the repository at this point in the history
still todo:
 - add LogValue
 - figure out span referencing question
 - fix all issues with the span trait
 - add docs to everything once done
 - complete noop impl
 - complete mock impl
  • Loading branch information
daschl committed Mar 20, 2018
1 parent 1f5ab04 commit 77f7cc2
Show file tree
Hide file tree
Showing 6 changed files with 385 additions and 7 deletions.
8 changes: 6 additions & 2 deletions opentracing-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#![doc(html_root_url = "https://docs.rs/opentracing-api/0.1.0")]

mod context;
mod tag;
mod field;
mod reference;
mod span;
mod tag;

pub use context::SpanContext;
pub use tag::{ParseTagsError, Tags};
pub use field::{Fields, ParseFieldsError};
pub use reference::{ParseReferencesError, References};
pub use span::{FinishedSpan, Span};
pub use tag::{ParseTagsError, TagValue, Tags};
70 changes: 70 additions & 0 deletions opentracing-api/src/reference.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::fmt;
use std::error::Error;
use std::str::FromStr;

const REF_CHILD_OF: &str = "child_of";
const REF_FOLLOWS_FROM: &str = "follows_from";

/// References provide a namespace for official OpenTracing reference types.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum References {
/// See http://opentracing.io/spec/#causal-span-references for
/// more information about ChildOf references.
ChildOf,
/// See http://opentracing.io/spec/#causal-span-references for
/// more information about FollowsFrom references.
FollowsFrom,
}

impl References {
/// Returns the string representation for the enum reference variant.
pub fn as_str(&self) -> &'static str {
match *self {
References::ChildOf => REF_CHILD_OF,
References::FollowsFrom => REF_FOLLOWS_FROM,
}
}
}

impl fmt::Display for References {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}

impl FromStr for References {
type Err = ParseReferencesError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
REF_CHILD_OF => Ok(References::ChildOf),
REF_FOLLOWS_FROM => Ok(References::FollowsFrom),
_ => Err(ParseReferencesError::UnknownReference),
}
}
}

/// Describes errors which can happen while parsing into the `References` enum.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum ParseReferencesError {
/// The provided reference is not known.
UnknownReference,
}

impl Error for ParseReferencesError {
fn description(&self) -> &str {
match *self {
ParseReferencesError::UnknownReference => "Unknown Reference",
}
}

fn cause(&self) -> Option<&Error> {
None
}
}

impl fmt::Display for ParseReferencesError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
81 changes: 81 additions & 0 deletions opentracing-api/src/span.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
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<S>(&mut self, key: S, value: TagValue)
where
S: Into<String>;

/// Allows to unset a tag based on the given key. Noop if
/// it doesn't exist.
fn unset_tag<S>(&mut self, key: S)
where
S: Into<String>;

/// Returns a tag value if set, none otherwise
fn tag<S>(&self, key: S) -> Option<&TagValue>
where
S: Into<String>;

/// 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<S>(&mut self, key: S, value: String)
where
S: Into<String>;

/// Allows to unset a baggage item based on the given key. Noop if
/// it doesn't exist.
fn unset_baggage_item<S>(&mut self, key: S)
where
S: Into<String>;

/// the value of the baggage item identified by the given key, or None if no such item
/// could be found.
fn baggage_item<S>(&self, key: S) -> Option<&String>
where
S: Into<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<&str>;

/// Sets the end timestamp to now and finishes (records) the span.
fn finish(self) -> FinishedSpan<Self::Context>;

/// Sets an explicit end timestamp and finishes (records) the span.
fn finish_at(self, timestamp: u64) -> FinishedSpan<Self::Context>;
}

pub struct FinishedSpan<C> {
context: C,
}

impl<'a, C> FinishedSpan<C>
where
C: SpanContext<'a>,
{
pub fn new(context: C) -> Self {
FinishedSpan { context }
}

pub fn context(&self) -> &C {
&self.context
}
}
20 changes: 20 additions & 0 deletions opentracing-api/src/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,26 @@ 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.
#[derive(Clone, PartialEq, PartialOrd, Debug)]
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 {

Expand Down
135 changes: 131 additions & 4 deletions opentracing-mock/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,36 @@

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<String, String>,
}

impl MockSpanContext {
/// Create a new `MockSpanContext` with the given baggage.
pub fn new(baggage: HashMap<String, String>) -> Self {
fn new(baggage: HashMap<String, String>) -> Self {
MockSpanContext { baggage }
}

/// Create a new `MockSpanContext` with empty baggage.
fn empty() -> Self {
MockSpanContext::new(HashMap::new())
}

fn set_baggage_item(&mut self, key: String, value: String) {
self.baggage.insert(key, value);
}

fn unset_baggage_item(&mut self, key: &String) {
self.baggage.remove(key);
}

fn baggage_item(&self, key: &String) -> Option<&String> {
self.baggage.get(key)
}
}

impl<'a> SpanContext<'a> for MockSpanContext {
Expand All @@ -27,11 +44,99 @@ impl<'a> SpanContext<'a> for MockSpanContext {
}
}

pub struct MockSpan {
ctx: MockSpanContext,
tags: HashMap<String, TagValue>,
}

impl MockSpan {
pub fn new() -> Self {
Self {
ctx: MockSpanContext::empty(),
tags: HashMap::new(),
}
}
}

impl<'a> Span<'a> for MockSpan {
type Context = MockSpanContext;

fn context(&self) -> &Self::Context {
&self.ctx
}

fn set_tag<S>(&mut self, key: S, value: TagValue)
where
S: Into<String>,
{
self.tags.insert(key.into(), value);
}

fn unset_tag<S>(&mut self, key: S)
where
S: Into<String>,
{
self.tags.remove(&key.into());
}

fn tag<S>(&self, key: S) -> Option<&TagValue>
where
S: Into<String>,
{
self.tags.get(&key.into())
}

fn log(&mut self, _event: String) {
unimplemented!()
}

fn log_at(&mut self, _timestamp: u64, _event: String) {
unimplemented!()
}

fn set_baggage_item<S>(&mut self, key: S, value: String)
where
S: Into<String>,
{
self.ctx.set_baggage_item(key.into(), value);
}

fn unset_baggage_item<S>(&mut self, key: S)
where
S: Into<String>,
{
self.ctx.unset_baggage_item(&key.into())
}

fn baggage_item<S>(&self, key: S) -> Option<&String>
where
S: Into<String>,
{
self.ctx.baggage_item(&key.into())
}

fn set_operation_name(&mut self, _name: &str) {
unimplemented!()
}

fn operation_name(&self) -> Option<&str> {
unimplemented!()
}

fn finish(self) -> FinishedSpan<Self::Context> {
unimplemented!()
}

fn finish_at(self, _timestamp: u64) -> FinishedSpan<Self::Context> {
unimplemented!()
}
}

#[cfg(test)]
mod tests {

use super::MockSpanContext;
use opentracing_api::SpanContext;
use super::{MockSpan, MockSpanContext};
use opentracing_api::{Span, SpanContext, TagValue};
use std::collections::HashMap;

#[test]
Expand All @@ -48,4 +153,26 @@ mod tests {
assert_eq!(None, iter.next());
}

#[test]
fn test_set_get_unset_tag() {
let mut span = MockSpan::new();
assert_eq!(None, span.tag("key"));
span.set_tag("key", TagValue::String("some content".into()));
assert_eq!(
Some(&TagValue::String("some content".into())),
span.tag("key")
);
span.unset_tag("key");
assert_eq!(None, span.tag("key"));
}

#[test]
fn test_set_get_baggage() {
let mut span = MockSpan::new();
assert_eq!(None, span.baggage_item("key"));
span.set_baggage_item("key", "value".into());
assert_eq!(Some(&String::from("value")), span.baggage_item("key"));
span.unset_baggage_item("key");
assert_eq!(None, span.baggage_item("key"));
}
}
Loading

0 comments on commit 77f7cc2

Please sign in to comment.