Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layer: Document all public items #3

Merged
merged 2 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions crates/layer/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,25 @@ pub enum Error {
/// A generic C++ exception occurred in the C++ code.
#[error("C++ code threw an exception: {0}")]
Cxx(#[from] cxx::Exception),
/// A generic OS-level IO error occurred.
#[error("IO error: {0}")]
IO(#[from] io::Error),
/// An internal `Mutex` is poisoned due to some other thread panicking while
/// holding the mutex.
#[error("Encountered a poisoned mutex")]
PoisonedMutex,
/// An operation can't complete because someone already called
/// `layer.stop()` on the layer.
#[error("The layer has been stopped")]
LayerStopped,
/// An operation timed out according to one of the timeouts set in the layer
/// builder.
#[error("Failed to complete operation before timeout was reached")]
TimedOut,
/// A flush failed due to some unknown reason.
///
/// This is not necessarily separate from the `TimedOut` case; we simply
/// don't know the reason why the flush failed.
#[error("Failed to flush data due to some unknown reason (might also be due to timeout)")]
FlushFailed,
}
Expand Down
59 changes: 59 additions & 0 deletions crates/layer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![deny(clippy::all)]
#![deny(missing_docs)]
//! # `tracing-perfetto-sdk-layer`
//! A suite of tracing layers that reports traces via the C++ Perfetto SDK
//!
Expand Down Expand Up @@ -35,6 +36,35 @@
//! });
//! ```
//!
//! ## Trace config
//!
//! The layer constructor expects a `TraceConfig` protobuf message to configure
//! tracing settings. This can either be supplied as a `prost`-generated struct
//! or as raw (protobuf-encoded) bytes. The raw bytes option might be useful if
//! you want to embed a config with your binary that doesn't have to change, and
//! you want to save on space/overhead/... In the end the config will
//! always be encoded to bytes anyway to be sent to the C++ SDK.
//!
//! Since the protobuf schema also implements `serde` traits, you can load/store
//! the config file in any format you like, as long as there is a `serde` codec
//! for it. To activate the `tracing` data source, you need to add at least the
//! `rust_tracing` data source in the relevant config section (here, the config
//! is in YAML format):
//!
//! ```yaml
//! buffers:
//! - size_kb: 1024
//! data_sources:
//! - config:
//! name: "rust_tracing"
//! ```
//!
//! This is a good starting point for a minimal config file. If you want to
//! activate additional data sources, you can add them here; just remember that
//! most of them rely on the `traced daemon running on the host, and requires
//! you to use system mode (Explained further below in the section "Controlling
//! output destinations").
//!
//! ## Using counters
//!
//! When logging trace events, such as when calling `tracing::info!()` and
Expand All @@ -55,6 +85,9 @@
//! tracing::info!(counter.mem_usage.bytes=42, counter.cpu_usage.percent=23.2, "hi!");
//! ```
//!
//! The unit will be reported properly in the Perfetto UI at the track-level
//! next to the sidebar of each line chart.
//!
//! **NOTE**: at the time of writing, counters are only implemented by the
//! [`NativeLayer`].
//!
Expand Down Expand Up @@ -99,6 +132,32 @@
//! system's `traced` daemon, or (in the case of [`NativeLayer`]) poll for
//! system-wide traces from the `traced` daemon and include them in the trace
//! file.
//!
//! ## Sharing
//!
//! Layers are cloneable and will internally keep a reference count to keep the
//! layer internals alive. This means you can make a clone of the layer to
//! control it from many places at once. For example, it can be useful to have a
//! clone of the layer to be able to call `.flush()` or `.stop()` from somewhere
//! else.
//!
//! ## Timeouts
//!
//! The layers allow you to configure various timeouts that will be used
//! throughout the lifecycle of a layer. These are:
//!
//! * `drop_flush_timeout`: When the layer is dropped: how long to wait for a
//! final flush to complete before destroying the layer. If you want to
//! avoid this cost during `drop()`, call `.stop()` manually before the
//! layer is dropped.
//! * `background_flush_timeout`: In the case of [`NativeLayer`], a background
//! thread is used to fetch data from the SDK into the Rust world. This
//! controls how long we wait for each flush to complete; however, if it
//! doesn't complete in time, another attempt will soon be made.
//! * `background_poll_timeout`: How long to wait for new data to arrive
//! during each attempt of the background thread.
//! * `background_poll_interval`: How long to wait between attempts to poll
//! for new data in the background thread.

// Internal modules:
mod debug_annotations;
Expand Down
33 changes: 33 additions & 0 deletions crates/layer/src/native_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub struct NativeLayer<W> {
inner: sync::Arc<Inner<W>>,
}

/// A builder for [`NativeLayer`]; use [`NativeLayer::from_config`] or
/// [`NativeLayer::from_config_bytes`] to create a new instance.
pub struct Builder<'c, W> {
config_bytes: borrow::Cow<'c, [u8]>,
writer: W,
Expand Down Expand Up @@ -65,11 +67,26 @@ impl<W> NativeLayer<W>
where
W: for<'w> fmt::MakeWriter<'w> + Send + Sync + 'static,
{
/// Create a new layer builder from the supplied proto config.
///
/// The proto config is usually read from an external source using the
/// prototext syntax, or else using one of the `serde` codecs. The config
/// will internally be encoded to bytes straight away, so prefer
/// [`NativeLayer::from_config_bytes`] if you already have the byte
/// representation.
///
/// The built layer will write traces to the supplied writer.
pub fn from_config(config: schema::TraceConfig, writer: W) -> Builder<'static, W> {
use prost::Message as _;
Builder::new(config.encode_to_vec().into(), writer)
}

/// Create a new layer builder from the supplied proto config bytes.
///
/// The proto config bytes needs to be an already encoded message of type
/// [`schema::TraceConfig`].
///
/// The built layer will write traces to the supplied writer.
pub fn from_config_bytes(config_bytes: &[u8], writer: W) -> Builder<W> {
Builder::new(config_bytes.into(), writer)
}
Expand Down Expand Up @@ -181,10 +198,13 @@ where
}
}

/// Flush internal buffers, making the best effort for all pending writes to
/// be visible on this layer's `writer`.
pub fn flush(&self, timeout: time::Duration) -> error::Result<()> {
self.inner.flush(timeout)
}

/// Stop the layer and stop collecting traces.
pub fn stop(&self) -> error::Result<()> {
self.inner.stop()
}
Expand Down Expand Up @@ -633,26 +653,36 @@ where
}
}

/// If `Some`, force the specified trace flavor. If `None`, use heuristics
/// for every created span to determine the flavor.
pub fn with_force_flavor(mut self, force_flavor: Option<flavor::Flavor>) -> Self {
self.force_flavor = force_flavor;
self
}

/// Enable in-process collection, where traces will be collected by buffers
/// in the Perfetto SDK and spilled to file in-process.
pub fn with_enable_in_process(mut self, enable_in_process: bool) -> Self {
self.enable_in_process = enable_in_process;
self
}

/// Enable system collection, where traces will be sent/collected from the
/// `traced` daemon, and additional system-wide data sources (such as
/// `ftrace`, `procfs`, `sysfs`, etc.) can be collected too.
pub fn with_enable_system(mut self, enable_system: bool) -> Self {
self.enable_system = enable_system;
self
}

/// The timeout of the final flush that will happen when dropping this
/// layer.
pub fn with_drop_flush_timeout(mut self, drop_flush_timeout: time::Duration) -> Self {
self.drop_flush_timeout = drop_flush_timeout;
self
}

/// The timeout of each flush in the background trace polling thread.
pub fn with_background_flush_timeout(
mut self,
background_flush_timeout: time::Duration,
Expand All @@ -661,11 +691,13 @@ where
self
}

/// The timeout of each poll in the background trace polling thread.
pub fn with_background_poll_timeout(mut self, background_poll_timeout: time::Duration) -> Self {
self.background_poll_timeout = background_poll_timeout;
self
}

/// The delay between each poll in the background trace polling thread.
pub fn with_background_poll_interval(
mut self,
background_poll_interval: time::Duration,
Expand All @@ -674,6 +706,7 @@ where
self
}

/// Turn this builder into a built layer.
pub fn build(self) -> error::Result<NativeLayer<W>> {
NativeLayer::build(self)
}
Expand Down
44 changes: 39 additions & 5 deletions crates/layer/src/sdk_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ pub struct SdkLayer {
inner: sync::Arc<Inner>,
}

/// A builder for [`SdkLayer`]; use [`SdkLayer::from_config`] or
/// [`SdkLayer::from_config_bytes`] to create a new instance.
pub struct Builder<'c> {
config_bytes: borrow::Cow<'c, [u8]>,
output_file: Option<fs::File>,
Expand Down Expand Up @@ -46,6 +48,18 @@ struct Inner {
}

impl SdkLayer {
/// Create a new layer builder from the supplied proto config.
///
/// The proto config is usually read from an external source using the
/// prototext syntax, or else using one of the `serde` codecs. The config
/// will internally be encoded to bytes straight away, so prefer
/// [`NativeLayer::from_config_bytes`] if you already have the byte
/// representation.
///
/// The built layer will write traces to the supplied output file. If no
/// file is specified, it is probably only useful to run in system mode, so
/// that the traces are sent to the `traced` daemon instead (else they would
/// just get lost).
pub fn from_config(
config: schema::TraceConfig,
output_file: Option<fs::File>,
Expand All @@ -54,6 +68,15 @@ impl SdkLayer {
Builder::new(config.encode_to_vec().into(), output_file)
}

/// Create a new layer builder from the supplied proto config bytes.
///
/// The proto config bytes needs to be an already encoded message of type
/// [`schema::TraceConfig`].
///
/// The built layer will write traces to the supplied output file. If no
/// file is specified, it is probably only useful to run in system mode, so
/// that the traces are sent to the `traced` daemon instead (else they would
/// just get lost).
pub fn from_config_bytes(config_bytes: &[u8], output_file: Option<fs::File>) -> Builder {
Builder::new(config_bytes.into(), output_file)
}
Expand Down Expand Up @@ -183,10 +206,13 @@ impl SdkLayer {
)
}

/// Flush internal buffers, making the best effort for all pending writes to
/// be visible on this layer's `output_file`.
pub fn flush(&self, timeout: time::Duration) -> error::Result<()> {
self.inner.flush(timeout)
}

/// Stop the layer and stop collecting traces.
pub fn stop(&self) -> error::Result<()> {
self.inner.stop()
}
Expand Down Expand Up @@ -354,21 +380,29 @@ impl<'c> Builder<'c> {
}
}

pub fn with_drop_flush_timeout(mut self, drop_flush_timeout: time::Duration) -> Self {
self.drop_flush_timeout = drop_flush_timeout;
self
}

/// Enable in-process collection, where traces will be collected by buffers
/// in the Perfetto SDK and spilled to file in-process.
pub fn with_enable_in_process(mut self, enable_in_process: bool) -> Self {
self.enable_in_process = enable_in_process;
self
}

/// Enable system collection, where traces will be sent/collected from the
/// `traced` daemon, and additional system-wide data sources (such as
/// `ftrace`, `procfs`, `sysfs`, etc.) can be collected too.
pub fn with_enable_system(mut self, enable_system: bool) -> Self {
self.enable_system = enable_system;
self
}

/// The timeout of the final flush that will happen when dropping this
/// layer.
pub fn with_drop_flush_timeout(mut self, drop_flush_timeout: time::Duration) -> Self {
self.drop_flush_timeout = drop_flush_timeout;
self
}

/// Turn this builder into a built layer.
pub fn build(self) -> error::Result<SdkLayer> {
SdkLayer::build(self)
}
Expand Down