Forge documentation
Library referenceRust

forge-telemetry

ANVIL Telemetry Contract: span collection, audit trails, and observability for the Forge SDK

ANVIL Telemetry Contract: span collection, audit trails, and observability for the Forge SDK

Package contract

FieldValue
Languagerust
Source version0.2.0
Manifestforge-rs/crates/forge-telemetry/Cargo.toml
Source files6
EvidenceSource reference; registry publication and runtime conformance are separate checks

Import boundary

use forge_telemetry;

Use a source checkout or your verified private registry. Manifest coordinates identify the package; they do not establish that a public registry release exists.

Crate boundary

The following entries are taken from src/lib.rs. Feature conditions in the exact source still apply.

pub mod audit;

pub mod collector;

pub mod contract;

pub mod error;

pub mod signed_audit;

pub mod prelude;

pub use crate::audit::{AuditEntry, AuditTrail};

pub use crate::collector::{
        CompletedSpan, InMemoryCollector, InMemoryTelemetry, NoopCollector, SpanCollector,
    };

pub use crate::contract::{AuditEvent, NoopTelemetry, SpanId, TelemetryContract};

pub use crate::error::TelemetryError;

pub use crate::signed_audit::{SignedAuditEntry, SignedAuditTrail};

Feature flags

FeatureEnables
defaultsigned-audit
signed-auditdep:forge-identity

Source reference

Download package reference JSON. Each original source file and generated declaration artifact has its own SHA-256 digest. Function bodies and constant values are omitted from downloads. These are source declaration inventories, not compiler-resolved rustdoc, TypeDoc, DocC, or Dokka output. Private modules can contain public declarations that are not reachable through the package boundary; consult the entry point before importing.

audit.rs

Read declaration text · 10 declaration entries

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditEntry {
/// Sequential index in the trail (0-based).

pub index: usize,
/// The audit event.

pub event: AuditEvent
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditTrail {

}

pub fn new(agent_did: String) -> Self;

pub fn append(&mut self, event: AuditEvent);

pub fn entries(&self) -> &[AuditEntry];

pub fn len(&self) -> usize;

pub fn is_empty(&self) -> bool;

pub fn last(&self) -> Option<&AuditEntry>;

pub fn agent_did(&self) -> &str;

pub fn filter_by_kind(&self, kind: &AuditEventKind) -> Vec<&AuditEntry>;

collector.rs

Read declaration text · 12 declaration entries

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompletedSpan {
/// The unique identifier for this span.

pub span_id: SpanId,
/// The span name (e.g., `"anvil.generate"`, `"anvil.tool.invoke"`).

pub name: String,
/// Key-value attributes associated with this span.

pub attributes: Vec<(String, String)>,
/// ISO 8601 timestamp of when the span was started.

pub start_time: String,
/// ISO 8601 timestamp of when the span was ended.

pub end_time: String,
/// The agent's OAS DID, if available.

pub agent_did: Option<String>
}

pub trait SpanCollector: Send + Sync {
    /// Record a completed span.
    ///
    /// # Arguments
    ///
    /// * `span` - The completed span to record.
    fn record_span(&self, span: CompletedSpan);

    /// Retrieve all recorded spans.
    ///
    /// # Returns
    ///
    /// A vector of all completed spans recorded so far.
    fn spans(&self) -> Vec<CompletedSpan>;

    /// Clear all recorded spans.
    fn clear(&self);

    /// Number of recorded spans.
    fn len(&self) -> usize;

    /// Returns `true` if no spans have been recorded.
    fn is_empty(&self) -> bool;
}

pub struct NoopCollector;

pub struct InMemoryCollector {

}

pub fn new() -> Self;

pub struct InMemoryTelemetry {

}

pub fn new(agent_did: Option<String>) -> Self;

pub fn completed_spans(&self) -> Vec<CompletedSpan>;

pub fn events(&self) -> Vec<AuditEvent>;

pub fn clear(&self);

pub fn span_count(&self) -> usize;

pub fn event_count(&self) -> usize;

contract.rs

Read declaration text · 9 declaration entries

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SpanId(pub String);

pub fn generate() -> Self;

pub fn from_string(id: String) -> Self;

pub fn as_str(&self) -> &str;

pub trait TelemetryContract: Send + Sync {
    /// Start a new span with the given name and attributes.
    ///
    /// Returns a `SpanId` that must be passed to `end_span` when the
    /// operation completes.
    ///
    /// # Arguments
    ///
    /// * `name` - The span name (use dotted notation, e.g., `"anvil.generate"`).
    /// * `attributes` - Key-value pairs of span attributes.
    ///
    /// # Returns
    ///
    /// A unique `SpanId` for the started span.
    fn start_span(&self, name: &str, attributes: &[(&str, &str)]) -> SpanId;

    /// End a previously started span.
    ///
    /// Marks the span as completed with the current timestamp. If the span
    /// has already been ended, the behavior is implementation-defined (some
    /// implementations may silently ignore, others may log a warning).
    ///
    /// # Arguments
    ///
    /// * `span_id` - The ID returned by `start_span`.
    fn end_span(&self, span_id: &SpanId);

    /// Emit an audit event for the agent's audit trail.
    ///
    /// Events are buffered until `flush` is called, or may be written
    /// immediately depending on the implementation.
    ///
    /// # Arguments
    ///
    /// * `event` - The audit event to record.
    fn emit_event(&self, event: AuditEvent);

    /// Flush any buffered telemetry data to the backend.
    ///
    /// # Errors
    ///
    /// Returns `TelemetryError::FlushFailed` if the flush operation fails.
    fn flush(&self) -> Result<(), TelemetryError>;
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditEvent {
/// The kind of event.

pub kind: AuditEventKind,
/// The agent's OAS DID.

pub agent_did: String,
/// ISO 8601 timestamp of when the event occurred.

pub timestamp: String,
/// Event-specific details as a JSON value.

pub details: serde_json::Value,
/// Ed25519 signature (hex-encoded), if signed.

pub signature: Option<String>
}

pub fn new(kind: AuditEventKind, agent_did: String, details: serde_json::Value) -> Self;

pub fn with_signature(mut self, signature: String) -> Self;

pub struct NoopTelemetry;

error.rs

Read declaration text · 1 declaration entries

#[derive(Debug, Error)]
pub enum TelemetryError {
    /// A span with the given ID was not found in the collector.
    #[error("span '{span_id}' not found in telemetry collector")]
    SpanNotFound {
        /// The span ID that was not found.
        span_id: String,
    },

    /// An attempt was made to close a span that is already closed.
    #[error("span '{span_id}' has already been closed and cannot be ended again")]
    SpanAlreadyClosed {
        /// The span ID that was already closed.
        span_id: String,
    },

    /// An audit entry failed validation.
    #[error("audit entry is invalid: {reason}")]
    AuditEntryInvalid {
        /// The reason the entry is invalid.
        reason: String,
    },

    /// The audit trail integrity check failed at the given index.
    #[error("audit trail corrupted at index {index}: {reason}")]
    AuditTrailCorrupted {
        /// The index where corruption was detected.
        index: usize,
        /// The reason for the corruption.
        reason: String,
    },

    /// Flushing buffered telemetry data to the backend failed.
    #[error("failed to flush telemetry data: {reason}")]
    FlushFailed {
        /// The reason the flush failed.
        reason: String,
    },

    /// The span collector has reached its capacity limit.
    #[error("telemetry collector is full (capacity: {capacity} spans)")]
    CollectorFull {
        /// The maximum number of spans the collector can hold.
        capacity: usize,
    },

    /// Exporting telemetry data to an external system failed.
    #[error("failed to export telemetry data: {reason}")]
    ExportFailed {
        /// The reason the export failed.
        reason: String,
    },

    /// An audit trail signature or hash chain verification failed.
    ///
    /// This indicates either a tampered entry, a wrong signer, or a
    /// corrupted hash chain in the signed audit trail.
    ///
    /// # ANVIL Spec §14.2
    #[error("audit trail verification failed: {reason}")]
    AuditVerificationFailed {
        /// Human-readable description of the verification failure.
        reason: String,
    },
}

lib.rs

Read declaration text · 11 declaration entries

pub mod audit;

pub mod collector;

pub mod contract;

pub mod error;

pub mod signed_audit;

pub mod prelude;

pub use crate::audit::{AuditEntry, AuditTrail};

pub use crate::collector::{
        CompletedSpan, InMemoryCollector, InMemoryTelemetry, NoopCollector, SpanCollector,
    };

pub use crate::contract::{AuditEvent, NoopTelemetry, SpanId, TelemetryContract};

pub use crate::error::TelemetryError;

pub use crate::signed_audit::{SignedAuditEntry, SignedAuditTrail};

signed_audit.rs

Read declaration text · 14 declaration entries

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedAuditEntry {
/// Sequential index in the trail (0-based).

pub index: usize,
/// The audit event data.

pub event: AuditEvent,
/// BLAKE3 hash of the previous entry (or genesis hash for index 0).

pub previous_hash: String,
/// Hex-encoded 64-byte Ed25519 signature over the canonical content.

pub signature_hex: String,
/// BLAKE3 hash of this entry's signed content (used as `previous_hash` by the next entry).

pub entry_hash: String
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedAuditTrail {

}

#[cfg(feature = "signed-audit")]
pub fn new(identity: &forge_identity::agent_identity::ForgeAgentIdentity) -> Self;

pub fn from_parts(agent_did: String, verifying_key_hex: String) -> Self;

#[cfg(feature = "signed-audit")]
pub fn append_signed(
        &mut self,
        event: AuditEvent,
        identity: &forge_identity::agent_identity::ForgeAgentIdentity,
    );

pub fn verify_entry(&self, index: usize) -> Result<(), TelemetryError>;

pub fn verify_all(&self) -> Result<(), TelemetryError>;

pub fn entries(&self) -> &[SignedAuditEntry];

pub fn len(&self) -> usize;

pub fn is_empty(&self) -> bool;

pub fn last(&self) -> Option<&SignedAuditEntry>;

pub fn agent_did(&self) -> &str;

pub fn verifying_key_hex(&self) -> &str;

pub fn filter_by_kind(&self, kind: &AuditEventKind) -> Vec<&SignedAuditEntry>;

Continue

On this page