@j0nnyboi/amman
Version:
A modern mandatory toolbelt to help test solana SDK libraries and apps on a locally running validator.
169 lines • 6.45 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrettyLogger = void 0;
const program_err_1 = require("./program-err");
const program_names_1 = require("./program-names");
const txExecutedRx = /Transaction executed in slot/i;
class PrettyLogger {
constructor(amman) {
this.amman = amman;
this.prettyLogs = [];
this.instructionCount = [];
this.depth = 0;
}
incDepth() {
this.depth++;
this.instructionCount[this.depth - 1] = 0;
}
decDepth() {
this.depth--;
if (this.depth >= 0) {
this.instructionCount.length = this.depth;
}
}
incInstructionCount() {
var _a;
const count = (_a = this.instructionCount[this.depth - 1]) !== null && _a !== void 0 ? _a : 0;
this.instructionCount[this.depth - 1] = count + 1;
}
resetCount() {
this.instructionCount = [];
}
async addLine(line, error, cluster) {
const newLogs = [];
let newInstruction = false;
let newOuterInstruction = false;
const prefixBuilder = (depth) => {
const prefix = new Array(depth - 1).fill('\u00A0\u00A0').join('');
return prefix + '> ';
};
let prettyError;
if (error) {
prettyError = (0, program_err_1.getTransactionInstructionError)(error);
}
if (txExecutedRx.test(line)) {
this.resetCount();
}
if (line.startsWith('Program log:')) {
const log = {
prefix: prefixBuilder(this.depth),
text: line,
style: 'muted',
};
this.prettyLogs[this.prettyLogs.length - 1].logs.push(log);
newLogs.push(log);
}
else {
const regex = /Program (\w*) invoke \[(\d)\]/g;
const matches = [...line.matchAll(regex)];
if (matches.length > 0) {
// -----------------
// Invoke Instruction
// -----------------
this.incInstructionCount();
const programAddress = matches[0][1];
const programName = await this.prettyProgramLabel(programAddress, cluster);
if (this.depth === 0) {
this.prettyLogs.push({
logs: [],
failed: false,
});
}
else {
if (this.depth <= 1) {
newOuterInstruction = true;
}
newInstruction = true;
const log = {
prefix: prefixBuilder(this.depth),
style: 'info',
count: this.instructionCount.slice(),
text: `Invoking ${programName}`,
};
this.prettyLogs[this.prettyLogs.length - 1].logs.push(log);
newLogs.push(log);
}
this.incDepth();
}
else if (line.includes('success')) {
// -----------------
// Instruction Success
// -----------------
const log = {
prefix: prefixBuilder(this.depth),
style: 'success',
text: `Program returned success`,
};
this.prettyLogs[this.prettyLogs.length - 1].logs.push(log);
newLogs.push(log);
this.decDepth();
}
else if (line.includes('failed')) {
const instructionLog = this.prettyLogs[this.prettyLogs.length - 1];
if (!instructionLog.failed) {
instructionLog.failed = true;
const log = {
prefix: prefixBuilder(this.depth),
style: 'warning',
text: `Program returned error: ${line.slice(line.indexOf(': ') + 2)}`,
};
instructionLog.logs.push(log);
newLogs.push(log);
}
this.decDepth();
}
else {
if (this.depth === 0) {
this.prettyLogs.push({
logs: [],
failed: false,
});
this.incDepth();
}
// system transactions don't start with "Program log:"
const log = {
prefix: prefixBuilder(this.depth),
text: line,
style: 'muted',
};
this.prettyLogs[this.prettyLogs.length - 1].logs.push(log);
newLogs.push(log);
}
}
// If the instruction's simulation returned an error without any logs then add an empty log entry for Runtime error
// For example BpfUpgradableLoader fails without returning any logs for Upgrade instruction with buffer that doesn't exist
if (prettyError && this.prettyLogs.length === 0) {
this.prettyLogs.push({
logs: [],
failed: true,
});
}
if (prettyError && prettyError.index === this.prettyLogs.length - 1) {
const failedIx = this.prettyLogs[prettyError.index];
failedIx.failed = true;
const log = {
prefix: prefixBuilder(1),
text: `Runtime error: ${prettyError.message}`,
style: 'warning',
};
failedIx.logs.push(log);
newLogs.push(log);
}
return {
newLogs,
newInstruction,
newOuterInstruction,
};
}
async prettyProgramLabel(programAddress, cluster) {
const programName = (0, program_names_1.programLabel)(programAddress, cluster);
if (programName != null)
return programName;
const resolvedProgramName = this.amman != null
? await this.amman.addr.resolveRemoteAddress(programAddress)
: null;
return resolvedProgramName !== null && resolvedProgramName !== void 0 ? resolvedProgramName : `Unknown (${programAddress}) Program`;
}
}
exports.PrettyLogger = PrettyLogger;
//# sourceMappingURL=log-parser.js.map