diff --git a/maubot/management/api/log.py b/maubot/management/api/log.py
index 467f16e..572bf87 100644
--- a/maubot/management/api/log.py
+++ b/maubot/management/api/log.py
@@ -38,6 +38,12 @@ class WebSocketHandler(logging.Handler):
self.formatter = logging.Formatter()
def emit(self, record: logging.LogRecord) -> None:
+ try:
+ self._emit(record)
+ except Exception as e:
+ print("Logging error:", e)
+
+ def _emit(self, record: logging.LogRecord) -> None:
# JSON conversion based on Marsel Mavletkulov's json-log-formatter (MIT license)
# https://github.com/marselester/json-log-formatter
content = {
@@ -45,6 +51,7 @@ class WebSocketHandler(logging.Handler):
for name, value in record.__dict__.items()
if name not in EXCLUDE_ATTRS
}
+ content["id"] = record.relativeCreated
content["msg"] = record.getMessage()
content["time"] = datetime.utcnow()
@@ -61,7 +68,7 @@ class WebSocketHandler(logging.Handler):
try:
await self.ws.send_json(record)
except Exception as e:
- pass
+ print("Log sending error:", e)
log_root = logging.getLogger("maubot")
diff --git a/maubot/management/frontend/src/api.js b/maubot/management/frontend/src/api.js
index fc4e518..0992233 100644
--- a/maubot/management/frontend/src/api.js
+++ b/maubot/management/frontend/src/api.js
@@ -82,6 +82,7 @@ export async function openLogSocket() {
socket: null,
connected: false,
authenticated: false,
+ onLog: data => {},
fails: -1,
}
const openHandler = () => {
@@ -100,7 +101,9 @@ export async function openLogSocket() {
console.info("Websocket connection authentication failed")
}
} else {
+ data.time = new Date(data.time)
console.log("SERVLOG", data)
+ wrapper.onLog(data)
}
}
const closeHandler = evt => {
diff --git a/maubot/management/frontend/src/pages/dashboard/Client.js b/maubot/management/frontend/src/pages/dashboard/Client.js
index 0424911..45bf10e 100644
--- a/maubot/management/frontend/src/pages/dashboard/Client.js
+++ b/maubot/management/frontend/src/pages/dashboard/Client.js
@@ -21,6 +21,7 @@ import { PrefTable, PrefSwitch, PrefInput } from "../../components/PreferenceTab
import Spinner from "../../components/Spinner"
import api from "../../api"
import BaseMainView from "./BaseMainView"
+import Log from "./Log"
const ClientListEntry = ({ entry }) => {
const classes = ["client", "entry"]
@@ -200,14 +201,17 @@ class Client extends BaseMainView {
>
render() {
- return
- {this.renderSidebar()}
-
- {this.renderPreferences()}
- {this.renderPrefButtons()}
- {this.renderInstances()}
+ return <>
+
+ {this.renderSidebar()}
+
+ {this.renderPreferences()}
+ {this.renderPrefButtons()}
+ {this.renderInstances()}
+
-
+
+ >
}
}
diff --git a/maubot/management/frontend/src/pages/dashboard/Home.js b/maubot/management/frontend/src/pages/dashboard/Home.js
new file mode 100644
index 0000000..f1a4fad
--- /dev/null
+++ b/maubot/management/frontend/src/pages/dashboard/Home.js
@@ -0,0 +1,30 @@
+// maubot - A plugin-based Matrix bot system.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+import React, { Component } from "react"
+import Log from "./Log"
+
+class Home extends Component {
+ render() {
+ return <>
+
+ See sidebar to get started
+
+
+ >
+ }
+}
+
+export default Home
diff --git a/maubot/management/frontend/src/pages/dashboard/Instance.js b/maubot/management/frontend/src/pages/dashboard/Instance.js
index 8f1ed42..58463be 100644
--- a/maubot/management/frontend/src/pages/dashboard/Instance.js
+++ b/maubot/management/frontend/src/pages/dashboard/Instance.js
@@ -23,6 +23,7 @@ import PrefTable, { PrefInput, PrefSelect, PrefSwitch } from "../../components/P
import api from "../../api"
import Spinner from "../../components/Spinner"
import BaseMainView from "./BaseMainView"
+import Log from "./Log"
const InstanceListEntry = ({ entry }) => (
@@ -167,6 +168,7 @@ class Instance extends BaseMainView {
{this.state.error}
+
}
}
diff --git a/maubot/management/frontend/src/pages/dashboard/Log.js b/maubot/management/frontend/src/pages/dashboard/Log.js
new file mode 100644
index 0000000..9b1929c
--- /dev/null
+++ b/maubot/management/frontend/src/pages/dashboard/Log.js
@@ -0,0 +1,29 @@
+// maubot - A plugin-based Matrix bot system.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+import React from "react"
+
+const Log = ({ lines, showName = true }) =>
+ {lines.map(data =>
+
+ {data.time.toLocaleTimeString()}
+ {data.levelname}
+ {showName && {data.name}}
+ {data.msg}
+
,
+ )}
+
+
+export default Log
diff --git a/maubot/management/frontend/src/pages/dashboard/Plugin.js b/maubot/management/frontend/src/pages/dashboard/Plugin.js
index aac38cf..4ca7f6a 100644
--- a/maubot/management/frontend/src/pages/dashboard/Plugin.js
+++ b/maubot/management/frontend/src/pages/dashboard/Plugin.js
@@ -21,6 +21,7 @@ import PrefTable, { PrefInput } from "../../components/PreferenceTable"
import Spinner from "../../components/Spinner"
import api from "../../api"
import BaseMainView from "./BaseMainView"
+import Log from "./Log"
const PluginListEntry = ({ entry }) => (
@@ -90,6 +91,7 @@ class Plugin extends BaseMainView {
}
{this.state.error}
{!this.isNew && this.renderInstances()}
+
}
}
diff --git a/maubot/management/frontend/src/pages/dashboard/index.js b/maubot/management/frontend/src/pages/dashboard/index.js
index 26b70fa..232923e 100644
--- a/maubot/management/frontend/src/pages/dashboard/index.js
+++ b/maubot/management/frontend/src/pages/dashboard/index.js
@@ -20,6 +20,7 @@ import { ReactComponent as Plus } from "../../res/plus.svg"
import Instance from "./Instance"
import Client from "./Client"
import Plugin from "./Plugin"
+import Home from "./Home"
class Dashboard extends Component {
constructor(props) {
@@ -30,6 +31,8 @@ class Dashboard extends Component {
plugins: {},
sidebarOpen: false,
}
+ this.logLines = []
+ this.logMap = {}
window.maubot = this
}
@@ -55,9 +58,13 @@ class Dashboard extends Component {
plugins[plugin.id] = plugin
}
this.setState({ instances, clients, plugins })
+
const logs = await api.openLogSocket()
- console.log("WebSocket opened:", logs)
- window.logs = logs
+ logs.onLog = data => {
+ this.logLines.push(data)
+ ;(this.logMap[data.name] || (this.logMap[data.name] = [])).push(data)
+ this.setState({})
+ }
}
renderList(field, type) {
@@ -85,11 +92,13 @@ class Dashboard extends Component {
if (!entry) {
return this.renderNotFound(field.slice(0, -1))
}
+ console.log(`maubot.${field.slice(0, -1)}.${id}`)
return React.createElement(type, {
entry,
onDelete: () => this.delete(field, id),
onChange: newEntry => this.add(field, newEntry, id),
ctx: this.state,
+ log: this.logMap[`maubot.${field.slice(0, -1)}.${id}`] || [],
})
}
@@ -142,7 +151,7 @@ class Dashboard extends Component {
- "Hello, World!"}/>
+ }/>
this.add("instances", newEntry)}
ctx={this.state}/>}/>
diff --git a/maubot/management/frontend/src/style/pages/dashboard.sass b/maubot/management/frontend/src/style/pages/dashboard.sass
index 31f15bb..3ab03fa 100644
--- a/maubot/management/frontend/src/style/pages/dashboard.sass
+++ b/maubot/management/frontend/src/style/pages/dashboard.sass
@@ -78,17 +78,38 @@
@import instance
@import plugin
- > .not-found
- text-align: center
- margin-top: 5rem
- font-size: 1.5rem
-
- > div:not(.not-found)
+ > div
margin: 2rem 4rem
@media screen and (max-width: 50rem)
margin: 2rem 1rem
+ div.log > div.row
+ span.level, span.logger
+ display: none
+
+ > div.not-found, > div.home
+ text-align: center
+ margin-top: 5rem
+ font-size: 1.5rem
+
+ div.log
+ text-align: left
+ font-size: 12px
+ max-height: 20rem
+ font-family: "Fira Code", monospace
+ overflow: auto
+
+ > div.row
+ white-space: nowrap
+
+ > span.level:before
+ content: " ["
+ > span.logger:before
+ content: "@"
+ > span.text:before
+ content: "] "
+
div.buttons
+button-group
display: flex