1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! The `sol_log!` macro and its level-specific convenience wrappers.
//!
//! Import the macros you need:
//! ```rust,ignore
//! use soltrace::{sol_info, sol_warn, sol_error};
//! ```
/// Emits a structured [`SolTraceEvent`](crate::SolTraceEvent) with a
/// Borsh-serialized payload.
///
/// # Arguments
///
/// * `$level` — a [`LogLevel`](crate::LogLevel) variant
/// * `$event_name` — any expression implementing `ToString`; use a string
/// literal for zero runtime overhead
/// * `$payload` — any value implementing `borsh::BorshSerialize`
///
/// # Serialization failure
///
/// If Borsh serialization of `$payload` fails, a sentinel event with
/// `event_name = "__soltrace_serialization_error"` and an empty payload is
/// emitted. The failure is observable off-chain without panicking on-chain.
///
/// # devnet-only feature
///
/// When the `devnet-only` Cargo feature is enabled on this crate, the entire
/// macro body compiles to a no-op. Enable it in production builds to achieve
/// zero logging overhead; omit it in devnet/test builds to restore
/// observability.
///
/// # Example
///
/// ```rust,ignore
/// use anchor_lang::prelude::*;
/// use soltrace::{sol_log, LogLevel};
///
/// #[derive(AnchorSerialize, AnchorDeserialize)]
/// struct SwapExecuted { amount: u64 }
///
/// sol_log!(LogLevel::Info, "swap_executed", SwapExecuted { amount: 500 });
/// ```
/// Emits a [`SolTraceEvent`](crate::SolTraceEvent) at
/// [`LogLevel::Trace`](crate::LogLevel::Trace).
///
/// Use for fine-grained entry/exit tracing during development.
/// Disable in production via `soltrace = { features = ["devnet-only"] }`.
///
/// # Example
///
/// ```rust,ignore
/// use soltrace::sol_trace;
/// sol_trace!("fn_enter", FnEnter { instruction: 1 });
/// ```
/// Emits a [`SolTraceEvent`](crate::SolTraceEvent) at
/// [`LogLevel::Debug`](crate::LogLevel::Debug).
///
/// Use for internal state snapshots that are too verbose for production.
///
/// # Example
///
/// ```rust,ignore
/// use soltrace::sol_debug;
/// sol_debug!("reserves_snapshot", ReservesSnapshot { token_a: 1000, token_b: 2000 });
/// ```
/// Emits a [`SolTraceEvent`](crate::SolTraceEvent) at
/// [`LogLevel::Info`](crate::LogLevel::Info).
///
/// Use for meaningful instruction milestones that indexers should consume.
///
/// # Example
///
/// ```rust,ignore
/// use soltrace::sol_info;
/// sol_info!("swap_executed", SwapExecuted { amount: 500, user: ctx.accounts.user.key() });
/// ```
/// Emits a [`SolTraceEvent`](crate::SolTraceEvent) at
/// [`LogLevel::Warn`](crate::LogLevel::Warn).
///
/// Use when something unexpected occurred but the instruction can continue.
/// Off-chain monitors should alert on warn events.
///
/// # Example
///
/// ```rust,ignore
/// use soltrace::sol_warn;
/// sol_warn!("slippage_exceeded", SlippageWarning { bps: 150, limit_bps: 100 });
/// ```
/// Emits a [`SolTraceEvent`](crate::SolTraceEvent) at
/// [`LogLevel::Error`](crate::LogLevel::Error).
///
/// Use when a specific sub-operation fails but the instruction recovers and
/// returns `Ok(())`. If the instruction is about to return `Err`, emit this
/// first so the failure is recorded before the transaction reverts.
///
/// # Example
///
/// ```rust,ignore
/// use soltrace::sol_error;
/// sol_error!("oracle_stale", OracleError { age_slots: 300 });
/// ```