initial version of structured log display
This commit is contained in:
parent
518ad1d811
commit
f5fe1c4f29
2 changed files with 134 additions and 1 deletions
|
@ -4,6 +4,8 @@
|
|||
export let matchLog: string;
|
||||
let playerLog: PlayerLog;
|
||||
|
||||
let showRawStderr = false;
|
||||
|
||||
$: if (matchLog) {
|
||||
playerLog = parsePlayerLog(1, matchLog);
|
||||
} else {
|
||||
|
@ -13,9 +15,38 @@
|
|||
|
||||
<div class="output">
|
||||
<h3 class="output-header">Player log</h3>
|
||||
{#if showRawStderr}
|
||||
<div class="output-text stderr-text">
|
||||
{playerLog.flatMap((turn) => turn.stderr).join("\n")}
|
||||
</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>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -26,15 +57,62 @@
|
|||
padding: 15px;
|
||||
}
|
||||
|
||||
.turn {
|
||||
margin: 16px 4px;
|
||||
}
|
||||
|
||||
.output-text {
|
||||
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 {
|
||||
font-family: monospace;
|
||||
// font-family: monospace;
|
||||
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
|
||||
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 {
|
||||
color: #eee;
|
||||
padding-bottom: 20px;
|
||||
|
|
55
web/pw-server/src/lib/log_parser.ts
Normal file
55
web/pw-server/src/lib/log_parser.ts
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue