Crate chronograph

Source
Expand description

§Overview

A tracing library that allows you to efficiently record timestamps and metadata as datapoints within a span.

The Chronograph is the main entry point for starting spans.

Spans are recorded when they are dropped from memory where an underlying SpanRecorder is responsible for recording a span’s data.

§Spans

All spans contain a unique monotonically increasing ID, a start unix time, a start instant, an end instant, and user datapoints.

  • The start unix time is the unix time at the start of the span.
  • The start instant is a monotonic instant, accurate nanosecond timer elapsed from when the Cronograph was started.
  • The start instant can be used to calculate the duration of the span.
  • The end instant is a monotonic instant, accurate nanosecond timer elapsed from when the Cronograph was started.
  • User datapoints are typically recorded as “instant” time measurements, but they can also include metadata as simple types.

§Datapoints

User datapoints are recorded as a set of key-value pairs.

The DatapointId key is serialized as a u64 value.

  • Any impl Into<DatapointId> can be used as a datapoint.
  • A u64 will be used as-is.
  • A &str will be converted to a u64 using zwohash to derive a one-way, consistent u64 value.

The RecordValue can be one of the following types:

  • Instant: A monotonic instant, accurate nanosecond timer elapsed from when the Cronograph was started.
  • UnixTime: A unix time, as nanoseconds since epoch.
  • Utf8String: A string value formatted as UTF-8.
  • I32: A 32-bit signed integer.
  • I64: A 64-bit signed integer.
  • I128: A 128-bit signed integer.
  • U32: A 32-bit unsigned integer.
  • U64: A 64-bit unsigned integer.
  • U128: A 128-bit unsigned integer.
  • F32: A 32-bit floating point number.
  • F64: A 64-bit floating point number.

§Sampling

Spans can elect to be sampled. It is most efficient to use a sampling rate that is a power of two.

§Global Chronograph

The global chronograph is a singleton that can be used to record spans.

It is initialized by calling the init function, and can be accessed with the global function.

§Macros

The macros module provides macros for recording datapoints.

§Thread-local Spans

Thread-local spans can be used to record spans without needing to keep a reference to the Span. These are the same thread-local spans used by the macros module.

A thread-local span can be started with the global chronograph by calling the start_threadlocal_span function. You may alternative set it to any arbitraty span using the set_threadlocal_span function.

The thread-local span can be accessed with the get_threadlocal_span function or with the included macros.

end_threadlocal_span and take_threadlocal_span can be used to end/take the current thread-local span

§Global Instance Example with Macros

use std::time::Duration;
use std::thread::sleep;

use chronograph::macros::*;
use chronograph::recorder::batch::*;
use chronograph::schema::*;
use chronograph::Chronograph;

// Create a batching span recorder that will print each batch.
// Your code should elect to store the results somewhere.
// The collect callback function is called from a dedicated collector thread.
let recorder = BatchingSpanRecorder::start(
    Box::new(|batch: SpanBatch| {
        let serialized: Vec<u8> = batch.into();
        let deserialized = SpanBatch::try_from(serialized.as_slice()).unwrap();
        println!("collected {:?}", deserialized);
        println!("serialized to {} bytes", serialized.len());
    }),
    BatchCollectionOptions::default().with_batch_size_threshold(4),
);

// Initialize the global chronograph and record some random spans.
chronograph::init(
    Chronograph::builder()
        .with_recorder(recorder)
        .with_sample_rate(16) // it's most efficient to sample at a power of two
        .build(),
);

// Record some random data
for _ in 0..1000 {
    start_span!();
    record_instant!("my_op_start");
    record_value!("count", 42);
    record_instant!("mt_op_end");
    end_span!();
    sleep(Duration::from_millis(1));
}

// Give the collector thread a chance to wakeup and batch spans.
sleep(Duration::from_millis(100));

§Zero-Magic Example

Example without macros or global instances.

use chronograph::recorder::batch::*;
use chronograph::schema::*;
use chronograph::Chronograph;
use std::thread::sleep;
use std::time::Duration;

// Create a batching span recorder that will print each batch.
// Your code should elect to store the results somewhere.
// The collect callback function is called from a dedicated collector thread.
let recorder = BatchingSpanRecorder::start(
    Box::new(|batch: SpanBatch| {
        let serialized: Vec<u8> = batch.into();
        let deserialized = SpanBatch::try_from(serialized.as_slice()).unwrap();
        println!("collected {:?}", deserialized);
        println!("serialized to {} bytes", serialized.len());
    }),
    BatchCollectionOptions::default().with_batch_size_threshold(4),
);

// Create a chronograph and record some random spans.
let chronograph = Chronograph::builder()
    .with_recorder(recorder)
    .with_sample_rate(16) // it's most efficient to sample at a power of two
    .build();

// Record some random data
for _ in 0..1000 {
    let mut span = chronograph.start_span();
    span.record_instant("my_op_start");
    span.record_value("count", 42);
    span.record_instant("my_op_end");
    sleep(Duration::from_millis(1));
}

// Give the collector thread a chance to wakeup and batch spans.
sleep(Duration::from_millis(100));

Re-exports§

pub use chronograph_macros as macros;

Modules§

processor
Traits for user to hook into completed spans by reference.
recorder
schema
Serialization and deserialization of chronograph data, utilizing rkyv for fast serialization and deserialization.

Structs§

Chronograph
The main chronograph struct, which is used to start spans.
ChronographBuilder
Created using Chronograph::builder
Span
A span records a set of related datapoints. The span data is recorded when the span is dropped from memory.

Functions§

end_threadlocal_span
Explicitly end the current thread-local span, dropping it from memory if it existed.
get_threadlocal_span
Get a mutable reference to the current thread-local span. If no span exists, a new one will be automatically created using the global chronograph. This ensures that a valid span is always available.
global
Get a reference to the global chronograph. If init has not been called, a no-op chronograph will be returned.
init
Initialize the global chronograph.
set_threadlocal_span
Set the current thread-local span.
start_threadlocal_span
Start a new current thread-local span from the global chronograph.
take_threadlocal_span
Take the current thread-local span, leaving None in its place.