initial version of structured log display

This commit is contained in:
Ilion Beyst 2022-09-17 11:55:17 +02:00
parent 518ad1d811
commit f5fe1c4f29
2 changed files with 134 additions and 1 deletions

View file

@ -4,6 +4,8 @@
export let matchLog: string; export let matchLog: string;
let playerLog: PlayerLog; let playerLog: PlayerLog;
let showRawStderr = false;
$: if (matchLog) { $: if (matchLog) {
playerLog = parsePlayerLog(1, matchLog); playerLog = parsePlayerLog(1, matchLog);
} else { } else {
@ -13,9 +15,38 @@
<div class="output"> <div class="output">
<h3 class="output-header">Player log</h3> <h3 class="output-header">Player log</h3>
{#if showRawStderr}
<div class="output-text stderr-text"> <div class="output-text stderr-text">
{playerLog.flatMap((turn) => turn.stderr).join("\n")} {playerLog.flatMap((turn) => turn.stderr).join("\n")}
</div> </div>
{:else}
<div class="output-text">
{#each playerLog as logTurn, i}
<div class="turn">
<div class="turn-header">
<span class="turn-header-text">Turn {i}</span>
{#if logTurn.action?.type === "bad_command"}
<span class="turn-error">invalid command</span>
{/if}
</div>
{#if logTurn.action?.type === "bad_command"}
<div class="bad-command-container">
<div class="bad-command-text">{logTurn.action.command}</div>
<div class="bad-command-error">Parse error: {logTurn.action.error}</div>
</div>
{/if}
{#if logTurn.stderr.length > 0}
<div class="stderr-header">stderr</div>
<div class="stderr-text-box">
{#each logTurn.stderr as stdErrMsg}
<div class="stderr-text">{stdErrMsg}</div>
{/each}
</div>
{/if}
</div>
{/each}
</div>
{/if}
</div> </div>
<style lang="scss"> <style lang="scss">
@ -26,15 +57,62 @@
padding: 15px; padding: 15px;
} }
.turn {
margin: 16px 4px;
}
.output-text { .output-text {
color: #ccc; color: #ccc;
} }
.turn-header {
display: flex;
justify-content: space-between;
}
.turn-header-text {
color: #eee;
font-size: 14px;
font-weight: 600;
text-transform: uppercase;
}
.turn-error {
color: red;
}
.bad-command-container {
border-left: 1px solid red;
margin-left: 4px;
padding-left: 8px;
}
.bad-command-text {
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
padding-bottom: 4px;
}
.bad-command-error {
color: whitesmoke;
}
.stderr-text { .stderr-text {
font-family: monospace; // font-family: monospace;
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
white-space: pre-wrap; white-space: pre-wrap;
} }
.stderr-header {
color: #eee;
padding-top: 4px;
}
.stderr-text-box {
border-left: 1px solid #ccc;
margin-left: 4px;
padding-left: 8px;
}
.output-header { .output-header {
color: #eee; color: #eee;
padding-bottom: 20px; padding-bottom: 20px;

View file

@ -0,0 +1,55 @@
export type PlayerLog = PlayerLogTurn[];
export type PlayerLogTurn = {
action?: PlayerAction;
stderr: string[];
};
type PlayerAction = BadCommand;
type BadCommand = {
type: "bad_command";
command: string;
error: string;
};
function createEmptyLogTurn(): PlayerLogTurn {
return {
stderr: [],
};
}
export function parsePlayerLog(playerId: number, logText: string): PlayerLog {
const logLines = logText.split("\n").slice(0, -1);
const playerLog: PlayerLog = [];
let turn = null;
logLines.forEach((logLine) => {
const logMessage = JSON.parse(logLine);
if (logMessage["type"] === "gamestate") {
if (turn) {
playerLog.push(turn);
turn = createEmptyLogTurn();
}
} else if (logMessage["player_id"] === playerId) {
if (!turn) {
// older match logs don't have an initial game state due to a bug.
turn = createEmptyLogTurn();
}
switch (logMessage["type"]) {
case "stderr": {
let msg = logMessage["message"];
turn.stderr.push(msg);
}
case "bad_command": {
turn.action = logMessage;
}
}
}
});
return playerLog;
}