soroban_env_host/events/
diagnostic.rs1use std::rc::Rc;
2
3use crate::{
4 events::{
5 internal::{InternalDiagnosticArg, InternalDiagnosticEvent},
6 InternalEvent, InternalEventsBuffer,
7 },
8 host::metered_clone::{MeteredAlloc, MeteredClone, MeteredContainer, MeteredIterator},
9 xdr::{Hash, ScBytes, ScString, ScVal, StringM},
10 Error, Host, HostError, Symbol, SymbolSmall, Val,
11};
12
13#[derive(Clone, Default)]
14pub enum DiagnosticLevel {
15 #[default]
16 None,
17 Debug,
18}
19
20impl Host {
21 fn record_diagnostic_event(
22 &self,
23 contract_id: Option<Hash>,
24 topics: Vec<InternalDiagnosticArg>,
25 args: Vec<InternalDiagnosticArg>,
26 ) -> Result<(), HostError> {
27 self.with_debug_mode(|| {
28 #[cfg(any(test, feature = "recording_mode"))]
29 if *self.try_borrow_suppress_diagnostic_events()? {
30 return Ok(());
31 }
32
33 let de = Rc::metered_new(
34 InternalDiagnosticEvent {
35 contract_id,
36 topics,
37 args,
38 },
39 self,
40 )?;
41 self.with_events_mut(|events| events.record(InternalEvent::Diagnostic(de), self))
42 });
43 Ok(())
44 }
45
46 pub(crate) fn log_diagnostics(&self, msg: &str, args: &[Val]) {
47 self.with_debug_mode(|| {
48 let calling_contract = self.get_current_contract_id_opt_internal()?;
49 let log_sym = SymbolSmall::try_from_str("log")?;
50 Vec::<InternalDiagnosticArg>::charge_bulk_init_cpy(1, self)?;
51 let topics = vec![InternalDiagnosticArg::HostVal(log_sym.to_val())];
52 let msg = ScVal::String(ScString::from(StringM::try_from(
53 self.metered_slice_to_vec(msg.as_bytes())?,
54 )?));
55 let args: Vec<_> = std::iter::once(InternalDiagnosticArg::XdrVal(msg))
56 .chain(args.iter().map(|rv| InternalDiagnosticArg::HostVal(*rv)))
57 .metered_collect(self)?;
58 self.record_diagnostic_event(calling_contract, topics, args)
59 })
60 }
61
62 pub(crate) fn record_err_diagnostics(
63 &self,
64 events: &mut InternalEventsBuffer,
65 error: Error,
66 msg: &str,
67 args: &[Val],
68 ) {
69 self.with_debug_mode(|| {
70 #[cfg(any(test, feature = "recording_mode"))]
71 if *self.try_borrow_suppress_diagnostic_events()? {
72 return Ok(());
73 }
74 let error_sym = SymbolSmall::try_from_str("error")?;
75 let contract_id = self.get_current_contract_id_opt_internal()?;
76 Vec::<InternalDiagnosticArg>::charge_bulk_init_cpy(2, self)?;
77 let topics = vec![
78 InternalDiagnosticArg::HostVal(error_sym.to_val()),
79 InternalDiagnosticArg::HostVal(error.to_val()),
80 ];
81 let msg = ScVal::String(ScString::from(StringM::try_from(
82 self.metered_slice_to_vec(msg.as_bytes())?,
83 )?));
84 let args: Vec<_> = std::iter::once(InternalDiagnosticArg::XdrVal(msg))
85 .chain(args.iter().map(|rv| InternalDiagnosticArg::HostVal(*rv)))
86 .metered_collect(self)?;
87
88 let ce = Rc::metered_new(
93 InternalDiagnosticEvent {
94 contract_id,
95 topics,
96 args,
97 },
98 self,
99 )?;
100 events.record(InternalEvent::Diagnostic(ce), self)
101 })
102 }
103
104 pub(crate) fn fn_call_diagnostics(
109 &self,
110 called_contract_id: &Hash,
111 func: &Symbol,
112 args: &[Val],
113 ) {
114 self.with_debug_mode(|| {
115 let calling_contract = self.get_current_contract_id_opt_internal()?;
116 Vec::<InternalDiagnosticArg>::charge_bulk_init_cpy(3, self)?;
117 let topics = vec![
118 InternalDiagnosticArg::HostVal(SymbolSmall::try_from_str("fn_call")?.into()),
119 InternalDiagnosticArg::XdrVal(ScVal::Bytes(ScBytes::try_from(
120 self.metered_slice_to_vec(called_contract_id.as_slice())?,
121 )?)),
122 InternalDiagnosticArg::HostVal(func.into()),
123 ];
124 let args = args
125 .iter()
126 .map(|rv| InternalDiagnosticArg::HostVal(*rv))
127 .metered_collect(self)?;
128 self.record_diagnostic_event(calling_contract, topics, args)
129 })
130 }
131
132 pub(crate) fn fn_return_diagnostics(&self, contract_id: &Hash, func: &Symbol, res: &Val) {
135 self.with_debug_mode(|| {
136 Vec::<InternalDiagnosticArg>::charge_bulk_init_cpy(2, self)?;
137 let topics = vec![
138 InternalDiagnosticArg::HostVal(SymbolSmall::try_from_str("fn_return")?.into()),
139 InternalDiagnosticArg::HostVal(func.into()),
140 ];
141 Vec::<InternalDiagnosticArg>::charge_bulk_init_cpy(1, self)?;
142 let args = vec![InternalDiagnosticArg::HostVal(*res)];
143 self.record_diagnostic_event(Some(contract_id.metered_clone(self)?), topics, args)
144 })
145 }
146}