light_instruction_decoder/
config.rs

1//! Configuration types for enhanced logging
2
3use std::sync::Arc;
4
5use serde::{Deserialize, Serialize};
6
7use crate::{registry::DecoderRegistry, InstructionDecoder};
8
9/// Configuration for enhanced transaction logging
10#[derive(Debug, Serialize, Deserialize)]
11pub struct EnhancedLoggingConfig {
12    /// Whether enhanced logging is enabled
13    pub enabled: bool,
14    /// Whether to log events to console (file logging is always enabled when enhanced_logging.enabled = true)
15    pub log_events: bool,
16    /// Level of detail in logs
17    pub verbosity: LogVerbosity,
18    /// Show account changes before/after transaction
19    pub show_account_changes: bool,
20    /// Decode Light Protocol specific instructions
21    pub decode_light_instructions: bool,
22    /// Show compute units consumed per instruction
23    pub show_compute_units: bool,
24    /// Use ANSI colors in output
25    pub use_colors: bool,
26    /// Maximum CPI depth to display
27    pub max_cpi_depth: usize,
28    /// Show instruction data for account compression program
29    pub show_compression_instruction_data: bool,
30    /// Truncate byte arrays: Some((first, last)) shows first N and last N elements; None disables
31    pub truncate_byte_arrays: Option<(usize, usize)>,
32    /// Decoder registry containing built-in and custom decoders
33    /// Wrapped in Arc so it can be shared across clones instead of being lost
34    #[serde(skip)]
35    decoder_registry: Option<Arc<DecoderRegistry>>,
36}
37
38impl Clone for EnhancedLoggingConfig {
39    fn clone(&self) -> Self {
40        // Arc clone shares the underlying DecoderRegistry across clones
41        // This preserves custom decoders registered via with_decoders()
42        Self {
43            enabled: self.enabled,
44            log_events: self.log_events,
45            verbosity: self.verbosity,
46            show_account_changes: self.show_account_changes,
47            decode_light_instructions: self.decode_light_instructions,
48            show_compute_units: self.show_compute_units,
49            use_colors: self.use_colors,
50            max_cpi_depth: self.max_cpi_depth,
51            show_compression_instruction_data: self.show_compression_instruction_data,
52            truncate_byte_arrays: self.truncate_byte_arrays,
53            decoder_registry: self.decoder_registry.clone(),
54        }
55    }
56}
57
58impl Default for EnhancedLoggingConfig {
59    fn default() -> Self {
60        Self {
61            enabled: true,     // Always enabled for processing
62            log_events: false, // Don't log by default
63            verbosity: LogVerbosity::Standard,
64            show_account_changes: true,
65            decode_light_instructions: true,
66            show_compute_units: true,
67            use_colors: true,
68            max_cpi_depth: 60,
69            show_compression_instruction_data: false,
70            truncate_byte_arrays: Some((2, 2)),
71            decoder_registry: Some(Arc::new(DecoderRegistry::new())),
72        }
73    }
74}
75
76/// Verbosity levels for transaction logging
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
78pub enum LogVerbosity {
79    /// Only instruction hierarchy and status
80    Brief,
81    /// + account changes and basic instruction info
82    Standard,
83    /// + parsed instruction data when available
84    Detailed,
85    /// + raw instruction data and internal debugging info
86    Full,
87}
88
89impl EnhancedLoggingConfig {
90    /// Create config optimized for debugging
91    pub fn debug() -> Self {
92        Self {
93            enabled: true,
94            log_events: true, // Enable logging for debug mode
95            verbosity: LogVerbosity::Full,
96            show_account_changes: true,
97            decode_light_instructions: true,
98            show_compute_units: true,
99            use_colors: true,
100            max_cpi_depth: 60,
101            show_compression_instruction_data: false,
102            truncate_byte_arrays: Some((2, 2)),
103            decoder_registry: Some(Arc::new(DecoderRegistry::new())),
104        }
105    }
106
107    /// Create config optimized for CI/production
108    pub fn minimal() -> Self {
109        Self {
110            enabled: true,
111            log_events: false, // Don't log for minimal config
112            verbosity: LogVerbosity::Brief,
113            show_account_changes: false,
114            decode_light_instructions: false,
115            show_compute_units: false,
116            use_colors: false,
117            max_cpi_depth: 60,
118            show_compression_instruction_data: false,
119            truncate_byte_arrays: Some((2, 2)),
120            decoder_registry: Some(Arc::new(DecoderRegistry::new())),
121        }
122    }
123
124    /// Register custom decoders
125    ///
126    /// Note: Uses Arc::get_mut which works correctly in the builder pattern since
127    /// there's only one Arc reference. If the Arc has been cloned, a new registry
128    /// is created with built-in decoders plus the custom ones.
129    pub fn with_decoders(mut self, decoders: Vec<Box<dyn InstructionDecoder>>) -> Self {
130        if let Some(ref mut arc) = self.decoder_registry {
131            if let Some(registry) = Arc::get_mut(arc) {
132                registry.register_all(decoders);
133                return self;
134            }
135        }
136        // Create new registry if none exists or Arc has multiple references
137        let mut registry = DecoderRegistry::new();
138        registry.register_all(decoders);
139        self.decoder_registry = Some(Arc::new(registry));
140        self
141    }
142
143    /// Get or create the decoder registry
144    pub fn get_decoder_registry(&mut self) -> &DecoderRegistry {
145        if self.decoder_registry.is_none() {
146            self.decoder_registry = Some(Arc::new(DecoderRegistry::new()));
147        }
148        self.decoder_registry.as_ref().unwrap()
149    }
150
151    /// Get the decoder registry if it exists (immutable access)
152    pub fn decoder_registry(&self) -> Option<&DecoderRegistry> {
153        self.decoder_registry.as_ref().map(|arc| arc.as_ref())
154    }
155
156    /// Create config based on environment - always enabled, debug level when RUST_BACKTRACE is set
157    pub fn from_env() -> Self {
158        if std::env::var("RUST_BACKTRACE").is_ok() {
159            Self::debug()
160        } else {
161            // Always enabled but with standard verbosity when backtrace is not set
162            Self::default()
163        }
164    }
165
166    /// Enable event logging with current settings
167    pub fn with_logging(mut self) -> Self {
168        self.log_events = true;
169        self
170    }
171
172    /// Disable event logging
173    pub fn without_logging(mut self) -> Self {
174        self.log_events = false;
175        self
176    }
177}