soltrace 0.1.1

Structured, Borsh-serialized Anchor events as a drop-in replacement for msg! in Solana programs.
Documentation
//! SolTrace — structured, Borsh-serialized Anchor events for Solana programs.
//!
//! ## Why this exists
//!
//! Solana programs rely on `msg!` for observability, but `msg!` performs string
//! formatting on-chain. For a swap instruction logging an amount and a pubkey,
//! `msg!` costs roughly 11,000 CU. SolTrace replaces that with a single
//! `emit!` call over a Borsh-serialized struct, cutting the same log entry to
//! ~781 CU — a 92.96% reduction.
//!
//! The emitted events are standard Anchor events, visible as `Program data:`
//! entries in transaction metadata and decodable by any Borsh-aware client.
//!
//! ## Quick start
//!
//! ```rust,ignore
//! use anchor_lang::prelude::*;
//! use soltrace::{sol_info, sol_warn};
//!
//! #[derive(AnchorSerialize, AnchorDeserialize)]
//! pub struct SwapExecuted {
//!     pub amount: u64,
//!     pub user: Pubkey,
//! }
//!
//! pub fn swap(ctx: Context<Swap>, amount: u64) -> Result<()> {
//!     sol_info!("swap_executed", SwapExecuted {
//!         amount,
//!         user: ctx.accounts.user.key(),
//!     });
//!     Ok(())
//! }
//! ```
//!
//! ## Feature flags
//!
//! | Flag | Default | Effect |
//! |------|---------|--------|
//! | `devnet-only` | off | Compiles out all `emit!` calls. Enable in mainnet builds. |
//! | `no-entrypoint` | off | Passes through to `anchor-lang/no-entrypoint`. |

#![deny(missing_docs)]
#![deny(clippy::unwrap_used)]

pub mod event;
pub mod level;
mod macros;

pub use event::SolTraceEvent;
pub use level::LogLevel;

/// Semi-private API used by the `sol_log!` macro family.
///
/// Items in this module are not covered by semver stability guarantees.
/// Do not call them directly.
#[doc(hidden)]
pub mod __private {
    use super::SolTraceEvent;

    /// Emits `event` via Anchor's `emit!` infrastructure.
    ///
    /// When the `devnet-only` feature is enabled this is a no-op, so the
    /// entire logging path — including payload serialization — is compiled out
    /// by the macro before this function is even called.
    #[cfg(not(feature = "devnet-only"))]
    #[inline(always)]
    pub fn emit_event(event: SolTraceEvent) {
        anchor_lang::prelude::emit!(event);
    }

    /// No-op variant active when `devnet-only` feature is enabled.
    ///
    /// The macro passes a fully constructed `SolTraceEvent` here, but since
    /// this function is a no-op, LLVM eliminates the call and all upstream
    /// allocations during optimization.
    #[cfg(feature = "devnet-only")]
    #[inline(always)]
    pub fn emit_event(_event: SolTraceEvent) {}
}