More useful Synchronizer logging + sync report tool.

Synchronizer logging now includes abbreviated block signature.
This commit is contained in:
catbref
2019-07-25 11:05:43 +01:00
parent 7042dd819f
commit 0c17f9cff6
2 changed files with 230 additions and 11 deletions

View File

@@ -0,0 +1,209 @@
package org.qora.test;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/*
* We are expecting log entries like:
*
* 2019-07-24 11:31:25 DEBUG Synchronizer:121 - Synchronizing with peer 52.33.79.54:9889 at height 73139, sig 2cfqHyJ4, ts 1563964269587; our height 73140, sig 8hae8BLg, ts 1563964271060
*
* 2019-07-24 11:31:26 DEBUG Synchronizer:138 - Common block with peer 52.33.79.54:9889 is at height 73138, sig 7LKMHZxU, ts 1563964148818
*
* 2019-07-24 11:31:26 INFO Synchronizer:326 - Synchronized with peer 52.33.79.54:9889 to height 73139, sig 2cfqHyJ4, ts: 1563964269587
*
*/
public class SyncReport {
private static final Pattern START_PATTERN;
private static final Pattern COMMON_PATTERN;
private static final Pattern DONE_PATTERN;
private static final Pattern FAIL_PATTERN;
static {
try {
START_PATTERN = Pattern.compile("(\\d+-\\d+-\\d+ \\d+:\\d+:\\d+) .*? Synchronizing with peer (\\S+) at height (\\d+), sig (\\S+), ts (\\d+); our height (\\d+), sig (\\S+), ts (\\d+)");
COMMON_PATTERN = Pattern.compile(".*? Common block with peer (\\S+) is at height (\\d+), sig (\\S+), ts (\\d+)");
DONE_PATTERN = Pattern.compile(".*? Synchronized with peer (\\S+) to height (\\d+), sig (\\S+), ts:? (\\d+)");
FAIL_PATTERN = Pattern.compile(".*? .ynchronized? with peer (\\S+) \\((\\S+)\\)");
} catch (PatternSyntaxException e) {
throw new RuntimeException(e);
}
}
private static final SimpleDateFormat LOG_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
static class SyncEvent {
long timestamp;
String peer;
String fromBlockSig;
String commonBlockSig;
String tipBlockSig;
}
public static void main(String args[]) {
if (args.length == 0) {
System.err.println("usage: SyncReport <logfile> [<logfile> ...]");
System.exit(1);
}
List<SyncEvent> syncEvents = new ArrayList<>();
Map<String, Integer> blockHeights = new HashMap<>();
InputStream in = null;
Scanner scanner = null;
int argIndex = 0;
Matcher matcher;
SyncEvent syncEvent = null;
while (argIndex < args.length) {
if (in == null) {
// Open a log file
Path path = Paths.get(args[argIndex]);
try {
in = Files.newInputStream(path);
} catch (IOException e) {
System.err.println(String.format("Unable to open '%s': %s", path.toString(), e.getMessage()));
System.exit(2);
}
scanner = new Scanner(in, "UTF8");
scanner.useDelimiter("\n");
}
if (!scanner.hasNext()) {
scanner.close();
scanner = null;
try {
in.close();
} catch (IOException e) {
System.err.println(String.format("Unable to close InputStream: %s", e.getMessage()));
System.exit(2);
}
in = null;
++argIndex;
continue;
}
String line = scanner.next();
matcher = START_PATTERN.matcher(line);
if (matcher.matches()) {
long logTimestamp = 0;
try {
Date logDate = LOG_DATE_FORMAT.parse(matcher.group(1));
logTimestamp = logDate.toInstant().toEpochMilli();
} catch (ParseException e) {
System.err.println(String.format("Couldn't determine log entry timestamp from '%s'", matcher.group(1)));
System.exit(3);
}
Integer tipHeight = Integer.valueOf(matcher.group(3));
Integer ourHeight = Integer.valueOf(matcher.group(6));
if (syncEvent != null) {
// Salvageable?
if (syncEvent.commonBlockSig != null && ourHeight > blockHeights.get(syncEvent.fromBlockSig)) {
syncEvent.tipBlockSig = matcher.group(7);
syncEvents.add(syncEvent);
}
}
syncEvent = new SyncEvent();
syncEvent.timestamp = logTimestamp;
syncEvent.peer = matcher.group(2);
syncEvent.fromBlockSig = matcher.group(7);
blockHeights.put(matcher.group(4), tipHeight);
blockHeights.put(matcher.group(7), ourHeight);
continue;
}
matcher = COMMON_PATTERN.matcher(line);
if (matcher.matches()) {
String peer = matcher.group(1);
if (syncEvent == null || !peer.equals(syncEvent.peer)) {
System.err.println(String.format("No current synchronization with %s", peer));
continue;
}
if (syncEvent.commonBlockSig != null) {
System.err.println(String.format("We already have a common block: %s", syncEvent.commonBlockSig));
continue;
}
syncEvent.commonBlockSig = matcher.group(3);
blockHeights.put(matcher.group(3), Integer.valueOf(matcher.group(2)));
continue;
}
matcher = DONE_PATTERN.matcher(line);
if (matcher.matches()) {
String peer = matcher.group(1);
if (syncEvent == null || !peer.equals(syncEvent.peer)) {
System.err.println(String.format("No current synchronization with %s", peer));
continue;
}
syncEvent.tipBlockSig = matcher.group(3);
// Add successful sync to list
syncEvents.add(syncEvent);
syncEvent = null;
continue;
}
matcher = FAIL_PATTERN.matcher(line);
if (matcher.matches()) {
String result = matcher.group(2);
if (result.equals("NO_REPLY"))
// Possibly salvageable
continue;
// Sync went bad
syncEvent = null;
continue;
}
}
for (SyncEvent se : syncEvents) {
if (se.commonBlockSig.equals(se.fromBlockSig))
System.out.println(String.format("%s: %s (%d) ===> %s (%d) (peer %s)",
LOG_DATE_FORMAT.format(Date.from(Instant.ofEpochMilli(se.timestamp))),
se.fromBlockSig, blockHeights.get(se.fromBlockSig),
se.tipBlockSig, blockHeights.get(se.tipBlockSig),
se.peer));
else
System.out.println(String.format("%s: %s (%d) ---> %s (%d) ===> %s (%d) (peer %s)",
LOG_DATE_FORMAT.format(Date.from(Instant.ofEpochMilli(se.timestamp))),
se.fromBlockSig, blockHeights.get(se.fromBlockSig),
se.commonBlockSig, blockHeights.get(se.commonBlockSig),
se.tipBlockSig, blockHeights.get(se.tipBlockSig),
se.peer));
}
}
}