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;
|
||||
mod get_display;
|
||||
mod get_items;
|
||||
mod log_it;
|
||||
mod on_event;
|
||||
mod on_javascript_result;
|
||||
mod on_update;
|
||||
|
@ -13,6 +14,7 @@ mod types;
|
|||
pub use about::get_about;
|
||||
pub use get_display::GetDisplayEndpoint;
|
||||
pub use get_items::get_items;
|
||||
pub use log_it::log_it;
|
||||
pub use on_event::on_event;
|
||||
pub use on_javascript_result::on_javascript_result;
|
||||
pub use on_update::on_update;
|
||||
|
|
|
@ -25,7 +25,7 @@ pub fn on_event(sender: Sender<QueueItem>) -> impl Fn(ApiParameterType) -> ApiPa
|
|||
vec![true.into()]
|
||||
},
|
||||
Err(e) => {
|
||||
log::warn!("Failed to parse event json: {}", e);
|
||||
log::error!("Failed to parse event json: {}", e);
|
||||
vec![false.into()]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ fn main() -> Result<(), ()> {
|
|||
.register_async("get_display", api::GetDisplayEndpoint::new(sender.clone()))
|
||||
.register_async("get_javascript_to_run", api::GetJavascriptEndpoint::new(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_update", api::on_update(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
|
||||
async def _main(self):
|
||||
# startup
|
||||
#self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend", "--config", ""])
|
||||
self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend", "--config", ""])
|
||||
while True:
|
||||
await asyncio.sleep(1)
|
||||
|
|
|
@ -98,6 +98,14 @@ export type CJavascriptResult = {
|
|||
|
||||
export type CJavascriptResponse = CJavascriptResult | CErrorResult;
|
||||
|
||||
export enum CLogLevel {
|
||||
TRACE = 1,
|
||||
DEBUG = 2,
|
||||
INFO = 3,
|
||||
WARN = 4,
|
||||
ERROR = 5,
|
||||
}
|
||||
|
||||
export async function getElements(): Promise<CElement[]> {
|
||||
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> {
|
||||
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 displayErrors: number[] = [];
|
||||
const DISPLAY_ERROR_ABORT_THRESHHOLD = 8;
|
||||
|
||||
function displayCallback(index: number) {
|
||||
return (newVal: backend.CDisplayResponse) => {
|
||||
if (newVal != null) {
|
||||
switch (newVal.result) {
|
||||
case "value":
|
||||
displayErrors[index] = 0;
|
||||
let val = newVal as backend.CValueResult;
|
||||
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);
|
||||
break;
|
||||
case "error":
|
||||
displayErrors[index]++;
|
||||
let err = newVal as backend.CErrorResult;
|
||||
console.warn("CAYLON: Got display error for " + index.toString(), err);
|
||||
backend.log(backend.CLogLevel.WARN, "Got display error for " + index.toString());
|
||||
break;
|
||||
default:
|
||||
console.error("CAYLON: Got invalid display response for " + index.toString(), newVal);
|
||||
backend.log(backend.CLogLevel.ERROR, "Got invalid display response for " + index.toString());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
displayErrors[index]++;
|
||||
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)));
|
||||
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");
|
||||
}
|
||||
updateTasks.push(() => backend.resolve(backend.getDisplay(index), displayCallback(index)));
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
let jsErrors: number = 0;
|
||||
const JAVASCRIPT_ERROR_ABORT_THRESHHOLD = 16;
|
||||
|
||||
function onGetElements() {
|
||||
displayErrors = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
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));
|
||||
}
|
||||
jsErrors = 0;
|
||||
backend.resolve(backend.getJavascriptToRun(), jsCallback());
|
||||
register_for_steam_events();
|
||||
}
|
||||
|
@ -73,24 +95,43 @@ const eval2 = eval;
|
|||
|
||||
function jsCallback() {
|
||||
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) {
|
||||
switch (script.result) {
|
||||
case "javascript":
|
||||
// register next callback (before running JS, in case that crashes)
|
||||
backend.resolve(backend.getJavascriptToRun(), jsCallback());
|
||||
let toRun = script as backend.CJavascriptResult;
|
||||
console.log("CAYLON: Got javascript " + toRun.id.toString(), toRun);
|
||||
let result = eval2(toRun.raw);
|
||||
backend.onJavascriptResult(toRun.id, result);
|
||||
backend.log(backend.CLogLevel.DEBUG, "Got javascript " + toRun.id.toString());
|
||||
try {
|
||||
let result = eval2(toRun.raw);
|
||||
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;
|
||||
case "error":
|
||||
jsErrors++;
|
||||
let err = script as backend.CErrorResult;
|
||||
console.warn("CAYLON: Got javascript retrieval error", err);
|
||||
backend.log(backend.CLogLevel.WARN, "Got javascript retrieval error");
|
||||
break;
|
||||
default:
|
||||
jsErrors++;
|
||||
console.error("CAYLON: Got invalid javascript response", script);
|
||||
backend.log(backend.CLogLevel.ERROR, "Got invalid javascript response");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
jsErrors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,14 +143,17 @@ function jsCallback() {
|
|||
let about_promise = backend.getAbout();
|
||||
let elements_promise = backend.getElements();
|
||||
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;
|
||||
console.log("CAYLON: got elements", result);
|
||||
console.log("CAYLON: Got elements", result);
|
||||
backend.log(backend.CLogLevel.DEBUG, "Got elements");
|
||||
if (result != null) {
|
||||
items = result;
|
||||
onGetElements();
|
||||
} 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());
|
||||
register_for_steam_events();
|
||||
|
@ -149,19 +193,22 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
|||
backend.resolve(backend.reload(),
|
||||
(reload_items: backend.CElement[]) => {
|
||||
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) {
|
||||
items = reload_items;
|
||||
onGetElements();
|
||||
} else {
|
||||
console.warn("CAYLON: backend connection failed");
|
||||
console.error("CAYLON: Backend connection failed");
|
||||
backend.log(backend.CLogLevel.ERROR, "Backend connection failed on reload");
|
||||
}
|
||||
update();
|
||||
});
|
||||
backend.resolve(backend.getAbout(),
|
||||
(new_about: backend.CAbout) => {
|
||||
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();
|
||||
});
|
||||
}}>
|
||||
|
@ -188,6 +235,7 @@ function buildHtmlElement(element: backend.CElement, index: number, updateIdc: a
|
|||
return buildEventDisplay(element as backend.CEventDisplay, index, updateIdc);
|
||||
}
|
||||
console.error("CAYLON: Unsupported element", element);
|
||||
backend.log(backend.CLogLevel.ERROR, "Unsupported element " + element.element);
|
||||
return <div>Unsupported</div>;
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue