Send front-end log messages to log file
This commit is contained in:
parent
4724576f72
commit
044f768768
7 changed files with 112 additions and 14 deletions
35
backend/src/api/log_it.rs
Normal file
35
backend/src/api/log_it.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use usdpl_back::core::serdes::Primitive;
|
||||||
|
|
||||||
|
use super::ApiParameterType;
|
||||||
|
|
||||||
|
/// API web method to send log messages to the back-end log, callable from the front-end
|
||||||
|
pub fn log_it() -> impl Fn(ApiParameterType) -> ApiParameterType {
|
||||||
|
move |params| {
|
||||||
|
if let Some(Primitive::F64(level)) = params.get(0) {
|
||||||
|
if let Some(Primitive::String(msg)) = params.get(1) {
|
||||||
|
log_msg_by_level(*level as u8, msg);
|
||||||
|
vec![true.into()]
|
||||||
|
} else if let Some(Primitive::Json(msg)) = params.get(1) {
|
||||||
|
log_msg_by_level(*level as u8, msg);
|
||||||
|
vec![true.into()]
|
||||||
|
} else {
|
||||||
|
log::warn!("Got log_it call with wrong/missing 2nd parameter");
|
||||||
|
vec![false.into()]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Got log_it call with wrong/missing 1st parameter");
|
||||||
|
vec![false.into()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log_msg_by_level(level: u8, msg: &str) {
|
||||||
|
match level {
|
||||||
|
1 => log::trace!("FRONT-END: {}", msg),
|
||||||
|
2 => log::debug!("FRONT-END: {}", msg),
|
||||||
|
3 => log::info!("FRONT-END: {}", msg),
|
||||||
|
4 => log::warn!("FRONT-END: {}", msg),
|
||||||
|
5 => log::error!("FRONT-END: {}", msg),
|
||||||
|
_ => log::trace!("FRONT-END: {}", msg),
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ mod about;
|
||||||
pub(crate) mod async_utils;
|
pub(crate) mod async_utils;
|
||||||
mod get_display;
|
mod get_display;
|
||||||
mod get_items;
|
mod get_items;
|
||||||
|
mod log_it;
|
||||||
mod on_event;
|
mod on_event;
|
||||||
mod on_javascript_result;
|
mod on_javascript_result;
|
||||||
mod on_update;
|
mod on_update;
|
||||||
|
@ -13,6 +14,7 @@ mod types;
|
||||||
pub use about::get_about;
|
pub use about::get_about;
|
||||||
pub use get_display::GetDisplayEndpoint;
|
pub use get_display::GetDisplayEndpoint;
|
||||||
pub use get_items::get_items;
|
pub use get_items::get_items;
|
||||||
|
pub use log_it::log_it;
|
||||||
pub use on_event::on_event;
|
pub use on_event::on_event;
|
||||||
pub use on_javascript_result::on_javascript_result;
|
pub use on_javascript_result::on_javascript_result;
|
||||||
pub use on_update::on_update;
|
pub use on_update::on_update;
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub fn on_event(sender: Sender<QueueItem>) -> impl Fn(ApiParameterType) -> ApiPa
|
||||||
vec![true.into()]
|
vec![true.into()]
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Failed to parse event json: {}", e);
|
log::error!("Failed to parse event json: {}", e);
|
||||||
vec![false.into()]
|
vec![false.into()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ fn main() -> Result<(), ()> {
|
||||||
.register_async("get_display", api::GetDisplayEndpoint::new(sender.clone()))
|
.register_async("get_display", api::GetDisplayEndpoint::new(sender.clone()))
|
||||||
.register_async("get_javascript_to_run", api::GetJavascriptEndpoint::new(sender.clone()))
|
.register_async("get_javascript_to_run", api::GetJavascriptEndpoint::new(sender.clone()))
|
||||||
.register_blocking("get_items", api::get_items(sender.clone()))
|
.register_blocking("get_items", api::get_items(sender.clone()))
|
||||||
|
.register("log", api::log_it())
|
||||||
.register("on_javascript_result", api::on_javascript_result(sender.clone()))
|
.register("on_javascript_result", api::on_javascript_result(sender.clone()))
|
||||||
.register("on_update", api::on_update(sender.clone()))
|
.register("on_update", api::on_update(sender.clone()))
|
||||||
.register("on_steam_event", api::on_event(sender.clone()))
|
.register("on_steam_event", api::on_event(sender.clone()))
|
||||||
|
|
2
main.py
2
main.py
|
@ -11,6 +11,6 @@ class Plugin:
|
||||||
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
||||||
async def _main(self):
|
async def _main(self):
|
||||||
# startup
|
# startup
|
||||||
#self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend", "--config", ""])
|
self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend", "--config", ""])
|
||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
|
@ -98,6 +98,14 @@ export type CJavascriptResult = {
|
||||||
|
|
||||||
export type CJavascriptResponse = CJavascriptResult | CErrorResult;
|
export type CJavascriptResponse = CJavascriptResult | CErrorResult;
|
||||||
|
|
||||||
|
export enum CLogLevel {
|
||||||
|
TRACE = 1,
|
||||||
|
DEBUG = 2,
|
||||||
|
INFO = 3,
|
||||||
|
WARN = 4,
|
||||||
|
ERROR = 5,
|
||||||
|
}
|
||||||
|
|
||||||
export async function getElements(): Promise<CElement[]> {
|
export async function getElements(): Promise<CElement[]> {
|
||||||
return (await call_backend("get_items", []))[0];
|
return (await call_backend("get_items", []))[0];
|
||||||
}
|
}
|
||||||
|
@ -129,3 +137,7 @@ export async function onJavascriptResult(id: number, value: any): Promise<boolea
|
||||||
export async function onSteamEvent(data: CSteamEvent): Promise<boolean> {
|
export async function onSteamEvent(data: CSteamEvent): Promise<boolean> {
|
||||||
return (await call_backend("on_steam_event", [data]))[0];
|
return (await call_backend("on_steam_event", [data]))[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function log(level: CLogLevel, msg: string): Promise<boolean> {
|
||||||
|
return (await call_backend("log", [level, msg]))[0];
|
||||||
|
}
|
||||||
|
|
|
@ -35,36 +35,58 @@ let update = () => {};
|
||||||
|
|
||||||
let updateTasks: (() => void)[] = [];
|
let updateTasks: (() => void)[] = [];
|
||||||
|
|
||||||
|
let displayErrors: number[] = [];
|
||||||
|
const DISPLAY_ERROR_ABORT_THRESHHOLD = 8;
|
||||||
|
|
||||||
function displayCallback(index: number) {
|
function displayCallback(index: number) {
|
||||||
return (newVal: backend.CDisplayResponse) => {
|
return (newVal: backend.CDisplayResponse) => {
|
||||||
if (newVal != null) {
|
if (newVal != null) {
|
||||||
switch (newVal.result) {
|
switch (newVal.result) {
|
||||||
case "value":
|
case "value":
|
||||||
|
displayErrors[index] = 0;
|
||||||
let val = newVal as backend.CValueResult;
|
let val = newVal as backend.CValueResult;
|
||||||
console.log("CAYLON: Got display for " + index.toString(), val);
|
console.log("CAYLON: Got display for " + index.toString(), val);
|
||||||
|
backend.log(backend.CLogLevel.DEBUG, "Got display for " + index.toString());
|
||||||
set_value(DISPLAY_KEY + index.toString(), val.value);
|
set_value(DISPLAY_KEY + index.toString(), val.value);
|
||||||
break;
|
break;
|
||||||
case "error":
|
case "error":
|
||||||
|
displayErrors[index]++;
|
||||||
let err = newVal as backend.CErrorResult;
|
let err = newVal as backend.CErrorResult;
|
||||||
console.warn("CAYLON: Got display error for " + index.toString(), err);
|
console.warn("CAYLON: Got display error for " + index.toString(), err);
|
||||||
|
backend.log(backend.CLogLevel.WARN, "Got display error for " + index.toString());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.error("CAYLON: Got invalid display response for " + index.toString(), newVal);
|
console.error("CAYLON: Got invalid display response for " + index.toString(), newVal);
|
||||||
|
backend.log(backend.CLogLevel.ERROR, "Got invalid display response for " + index.toString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
displayErrors[index]++;
|
||||||
console.warn("CAYLON: Ignoring null display result for " + index.toString());
|
console.warn("CAYLON: Ignoring null display result for " + index.toString());
|
||||||
|
backend.log(backend.CLogLevel.WARN, "Ignoring null display result for " + index.toString());
|
||||||
}
|
}
|
||||||
|
if (displayErrors[index] < DISPLAY_ERROR_ABORT_THRESHHOLD) {
|
||||||
updateTasks.push(() => backend.resolve(backend.getDisplay(index), displayCallback(index)));
|
updateTasks.push(() => backend.resolve(backend.getDisplay(index), displayCallback(index)));
|
||||||
update();
|
update();
|
||||||
|
} else {
|
||||||
|
console.error("CAYLON: Got too many display errors for " + index.toString() + ", stopping display updates for element");
|
||||||
|
backend.log(backend.CLogLevel.ERROR, "Got too many display errors for " + index.toString() + ", stopping display updates for element");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let jsErrors: number = 0;
|
||||||
|
const JAVASCRIPT_ERROR_ABORT_THRESHHOLD = 16;
|
||||||
|
|
||||||
function onGetElements() {
|
function onGetElements() {
|
||||||
|
displayErrors = [];
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
console.log("CAYLON: req display for item #" + i.toString());
|
console.log("CAYLON: req display for item #" + i.toString());
|
||||||
|
backend.log(backend.CLogLevel.DEBUG, "req display for item #" + i.toString());
|
||||||
|
displayErrors.push(0);
|
||||||
backend.resolve(backend.getDisplay(i), displayCallback(i));
|
backend.resolve(backend.getDisplay(i), displayCallback(i));
|
||||||
}
|
}
|
||||||
|
jsErrors = 0;
|
||||||
backend.resolve(backend.getJavascriptToRun(), jsCallback());
|
backend.resolve(backend.getJavascriptToRun(), jsCallback());
|
||||||
register_for_steam_events();
|
register_for_steam_events();
|
||||||
}
|
}
|
||||||
|
@ -73,24 +95,43 @@ const eval2 = eval;
|
||||||
|
|
||||||
function jsCallback() {
|
function jsCallback() {
|
||||||
return (script: backend.CJavascriptResponse) => {
|
return (script: backend.CJavascriptResponse) => {
|
||||||
|
// register next callback (before running JS, in case that crashes)
|
||||||
|
if (jsErrors < JAVASCRIPT_ERROR_ABORT_THRESHHOLD) {
|
||||||
|
backend.resolve(backend.getJavascriptToRun(), jsCallback());
|
||||||
|
} else {
|
||||||
|
console.error("CAYLON: Got too many javascript errors, stopping remote javascript execution");
|
||||||
|
backend.log(backend.CLogLevel.ERROR, "Got too many javascript errors, stopping remote javascript execution");
|
||||||
|
}
|
||||||
if (script != null) {
|
if (script != null) {
|
||||||
switch (script.result) {
|
switch (script.result) {
|
||||||
case "javascript":
|
case "javascript":
|
||||||
// register next callback (before running JS, in case that crashes)
|
|
||||||
backend.resolve(backend.getJavascriptToRun(), jsCallback());
|
|
||||||
let toRun = script as backend.CJavascriptResult;
|
let toRun = script as backend.CJavascriptResult;
|
||||||
console.log("CAYLON: Got javascript " + toRun.id.toString(), toRun);
|
console.log("CAYLON: Got javascript " + toRun.id.toString(), toRun);
|
||||||
|
backend.log(backend.CLogLevel.DEBUG, "Got javascript " + toRun.id.toString());
|
||||||
|
try {
|
||||||
let result = eval2(toRun.raw);
|
let result = eval2(toRun.raw);
|
||||||
backend.onJavascriptResult(toRun.id, result);
|
backend.onJavascriptResult(toRun.id, result);
|
||||||
|
jsErrors = 0;
|
||||||
|
} catch (err) {
|
||||||
|
jsErrors++;
|
||||||
|
console.warn("CAYLON: Javascript " + toRun.id.toString() + "failed", err);
|
||||||
|
backend.log(backend.CLogLevel.WARN, "Javascript " + toRun.id.toString() + "failed");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "error":
|
case "error":
|
||||||
|
jsErrors++;
|
||||||
let err = script as backend.CErrorResult;
|
let err = script as backend.CErrorResult;
|
||||||
console.warn("CAYLON: Got javascript retrieval error", err);
|
console.warn("CAYLON: Got javascript retrieval error", err);
|
||||||
|
backend.log(backend.CLogLevel.WARN, "Got javascript retrieval error");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
jsErrors++;
|
||||||
console.error("CAYLON: Got invalid javascript response", script);
|
console.error("CAYLON: Got invalid javascript response", script);
|
||||||
|
backend.log(backend.CLogLevel.ERROR, "Got invalid javascript response");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
jsErrors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,14 +143,17 @@ function jsCallback() {
|
||||||
let about_promise = backend.getAbout();
|
let about_promise = backend.getAbout();
|
||||||
let elements_promise = backend.getElements();
|
let elements_promise = backend.getElements();
|
||||||
about = await about_promise;
|
about = await about_promise;
|
||||||
console.log("CAYLON: got about", about);
|
console.log("CAYLON: Got about", about);
|
||||||
|
backend.log(backend.CLogLevel.DEBUG, "Got about");
|
||||||
let result = await elements_promise;
|
let result = await elements_promise;
|
||||||
console.log("CAYLON: got elements", result);
|
console.log("CAYLON: Got elements", result);
|
||||||
|
backend.log(backend.CLogLevel.DEBUG, "Got elements");
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
items = result;
|
items = result;
|
||||||
onGetElements();
|
onGetElements();
|
||||||
} else {
|
} else {
|
||||||
console.warn("CAYLON: backend connection failed");
|
console.error("CAYLON: Backend connection failed");
|
||||||
|
backend.log(backend.CLogLevel.ERROR, "Backend connection failed");
|
||||||
}
|
}
|
||||||
backend.resolve(backend.getJavascriptToRun(), jsCallback());
|
backend.resolve(backend.getJavascriptToRun(), jsCallback());
|
||||||
register_for_steam_events();
|
register_for_steam_events();
|
||||||
|
@ -149,19 +193,22 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
||||||
backend.resolve(backend.reload(),
|
backend.resolve(backend.reload(),
|
||||||
(reload_items: backend.CElement[]) => {
|
(reload_items: backend.CElement[]) => {
|
||||||
items = reload_items;
|
items = reload_items;
|
||||||
console.log("CAYLON: got elements", reload_items);
|
console.log("CAYLON: Got elements", reload_items);
|
||||||
|
backend.log(backend.CLogLevel.DEBUG, "Got elements for reload");
|
||||||
if (reload_items != null) {
|
if (reload_items != null) {
|
||||||
items = reload_items;
|
items = reload_items;
|
||||||
onGetElements();
|
onGetElements();
|
||||||
} else {
|
} else {
|
||||||
console.warn("CAYLON: backend connection failed");
|
console.error("CAYLON: Backend connection failed");
|
||||||
|
backend.log(backend.CLogLevel.ERROR, "Backend connection failed on reload");
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
});
|
});
|
||||||
backend.resolve(backend.getAbout(),
|
backend.resolve(backend.getAbout(),
|
||||||
(new_about: backend.CAbout) => {
|
(new_about: backend.CAbout) => {
|
||||||
about = new_about;
|
about = new_about;
|
||||||
console.log("CAYLON: got about", about);
|
console.log("CAYLON: Got about", about);
|
||||||
|
backend.log(backend.CLogLevel.DEBUG, "Got about for reload");
|
||||||
update();
|
update();
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
|
@ -188,6 +235,7 @@ function buildHtmlElement(element: backend.CElement, index: number, updateIdc: a
|
||||||
return buildEventDisplay(element as backend.CEventDisplay, index, updateIdc);
|
return buildEventDisplay(element as backend.CEventDisplay, index, updateIdc);
|
||||||
}
|
}
|
||||||
console.error("CAYLON: Unsupported element", element);
|
console.error("CAYLON: Unsupported element", element);
|
||||||
|
backend.log(backend.CLogLevel.ERROR, "Unsupported element " + element.element);
|
||||||
return <div>Unsupported</div>;
|
return <div>Unsupported</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue