Skip to content

Commit 0a7357e

Browse files
authored
Merge pull request #5 from brytelands/wasm-support
Wasm support
2 parents b8c05c7 + 2956aa9 commit 0a7357e

File tree

27 files changed

+2713
-6
lines changed

27 files changed

+2713
-6
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ members = [
55
"sologger-log-context",
66
"sologger-log-transport",
77
"sologger-log-transformer",
8+
"sologger-log-transformer-wasm",
89
"sologger"
910
]

sologger-log-context/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sologger_log_context"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
edition = "2021"
55
authors = ["Will Kennedy"]
66
description = "Provides functionality to turn raw logs output by Solana RPCs into structured logs for specified program IDs"
@@ -12,6 +12,7 @@ categories = ["development-tools::debugging"]
1212
exclude=["/tests", "/examples", "/benches", "/docs", "/target", "/.github", "/.gitignore", "/.gitattributes", "/.gitmodules", "/.travis.yml", "/.cargo-ok", "/.git", "/.idea"]
1313

1414
[lib]
15+
crate-type = ["cdylib", "rlib"]
1516
doctest = false
1617

1718
[dependencies]
@@ -22,9 +23,14 @@ serde_json = {version = "1.0.128"}
2223
serde_derive = "1.0.210"
2324
bs58 = "0.5.1"
2425
lazy_static = "1.5.0"
26+
wasm-bindgen = "0.2"
27+
serde-wasm-bindgen = "0.6.5"
28+
web-sys = { version = "0.3", features = ["console"] }
29+
console_error_panic_hook = "0.1"
2530

2631
[dev-dependencies]
2732
criterion = "0.5.1"
33+
wasm-bindgen-test = "0.3.45"
2834

2935
[[bench]]
3036
name = "log_context_benchmarks"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*

sologger-log-context/pkg/README.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# sologger-log-context
2+
3+
**Overview**
4+
5+
This library provides functionality to turn raw logs output by Solana RPCs into structured logs for specified program IDs.
6+
7+
**Usage**
8+
9+
```rust
10+
//Provide the ProgramSelector with the Program IDs for which you want to parse logs.
11+
//If you want to parse logs for all programs, use ProgramsSelector::new(&["*".to_string()])
12+
let programs_selector = ProgramsSelector::new(&["9RX7oz3WN5VRTqekBBHBvEJFVMNRnrCmVy7S6B6S5oU7".to_string()]);
13+
//Provide the raw logs, transfer error, programs selector, slot, and signature to the LogContext::parse_logs function.
14+
let log_contexts = LogContext::parse_logs(&logs, "".to_string(), &programs_selector, 1, "12345".to_string());
15+
```
16+
17+
These json schema for the log context can be found here: [LogContext-schema](LogContext-schema.json)
18+
19+
For example, if we have a list of raw logs retrieved from the Solana RPC, we can parse them into structured logs using the LogContext::parse_logs function. The first parameter is the raw logs, the second parameter is the program ID, the third parameter is the programs selector, the fourth parameter is the slot, and the fifth parameter is the signature.
20+
21+
The LogContext::parse_logs function returns a vector of LogContexts. Each LogContext contains a vector of LogMessages. Each LogMessage contains a vector of LogFields. Each LogField contains a key and a value.
22+
23+
Here is an example of raw logs retrieved from the Solana RPC:
24+
25+
```text
26+
Program 9RX7oz3WN5VRTqekBBHBvEJFVMNRnrCmVy7S6B6S5oU7 invoke [1]
27+
Program log: Instruction: Initialize
28+
Program 11111111111111111111111111111111 invoke [2]
29+
Program 11111111111111111111111111111111 success
30+
Program log: Initialized new event. Current value
31+
Program 9RX7oz3WN5VRTqekBBHBvEJFVMNRnrCmVy7S6B6S5oU7 consumed 59783 of 200000 compute units
32+
Program 9RX7oz3WN5VRTqekBBHBvEJFVMNRnrCmVy7S6B6S5oU7 success
33+
Program AbcdefGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]
34+
Program log: Create
35+
Program AbcdefGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 5475 of 200000 compute units
36+
Program failed to complete: Invoked an instruction with data that is too large (12178014311288245306 > 10240)
37+
Program AbcdefGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL failed: Program failed to complete
38+
```
39+
40+
Here is an example of the structured logs that are returned from the LogContext::parse_logs function:
41+
42+
```json
43+
{
44+
"log_messages":[
45+
"Instruction: Initialize",
46+
"Initialized new event. Current value"
47+
],
48+
"data_logs":[
49+
50+
],
51+
"raw_logs":[
52+
"Program 9RX7oz3WN5VRTqekBBHBvEJFVMNRnrCmVy7S6B6S5oU7 invoke [1]",
53+
"Program log: Instruction: Initialize",
54+
"Program log: Initialized new event. Current value",
55+
"Program 9RX7oz3WN5VRTqekBBHBvEJFVMNRnrCmVy7S6B6S5oU7 consumed 59783 of 200000 compute units",
56+
"Program 9RX7oz3WN5VRTqekBBHBvEJFVMNRnrCmVy7S6B6S5oU7 success"
57+
],
58+
"errors":[
59+
60+
],
61+
"transaction_error":"",
62+
"program_id":"9RX7oz3WN5VRTqekBBHBvEJFVMNRnrCmVy7S6B6S5oU7",
63+
"parent_program_id":"",
64+
"depth":1,
65+
"id":0,
66+
"instruction_index":0,
67+
"invoke_result":"",
68+
"slot":1,
69+
"signature":"12345"
70+
}
71+
```
72+
73+
```json
74+
{
75+
"log_messages":[
76+
77+
],
78+
"data_logs":[
79+
80+
],
81+
"raw_logs":[
82+
"Program 11111111111111111111111111111111 invoke [2]",
83+
"Program 11111111111111111111111111111111 success"
84+
],
85+
"errors":[
86+
87+
],
88+
"transaction_error":"",
89+
"program_id":"11111111111111111111111111111111",
90+
"parent_program_id":"9RX7oz3WN5VRTqekBBHBvEJFVMNRnrCmVy7S6B6S5oU7",
91+
"depth":2,
92+
"id":1,
93+
"instruction_index":0,
94+
"invoke_result":"",
95+
"slot":1,
96+
"signature":"12345"
97+
}
98+
```
99+
100+
```json
101+
{
102+
"log_messages":[
103+
"Create"
104+
],
105+
"data_logs":[
106+
107+
],
108+
"raw_logs":[
109+
"Program AbcdefGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]",
110+
"Program log: Create",
111+
"Program AbcdefGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 5475 of 200000 compute units",
112+
"Program failed to complete: Invoked an instruction with data that is too large (12178014311288245306 > 10240)",
113+
"Program AbcdefGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL failed: Program failed to complete"
114+
],
115+
"errors":[
116+
"Invoked an instruction with data that is too large (12178014311288245306 > 10240)",
117+
"Program failed to complete"
118+
],
119+
"transaction_error":"",
120+
"program_id":"AbcdefGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
121+
"parent_program_id":"",
122+
"depth":1,
123+
"id":2,
124+
"instruction_index":1,
125+
"invoke_result":"",
126+
"slot":1,
127+
"signature":"12345"
128+
}
129+
```
130+
131+
**Additional Usage**
132+
133+
The LogContext also provides utility to retrieve specific information from a log line.
134+
135+
- get_program_data: Returns the data mentioned in the provided log (for logs prefixed with "Program data: ")
136+
- parse_logs_from_string: Parses the provided payload and returns a vector of LogContexts. The payload in this case is the raw JSON response as a string from the Solana RPC log_subscription endpoint.
137+
- has_errors: Returns true if the log contains a program error
138+
139+
**Technical Details**
140+
141+
The parsing of the raw logs is done using a regular expression. The regular expression is defined in the LogContext::get_log_regex function. The regular expression is defined as follows:
142+
143+
[regex-vis](https://regex-vis.com/?r=%28%3F%3CprogramInvoke%3E%5EProgram+%28%3F%3CinvokeProgramId%3E%5B1-9A-HJ-NP-Za-km-z%5D%7B32%2C%7D%29+invoke+%5C%5B%28%3F%3Clevel%3E%5Cd%2B%29%5C%5D%24%29%7C%28%3F%3CprogramSuccessResult%3E%5EProgram+%28%3F%3CsuccessResultProgramId%3E%5B1-9A-HJ-NP-Za-km-z%5D%7B32%2C%7D%29+success%24%29%7C%28%3F%3CprogramFailedResult%3E%5EProgram+%28%3F%3CfailedResultProgramId%3E%5B1-9A-HJ-NP-Za-km-z%5D%7B32%2C%7D%29+failed%3A+%28%3F%3CfailedResultErr%3E.*%29%24%29%7C%28%3F%3CprogramCompleteFailedResult%3E%5EProgram+failed+to+complete%3A+%28%3F%3CfailedCompleteError%3E.*%29%24%29%7C%28%3F%3CprogramLog%3E%5E%5EProgram+log%3A+%28%3F%3ClogMessage%3E.*%29%24%29%7C%28%3F%3CprogramData%3E%5EProgram+data%3A+%28%3F%3Cdata%3E.*%29%24%29%7C%28%3F%3CprogramConsumed%3E%5EProgram+%28%3F%3CconsumedProgramId%3E%5B1-9A-HJ-NP-Za-km-z%5D%7B32%2C%7D%29+consumed+%28%3F%3CconsumedComputeUnits%3E%5Cd*%29+of+%28%3F%3CallComputedUnits%3E%5Cd*%29+compute+units%24%29%7C%28%3F%3CprogramConsumption%3E%5E%5EProgram+consumption%3A+%28%3F%3CcomputeUnitsRemaining%3E.*%29%24%29%7C%28%3F%3ClogTruncated%3E%5ELog+truncated%24%29%7C%28%3F%3CprogramReturn%3E%5EProgram+return%3A+%28%3F%3CreturnProgramId%3E%5B1-9A-HJ-NP-Za-km-z%5D%7B32%2C%7D%29+%28%3F%3CreturnMessage%3E.*%29%24%29&e=0)
144+
145+
```regexp
146+
(?<programInvoke>^Program (?<invokeProgramId>[1-9A-HJ-NP-Za-km-z]{32,}) invoke \[(?<level>\d+)\]$)|(?<programSuccessResult>^Program (?<successResultProgramId>[1-9A-HJ-NP-Za-km-z]{32,}) success$)|(?<programFailedResult>^Program (?<failedResultProgramId>[1-9A-HJ-NP-Za-km-z]{32,}) failed: (?<failedResultErr>.*)$)|(?<programCompleteFailedResult>^Program failed to complete: (?<failedCompleteError>.*)$)|(?<programLog>^^Program log: (?<logMessage>.*)$)|(?<programData>^Program data: (?<data>.*)$)|(?<programConsumed>^Program (?<consumedProgramId>[1-9A-HJ-NP-Za-km-z]{32,}) consumed (?<consumedComputeUnits>\d*) of (?<allComputedUnits>\d*) compute units$)|(?<programConsumption>^^Program consumption: (?<computeUnitsRemaining>.*)$)|(?<logTruncated>^Log truncated$)|(?<programReturn>^Program return: (?<returnProgramId>[1-9A-HJ-NP-Za-km-z]{32,}) (?<returnMessage>.*)$)
147+
```
148+
149+
The LogContext attempts to loop through the raw logs returned from the Solana websocket log subscription frames, or groups of logs retrieved from a specific transaction or block.
150+
If logs are provided that are out of order or not from a contained unit such as a block, transaction or websocket frame, then the LogContext will most likely fail.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "sologger_log_context",
3+
"type": "module",
4+
"collaborators": [
5+
"Will Kennedy"
6+
],
7+
"description": "Provides functionality to turn raw logs output by Solana RPCs into structured logs for specified program IDs",
8+
"version": "0.2.0",
9+
"license": "Apache-2.0",
10+
"repository": {
11+
"type": "git",
12+
"url": "https://github.com/brytelands/sologger"
13+
},
14+
"files": [
15+
"sologger_log_context_bg.wasm",
16+
"sologger_log_context.js",
17+
"sologger_log_context_bg.js",
18+
"sologger_log_context.d.ts"
19+
],
20+
"main": "sologger_log_context.js",
21+
"types": "sologger_log_context.d.ts",
22+
"sideEffects": [
23+
"./sologger_log_context.js",
24+
"./snippets/*"
25+
],
26+
"keywords": [
27+
"solana",
28+
"logging",
29+
"json",
30+
"parsing"
31+
]
32+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* tslint:disable */
2+
/* eslint-disable */
3+
/**
4+
* @param {(string)[]} logs
5+
* @param {(string)[]} program_ids
6+
* @returns {any}
7+
*/
8+
export function parse_logs_basic(logs: (string)[], program_ids: (string)[]): any;
9+
export class WasmLogParser {
10+
free(): void;
11+
/**
12+
* @param {(string)[]} program_ids
13+
*/
14+
constructor(program_ids: (string)[]);
15+
/**
16+
* @param {(string)[]} logs
17+
* @param {string} transaction_error
18+
* @param {bigint} slot
19+
* @param {string} signature
20+
* @returns {any}
21+
*/
22+
parse_logs(logs: (string)[], transaction_error: string, slot: bigint, signature: string): any;
23+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import * as wasm from "./sologger_log_context_bg.wasm";
2+
export * from "./sologger_log_context_bg.js";
3+
import { __wbg_set_wasm } from "./sologger_log_context_bg.js";
4+
__wbg_set_wasm(wasm);

0 commit comments

Comments
 (0)