[][src]Crate opentracingrust

An OpenTracing implementation for rust.

This crate provides a generic Tracer interface following the OpenTracing specification that allows users (libraries, framework, applications) to implement distributed tracing across ecosystems and without committing to a specific distributed tracer.

This means that:

  • Frameworks don't have to impose a tracer on applications.
  • Libraries can integrate their user's traces.
  • Applications lock end-users into a distributed tracer.

Official API heads up

An Opentracing official API is in the works: https://github.com/opentracing/opentracing-rust

Once the official API crate and utility crate are finished I hope to deprecate this crate in favour of the official crates.

For that reason, development of this crate will be limited while I dedicate my time to help with the development of the offical opentracing-api crate.

Lessons learend while developing this crate will be valuable knowledge for opentracing-api. If you find any issue and or usability limit, please let me know!

Architecture

At the core of this library are three types:

  • Tracer: an interface to create and serialise Spans.
  • Span: each instance represents an operation and its metadata.
  • SpanContext: a tracer-specific identifier of a Span.

Configuraing a Tracer

Application developers MUST read this, library and framework developers SHOULD still read it for completeness.

Every application and all the libraries and frameworks it uses share a single Tracer instance, unique to the entire process. The instance should be passed around using a dependency injection technique, of which there are many. This crate provides a GlobalTracer utility singleton for cases where dependency injections are not usable.

Configuration of the Tracer instance used across the process is the responsibility of the application and should be performed as soon as possible in the initialisation phase.

Tracers are implemented in separate crates and each tracers can be implemented as desired but there are two requirements of concrete tracers:

  • Initialisation returns instance of Tracer.
  • A crossbeam_channel::unbounded is used by the tracer to send FinishedSpans to a reporting thread.

The reporting thread is responsible for pushing the spans to the distributed tracer of choice.

In code:

extern crate opentracingrust;

use std::time::Duration;

use opentracingrust::tracers::NoopTracer;
use opentracingrust::utils::GlobalTracer;
use opentracingrust::utils::ReporterThread;


fn main() {
    let (tracer, receiver) = NoopTracer::new();
    let reporter = ReporterThread::new_with_duration(
        receiver, Duration::from_millis(50), NoopTracer::report
    );
    GlobalTracer::init(tracer);

    // ... snip ...
}

Tracing an operation

Now that a Tracer is configured and we are sending FinishedSpans to a distributed tracing software, it is possible to trace operations.

Tracing operations is done by:

  • Creating a named Span that represents the operation.
  • Attaching causality information with SpanContexts.
  • Adding any needed metadata.
  • Finishing the span once the operation is done.
extern crate opentracingrust;

use std::time::Duration;

use opentracingrust::SpanContext;
use opentracingrust::StartOptions;

use opentracingrust::tracers::NoopTracer;
use opentracingrust::utils::GlobalTracer;
use opentracingrust::utils::ReporterThread;


fn main() {
    let (tracer, receiver) = NoopTracer::new();
    let reporter = ReporterThread::new_with_duration(
        receiver, Duration::from_millis(50), NoopTracer::report
    );
    GlobalTracer::init(tracer);
    // Once the tracer is configured we can start working.
    start_working();
}

fn start_working() {
    let mut root_span = GlobalTracer::get().span("start_working");
    // The actual work is done in a sub-operation.
    do_work(root_span.context().clone());
    root_span.finish();
}

fn do_work(context: SpanContext) {
    let mut span = GlobalTracer::get().span_with_options(
        "do_work", StartOptions::default().child_of(context)
    );
    // ... do work ...
    span.finish();
}

The examples/ directoy includes many more working end-to-end examples of different use cases.

The NoopTracer

As mentioned above, the crate does not provide concrete Tracers but rather a standard interface for projects to bind against.

The NoopTracer is the perfect tool to write tests with and a good default for examples and projects that do not yet implement full tracing support.

Modules

tracers
utils

Structs

AutoFinishingSpan

A Span wrapper that finishes a span when dropped.

FinishedSpan

A Span that represents a finished operation.

ImplContextBox

Utility structure to create ImplContexts.

Log

Structured logging information to attach to spans.

Span

Model of an in progress operation.

SpanContext

Trecer-specific span and trace identifier and metadata.

StartOptions

Additional options that are passed to Tracer::span.

Tracer

The library users interface to tracing.

Enums

Error

Enumeration of all errors returned by OpenTracingRust.

ExtractFormat

SpanContext extraction format and source.

InjectFormat

SpanContext injection format and destination.

LogValue

Enumeration of valid types for log values.

SpanReference

Enumerates all known relationships among SpanContexts.

TagValue

Enumeration of valid types for tag values.

Traits

ImplContext

Tracer implementation's context details.

MapCarrier

Interface for HTTP header and text map carriers.

SpanReferenceAware

Trait for structures that want to be wrapped in ImplContextBoxs.

TracerInterface

Smallest set of operations that a concrete tracer must implement.

Type Definitions

Result

Type alias for Results that can fail with an OpenTracingRust Error.

SpanReceiver

Type alias for an crossbeam_channel::Receiver of FinishedSpans.

SpanSender

Type alias for an crossbeam_channel::Sender of FinishedSpans.