sol_log_parser/
parsed_log.rs

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