Skip to main content

sol_log_parser/
raw_log.rs

1use crate::quick_pubkey_check;
2
3/// A Raw Log
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum RawLog<'a> {
6    Invoke(RawInvokeLog<'a>),
7    Success(RawSuccessLog<'a>),
8    Failed(RawFailedLog<'a>),
9    Log(RawProgramLog<'a>),
10    Data(RawDataLog<'a>),
11    Return(RawReturnLog<'a>),
12    Cu(RawCuLog<'a>),
13    Other(RawOtherLog<'a>),
14}
15
16impl<'a> RawLog<'a> {
17    pub fn parse(log: &'a str) -> Self {
18        let trimmed = log.trim();
19
20        if let Some(rest) = trimmed.strip_prefix("Program log: ") {
21            return RawLog::Log(RawProgramLog {
22                raw: log,
23                msg: rest,
24            });
25        }
26
27        if let Some(rest) = trimmed.strip_prefix("Program data: ") {
28            return RawLog::Data(RawDataLog {
29                raw: log,
30                data: rest,
31            });
32        }
33
34        if let Some(rest) = trimmed.strip_prefix("Program return: ") {
35            let Some((program_id, data)) = rest.split_once(' ') else {
36                return RawLog::Other(RawOtherLog { raw: log });
37            };
38
39            return RawLog::Return(RawReturnLog {
40                raw: log,
41                program_id,
42                data,
43            });
44        }
45
46        if let Some(rest) = trimmed.strip_prefix("Program ") {
47            let Some((program_id, suffix)) = rest.split_once(' ') else {
48                return RawLog::Other(RawOtherLog { raw: log });
49            };
50
51            if !quick_pubkey_check(program_id) {
52                return RawLog::Other(RawOtherLog { raw: log });
53            }
54
55            if let Some(depth) = suffix
56                .strip_prefix("invoke [")
57                .and_then(|s| s.strip_suffix(']'))
58            {
59                return depth
60                    .parse()
61                    .ok()
62                    .map(|depth| {
63                        RawLog::Invoke(RawInvokeLog {
64                            raw: log,
65                            program_id,
66                            depth,
67                        })
68                    })
69                    .unwrap_or(RawLog::Other(RawOtherLog { raw: log }));
70            }
71
72            if suffix == "success" {
73                return RawLog::Success(RawSuccessLog {
74                    raw: log,
75                    program_id,
76                });
77            }
78
79            if let Some(err) = suffix.strip_prefix("failed: ") {
80                return RawLog::Failed(RawFailedLog {
81                    raw: log,
82                    program_id,
83                    err,
84                });
85            }
86
87            if let Some((consumed, of_budget)) = suffix
88                .strip_prefix("consumed ")
89                .and_then(|s| s.split_once(" of "))
90            {
91                let Some(budget) = of_budget.strip_suffix(" compute units") else {
92                    return RawLog::Other(RawOtherLog { raw: log });
93                };
94
95                return consumed
96                    .parse()
97                    .ok()
98                    .and_then(|consumed| {
99                        budget.parse().ok().map(|budget| {
100                            RawLog::Cu(RawCuLog {
101                                raw: log,
102                                program_id,
103                                consumed,
104                                budget,
105                            })
106                        })
107                    })
108                    .unwrap_or(RawLog::Other(RawOtherLog { raw: log }));
109            }
110        }
111
112        RawLog::Other(RawOtherLog { raw: log })
113    }
114}
115
116/// A Raw Invoke Log
117///
118/// `Program <id> invoke [n]`
119#[derive(Debug, Clone, PartialEq, Eq)]
120pub struct RawInvokeLog<'a> {
121    pub raw: &'a str,
122    pub program_id: &'a str,
123    pub depth: u8,
124}
125
126/// A Raw Success Log
127///
128/// `Program <id> success`
129#[derive(Debug, Clone, PartialEq, Eq)]
130pub struct RawSuccessLog<'a> {
131    pub raw: &'a str,
132    pub program_id: &'a str,
133}
134
135/// A Raw Failed Log
136///
137/// `Program <id> failed: <err>``
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct RawFailedLog<'a> {
140    pub raw: &'a str,
141    pub program_id: &'a str,
142    pub err: &'a str,
143}
144
145/// A Raw Program Log
146///
147/// `Program log: <msg>`
148#[derive(Debug, Clone, PartialEq, Eq)]
149pub struct RawProgramLog<'a> {
150    pub raw: &'a str,
151    pub msg: &'a str,
152}
153
154/// A Raw Data Log
155///
156/// `Program data: <base64>`
157#[derive(Debug, Clone, PartialEq, Eq)]
158pub struct RawDataLog<'a> {
159    pub raw: &'a str,
160    pub data: &'a str,
161}
162
163/// A Raw Return Log
164///
165/// `Program return: <id> <base64>`
166#[derive(Debug, Clone, PartialEq, Eq)]
167pub struct RawReturnLog<'a> {
168    pub raw: &'a str,
169    pub program_id: &'a str,
170    pub data: &'a str,
171}
172
173/// A Raw Cu Log
174///
175/// `Program <id> consumed <x> of <y> compute units`
176#[derive(Debug, Clone, PartialEq, Eq)]
177pub struct RawCuLog<'a> {
178    pub raw: &'a str,
179    pub program_id: &'a str,
180    pub consumed: u64,
181    pub budget: u64,
182}
183
184#[derive(Debug, Clone, PartialEq, Eq)]
185pub struct RawOtherLog<'a> {
186    pub raw: &'a str,
187}
188
189/* *************************************************************************** *
190 *     HELPER CODE
191 * *************************************************************************** */
192
193mod helper_code {
194    use crate::structured_log::{
195        ComputeUnitsLog, FailedLog, InvokeLog, Log, ReturnLog, SuccessLog,
196    };
197
198    use super::{
199        RawCuLog, RawDataLog, RawFailedLog, RawInvokeLog, RawOtherLog, RawProgramLog, RawReturnLog,
200        RawSuccessLog,
201    };
202
203    impl<'a> Log for RawInvokeLog<'a> {
204        type RawLog = &'a str;
205
206        fn raw_log(&self) -> Self::RawLog {
207            self.raw
208        }
209    }
210
211    impl<'a> Log for RawSuccessLog<'a> {
212        type RawLog = &'a str;
213
214        fn raw_log(&self) -> Self::RawLog {
215            self.raw
216        }
217    }
218
219    impl<'a> Log for RawFailedLog<'a> {
220        type RawLog = &'a str;
221
222        fn raw_log(&self) -> Self::RawLog {
223            self.raw
224        }
225    }
226
227    impl<'a> Log for RawProgramLog<'a> {
228        type RawLog = &'a str;
229
230        fn raw_log(&self) -> Self::RawLog {
231            self.raw
232        }
233    }
234
235    impl<'a> Log for RawDataLog<'a> {
236        type RawLog = &'a str;
237
238        fn raw_log(&self) -> Self::RawLog {
239            self.raw
240        }
241    }
242
243    impl<'a> Log for RawReturnLog<'a> {
244        type RawLog = &'a str;
245
246        fn raw_log(&self) -> Self::RawLog {
247            self.raw
248        }
249    }
250
251    impl<'a> Log for RawCuLog<'a> {
252        type RawLog = &'a str;
253
254        fn raw_log(&self) -> Self::RawLog {
255            self.raw
256        }
257    }
258
259    impl<'a> Log for RawOtherLog<'a> {
260        type RawLog = &'a str;
261
262        fn raw_log(&self) -> Self::RawLog {
263            self.raw
264        }
265    }
266
267    impl<'a> InvokeLog for RawInvokeLog<'a> {
268        type ProgramId = &'a str;
269
270        fn program_id(&self) -> Self::ProgramId {
271            self.program_id
272        }
273
274        fn depth(&self) -> u8 {
275            self.depth
276        }
277    }
278
279    impl<'a> SuccessLog for RawSuccessLog<'a> {
280        type ProgramId = &'a str;
281
282        fn program_id(&self) -> Self::ProgramId {
283            self.program_id
284        }
285    }
286
287    impl<'a> FailedLog for RawFailedLog<'a> {
288        type ProgramId = &'a str;
289        type Err = &'a str;
290
291        fn program_id(&self) -> Self::ProgramId {
292            self.program_id
293        }
294
295        fn err(&self) -> Self::Err {
296            self.err
297        }
298    }
299
300    impl<'a> ReturnLog for RawReturnLog<'a> {
301        type ProgramId = &'a str;
302        type Data = &'a str;
303
304        fn program_id(&self) -> Self::ProgramId {
305            self.program_id
306        }
307
308        fn data(&self) -> Self::Data {
309            self.data
310        }
311    }
312
313    impl<'a> ComputeUnitsLog for RawCuLog<'a> {
314        type ProgramId = &'a str;
315
316        fn program_id(&self) -> Self::ProgramId {
317            self.program_id
318        }
319    }
320}