Add ability to parse logs in ledger-tool (#10840)
Co-authored-by: Carl <carl@solana.com>
This commit is contained in:
parent
4b93a7c1f6
commit
2dfa48daf9
|
@ -4212,6 +4212,7 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"histogram",
|
"histogram",
|
||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
|
"regex",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
|
|
|
@ -27,6 +27,7 @@ solana-transaction-status = { path = "../transaction-status", version = "1.3.0"
|
||||||
solana-version = { path = "../version", version = "1.3.0" }
|
solana-version = { path = "../version", version = "1.3.0" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.3.0" }
|
solana-vote-program = { path = "../programs/vote", version = "1.3.0" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
regex = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "1.0"
|
assert_cmd = "1.0"
|
||||||
|
|
|
@ -2,10 +2,12 @@ use clap::{
|
||||||
crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App, Arg,
|
crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App, Arg,
|
||||||
ArgMatches, SubCommand,
|
ArgMatches, SubCommand,
|
||||||
};
|
};
|
||||||
|
use regex::Regex;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use solana_clap_utils::input_validators::{is_parsable, is_slot};
|
use solana_clap_utils::input_validators::{is_parsable, is_slot};
|
||||||
use solana_ledger::entry::Entry;
|
use solana_ledger::entry::Entry;
|
||||||
use solana_ledger::{
|
use solana_ledger::{
|
||||||
|
ancestor_iterator::AncestorIterator,
|
||||||
bank_forks_utils,
|
bank_forks_utils,
|
||||||
blockstore::Blockstore,
|
blockstore::Blockstore,
|
||||||
blockstore_db::{self, AccessType, Column, Database},
|
blockstore_db::{self, AccessType, Column, Database},
|
||||||
|
@ -25,11 +27,11 @@ use solana_sdk::{
|
||||||
};
|
};
|
||||||
use solana_vote_program::vote_state::VoteState;
|
use solana_vote_program::vote_state::VoteState;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, HashMap, HashSet},
|
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
||||||
convert::TryInto,
|
convert::TryInto,
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::{self, stdout, Write},
|
io::{self, stdout, BufRead, BufReader, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::{exit, Command, Stdio},
|
process::{exit, Command, Stdio},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
|
@ -834,6 +836,25 @@ fn main() {
|
||||||
.about("Prints the ledger's genesis config")
|
.about("Prints the ledger's genesis config")
|
||||||
.arg(&max_genesis_archive_unpacked_size_arg)
|
.arg(&max_genesis_archive_unpacked_size_arg)
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("parse_full_frozen")
|
||||||
|
.about("Parses log for information about critical events about ancestors of the given `ending_slot`")
|
||||||
|
.arg(&starting_slot_arg)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("ending_slot")
|
||||||
|
.long("ending-slot")
|
||||||
|
.value_name("SLOT")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("The last slot to iterate to"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("log_path")
|
||||||
|
.long("log-path")
|
||||||
|
.value_name("PATH")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("path to log file to parse"),
|
||||||
|
)
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("genesis-hash")
|
SubCommand::with_name("genesis-hash")
|
||||||
.about("Prints the ledger's genesis hash")
|
.about("Prints the ledger's genesis hash")
|
||||||
|
@ -1134,6 +1155,70 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
("parse_full_frozen", Some(arg_matches)) => {
|
||||||
|
let starting_slot = value_t_or_exit!(arg_matches, "starting_slot", Slot);
|
||||||
|
let ending_slot = value_t_or_exit!(arg_matches, "ending_slot", Slot);
|
||||||
|
let blockstore = open_blockstore(&ledger_path, AccessType::TryPrimaryThenSecondary);
|
||||||
|
let mut ancestors = BTreeSet::new();
|
||||||
|
if blockstore.meta(ending_slot).unwrap().is_none() {
|
||||||
|
panic!("Ending slot doesn't exist");
|
||||||
|
}
|
||||||
|
for a in AncestorIterator::new(ending_slot, &blockstore) {
|
||||||
|
ancestors.insert(a);
|
||||||
|
if a <= starting_slot {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("ancestors: {:?}", ancestors.iter());
|
||||||
|
|
||||||
|
let mut frozen = BTreeMap::new();
|
||||||
|
let mut full = BTreeMap::new();
|
||||||
|
let frozen_regex = Regex::new(r"bank frozen: (\d*)").unwrap();
|
||||||
|
let full_regex = Regex::new(r"slot (\d*) is full").unwrap();
|
||||||
|
|
||||||
|
let log_file = PathBuf::from(value_t_or_exit!(arg_matches, "log_path", String));
|
||||||
|
let f = BufReader::new(File::open(log_file).unwrap());
|
||||||
|
println!("Reading log file");
|
||||||
|
for line in f.lines() {
|
||||||
|
if let Ok(line) = line {
|
||||||
|
let parse_results = {
|
||||||
|
if let Some(slot_string) = frozen_regex.captures_iter(&line).next() {
|
||||||
|
Some((slot_string, &mut frozen))
|
||||||
|
} else if let Some(slot_string) = full_regex.captures_iter(&line).next() {
|
||||||
|
Some((slot_string, &mut full))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some((slot_string, map)) = parse_results {
|
||||||
|
let slot = slot_string
|
||||||
|
.get(1)
|
||||||
|
.expect("Only one match group")
|
||||||
|
.as_str()
|
||||||
|
.parse::<u64>()
|
||||||
|
.unwrap();
|
||||||
|
if ancestors.contains(&slot) && !map.contains_key(&slot) {
|
||||||
|
map.insert(slot, line);
|
||||||
|
}
|
||||||
|
if slot == starting_slot
|
||||||
|
&& frozen.contains_key(&slot)
|
||||||
|
&& full.contains_key(&slot)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((slot1, frozen_log), (slot2, full_log)) in frozen.iter().zip(full.iter()) {
|
||||||
|
assert_eq!(slot1, slot2);
|
||||||
|
println!(
|
||||||
|
"Slot: {}\n, full: {}\n, frozen: {}",
|
||||||
|
slot1, full_log, frozen_log
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
("verify", Some(arg_matches)) => {
|
("verify", Some(arg_matches)) => {
|
||||||
let process_options = ProcessOptions {
|
let process_options = ProcessOptions {
|
||||||
dev_halt_at_slot: value_t!(arg_matches, "halt_at_slot", Slot).ok(),
|
dev_halt_at_slot: value_t!(arg_matches, "halt_at_slot", Slot).ok(),
|
||||||
|
|
Loading…
Reference in New Issue