diff --git a/packages/web_ui/src/components/InstanceViewPage.tsx b/packages/web_ui/src/components/InstanceViewPage.tsx index 98a4b720..ef55c97e 100644 --- a/packages/web_ui/src/components/InstanceViewPage.tsx +++ b/packages/web_ui/src/components/InstanceViewPage.tsx @@ -1,7 +1,8 @@ import React, { useContext, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { - Alert, Button, Descriptions, Dropdown, Flex, MenuProps, Modal, Space, Spin, Switch, Typography, message, + Alert, Button, Descriptions, Dropdown, Flex, MenuProps, Modal, Segmented, Space, Spin, Tooltip, Typography, + message, } from "antd"; import CopyOutlined from "@ant-design/icons/CopyOutlined"; import DeleteOutlined from "@ant-design/icons/DeleteOutlined"; @@ -34,7 +35,7 @@ import { MetricRelativeDate } from "./system_metrics"; type MenuItem = Required["items"][number]; const { Title } = Typography; -// Remembers the console "Chat/Log" toggle across reloads (defaults to on). +// Remembers the console "Game/Instance" selection across reloads (defaults to game). const consoleActionsOnlyKey = "instance-console-actions-only"; type InstanceDescriptionProps = { @@ -249,12 +250,21 @@ export default function InstanceViewPage() { { account.hasPermission("core.log.follow") && - + + setActionsOnly(value === "game")} + options={[ + { label: "Game", value: "game" }, + { label: "Instance", value: "instance" }, + ]} + /> + {parsed.time.padStart(8)} ; @@ -51,7 +51,7 @@ function formatParsedOutput(parsed: Parsed, key: number) { info = <>[{parsed.action}] ; } - return {time}{info}{parsed.message}
; + return <>{time}{info}{parsed.message}; } type Info = { @@ -61,11 +61,27 @@ type Info = { }; function formatLog(info: Info, key: number): ReactElement { - if (info.level === "server" && info.parsed) { - return formatParsedOutput(info.parsed, key); - } let level = {info.level}; - return [{level}] {info.message}
; + let message = info.level === "server" && info.parsed ? formatParsedOutput(info.parsed) : info.message; + return [{level}] {message}
; +} + +/** + * Test if a log entry survives the console's actions only filter + */ +function passesActionsOnly(info: Info) { + // Clusterio's own entries are bookkeeping, only keep those reporting a problem. + if (info.level !== "server") { + return lib.levels[info.level] <= lib.levels.warn; + } + + // Factorio's seconds stamped engine log is verbose diagnostics, only keep warnings and errors. + if (info.parsed?.format === "seconds") { + return info.parsed.level === "Warning" || info.parsed.level === "Error"; + } + + // What is left is the date stamped console log: the actions done to the server and the replies to them. + return true; } type LogConsoleProps = { @@ -159,11 +175,7 @@ export default function LogConsole(props: LogConsoleProps) { "desc", )).then(result => { setPastLines(result.log - .filter(info => ( - !props.actionsOnly - || (info as Info).level !== "server" - || (info as Info).parsed?.type === "action" - )) + .filter(info => !props.actionsOnly || passesActionsOnly(info as Info)) .map((info, index) => formatLog(info as Info, -index - 1)) .reverse() ); @@ -175,7 +187,7 @@ export default function LogConsole(props: LogConsoleProps) { } function logHandler(info: Info) { - if (!props.actionsOnly || info.level !== "server" || info.parsed?.type === "action") { + if (!props.actionsOnly || passesActionsOnly(info)) { setLines(currentLines => currentLines.concat( [formatLog(info, currentLines.length)] )); diff --git a/packages/web_ui/src/style.css b/packages/web_ui/src/style.css index 53cd7cdc..5553ceff 100644 --- a/packages/web_ui/src/style.css +++ b/packages/web_ui/src/style.css @@ -257,6 +257,10 @@ body { color: #ad3939; } +.log-server { + font-weight: bold; +} + .log-fatal { font-weight: bold; background-color: #ad3939;