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
//! The `log!` macro and its level-specific convenience wrappers.
//!
//! Import the macros you need:
//! ```rust,ignore
//! use oculi::{log_info, log_warn, log_error};
//! ```
/// Emits a structured [`OculiEvent`](crate::OculiEvent) 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 = "__oculi_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 oculi::{log, LogLevel};
///
/// #[derive(AnchorSerialize, AnchorDeserialize)]
/// struct SwapExecuted { amount: u64 }
///
/// log!(LogLevel::Info, "swap_executed", SwapExecuted { amount: 500 });
/// ```
/// Emits an [`OculiEvent`](crate::OculiEvent) at
/// [`LogLevel::Debug`](crate::LogLevel::Debug).
///
/// Use for internal state snapshots that are too verbose for production.
///
/// # Example
///
/// ```rust,ignore
/// use oculi::log_debug;
/// log_debug!("reserves_snapshot", ReservesSnapshot { token_a: 1000, token_b: 2000 });
/// ```
/// Emits an [`OculiEvent`](crate::OculiEvent) at
/// [`LogLevel::Info`](crate::LogLevel::Info).
///
/// Use for meaningful instruction milestones that indexers should consume.
///
/// # Example
///
/// ```rust,ignore
/// use oculi::log_info;
/// log_info!("swap_executed", SwapExecuted { amount: 500, user: ctx.accounts.user.key() });
/// ```
/// Emits an [`OculiEvent`](crate::OculiEvent) 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 oculi::log_warn;
/// log_warn!("slippage_exceeded", SlippageWarning { bps: 150, limit_bps: 100 });
/// ```
/// Emits an [`OculiEvent`](crate::OculiEvent) 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 oculi::log_error;
/// log_error!("oracle_stale", OracleError { age_slots: 300 });
/// ```