Ver Fonte

Finish up event logs

ghorsington há 4 anos atrás
pai
commit
cf1d35e8ee

+ 1 - 2
bot/src/main.ts

@@ -7,7 +7,7 @@ import { client } from "./client";
 import { createConnection, getConnectionOptions } from "typeorm";
 import { DB_ENTITIES } from "@shared/db/entities";
 import { assertOk } from "@shared/common/async_utils";
-import { eventLogger, logger } from "./logging";
+import { logger } from "./logging";
 import { PluginManager } from "./plugin_manager";
 import { startRpcServer } from "./rpc";
 
@@ -16,7 +16,6 @@ export const COMMAND_PREFIX = "/";
 
 client.bot.on("ready", async () => {
     logger.info("Starting up NoctBot");
-    eventLogger.info("Started");
     await client.botUser.setActivity(`@${client.botUser.username} help`, { type: "PLAYING" });
     await assertOk(plgMgr.start(client.bot));
     logger.info("NoctBot is ready");

+ 1 - 2
web/src/routes/login/discord_auth.svelte

@@ -1,9 +1,8 @@
 <script lang="typescript">
   import Icon from "svelte-awesome/components/Icon.svelte";
   import { faSpinner } from "@fortawesome/free-solid-svg-icons";
-  import { onMount, tick } from "svelte";
+  import { onMount } from "svelte";
   import { Option } from "@shared/common/async_utils";
-  import { goto } from "@sapper/app";
 
   const spinner = (faSpinner as unknown) as undefined;
   let error = "";

+ 122 - 26
web/src/routes/logs.svelte

@@ -1,11 +1,55 @@
 <script lang="typescript">
-    import type { PollOptions, PollResult, LogEvent } from "src/routes/logs/poll";
+    import type {
+        PollOptions,
+        PollResult,
+        LogEvent,
+    } from "src/routes/logs/poll";
+    import { faSyncAlt } from "@fortawesome/free-solid-svg-icons";
+    import Icon from "svelte-awesome/components/Icon.svelte";
 
-    let logEvents: LogEvent[] = [];
+    const sync = (faSyncAlt as unknown) as undefined;
+    const POLL_INTERVAL = 5000;
+    let logEvents: LogEvent[] | undefined = undefined;
+    let syncing = false;
+    let poller = 0;
+    let maxMessages = 50;
+    let error = "";
+
+    const LEVEL_COLORS: Record<string, string> = {
+        "info": "#EFF2F7",
+        "warn": "#ECC94B",
+        "error": "#C53030",
+    };
+
+    function getLevelColor(level: string) {
+        if (level in LEVEL_COLORS) {
+            return LEVEL_COLORS[level];
+        }
+        return "#FFFFFF";
+    }
+
+    function onAutoUpdateChecked(event: Event & { target: HTMLInputElement }) {
+        if (event.target.checked) {
+            const pollCallback = async () => {
+                await pollEvents();
+                poller = setTimeout(pollCallback, POLL_INTERVAL);    
+            }
+            if (poller >= 0) {
+                poller = setTimeout(pollCallback, POLL_INTERVAL);
+            }
+        } else {
+            clearTimeout(poller);
+            poller = -1;
+        }
+    }
 
     async function pollEvents() {
+        if (syncing) {
+            return;
+        }
+        syncing = true;
         const params: PollOptions = {
-            limit: "50",
+            limit: maxMessages.toString(),
         };
         const query = Object.entries(params).reduce(
             (prev, [key, val]) =>
@@ -22,42 +66,94 @@
         });
 
         const result = (await response.json()) as PollResult;
-        console.log(result);
         if (result.ok) {
             logEvents = result.events;
+        } else {
+            error = result.error;
         }
+        syncing = false;
     }
 </script>
 
 <style>
+    .sync-button {
+        @apply bg-blue-600 py-1 px-3 text-white cursor-pointer rounded-sm text-sm;
+
+        &:hover {
+            @apply bg-blue-700 text-gray-100;
+        }
+    }
+
+    .logs-table {
+        @apply bg-black m-3 block overflow-y-auto;
+        max-height: 70%;
+
+        td,
+        th {
+            @apply font-mono px-2 text-sm;
+        }
+
+        thead th {
+            @apply sticky top-0 bg-black py-2;
+        }
+    }
+
+    .error-box {
+        @apply text-gray-100 bg-red-600 py-4 px-3 rounded-sm;
+    }
+
+    .query-row {
+        @apply flex flex-row justify-end items-center;
+    }
+
+    .event-log-options {
+        @apply flex flex-col;
+
+        input[type="number"] {
+            @apply text-black w-16;
+        }
+    }
 </style>
 
 <div class="viewport text-white">
     <h1 class="text-3xl pb-4">Event logs</h1>
     <form class="py-2" on:submit|preventDefault={pollEvents}>
-        <input
-            class="bg-blue-600 py-2 px-3 text-white cursor-pointer rounded-sm"
-            type="submit"
-            value="Query" />
+        <div class="event-log-options">
+            <label>Max messages: <input type="number" min="0" bind:value={maxMessages} /></label>
+        </div>
+        <div class="query-row">
+            {#if syncing}
+                <Icon class="mx-1" data={sync} spin />
+            {/if}
+            <input class="sync-button" type="submit" value="Query" disabled={syncing} />
+            <label class="mx-1"><input type="checkbox" on:input={onAutoUpdateChecked}/> Auto update</label>
+        </div>
     </form>
-    <table class="py-3">
-        <thead>
-            <tr>
-                <th>Source</th>
-                <th>Timestamp</th>
-                <th>Level</th>
-                <th>Message</th>
-            </tr>
-        </thead>
-        <tbody>
-            {#each logEvents as logEvent (logEvent._id)}
+    {#if error}
+        <p class="error-box">
+            Failed to query: <span class="font-mono">{error}</span>
+        </p>
+    {/if}
+    {#if logEvents}
+        <table class="logs-table">
+            <thead>
                 <tr>
-                    <td>{logEvent.label}</td>
-                    <td>{logEvent.timestamp}</td>
-                    <td>{logEvent.level}</td>
-                    <td>{logEvent.message}</td>
+                    <th>Timestamp</th>
+                    <th>Source</th>
+                    <th>Level</th>
+                    <th>Message</th>
                 </tr>
-            {/each}
-        </tbody>
-    </table>
+            </thead>
+            <tbody>
+                {#each logEvents as logEvent (logEvent._id)}
+                    <tr style="color: {getLevelColor(logEvent.level)};">
+                        <td>{logEvent.timestamp}</td>
+                        <td>{logEvent.label}</td>
+                        <td>{logEvent.level}</td>
+                        <td>{logEvent.message}</td>
+                    </tr>
+                {/each}
+            </tbody>
+        </table>
+    {/if}
 </div>

+ 0 - 1
web/src/routes/rules/index.svelte

@@ -24,7 +24,6 @@
 
 <script lang="typescript">
   import { Converter } from "showdown";
-  import { onMount, tick } from "svelte";
   import Icon from "svelte-awesome/components/Icon.svelte";
   import { faSpinner } from "@fortawesome/free-solid-svg-icons";
   import { fade } from "svelte/transition";

+ 0 - 1
web/src/server.ts

@@ -17,7 +17,6 @@ const PORT = process.env.PORT; // eslint-disable-line prefer-destructuring
 const dev = process.env.NODE_ENV === "development";
 
 logger.info("Staring webserver to port %s", PORT);
-eventLogger.info("Started");
 
 const key = process.env.WEB_COOKIE_KEY;