UNPKG

@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
"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