Commit e984e3170c4d44990f2f042a3ecd8525068033be
Commits[COMMIT BEGIN]commit e984e3170c4d44990f2f042a3ecd8525068033be Author: 0x4248 <[email protected]> Date: Mon Jan 12 23:58:43 2026 +0000 orion: Add logging functions Signed-off-by: 0x4248 <[email protected]> diff --git a/lab/orion/commands/system/open.py b/lab/orion/commands/system/open.py index 726db9d..e37a3d8 100644 --- a/lab/orion/commands/system/open.py +++ b/lab/orion/commands/system/open.py @@ -23,9 +23,27 @@ def open_page(request: Request, name: str = ""): return RedirectResponse(f"/command/{name}", status_code=303) +def goto(request: Request, name: str = ""): + return RedirectResponse(f"/{name}", status_code=303) + registry.register(Command( name="open", handler=open_page, summary="Open a UI page", mode="cli", )) + + +registry.register(Command( + name="goto", + handler=goto, + summary="Jumps to a url", + mode="cli", +)) + +registry.register(Command( + name="g", + handler=goto, + summary="Jumps to a url", + mode="cli", +)) diff --git a/lab/orion/core/console.py b/lab/orion/core/console.py new file mode 100644 index 0000000..8932e9d --- /dev/null +++ b/lab/orion/core/console.py @@ -0,0 +1,85 @@ +import datetime +from typing import Dict +import traceback + +from core.page import message + +global logger +global log_db + +import sys + +def _get_caller(): + f = sys._getframe(2) + module = f.f_globals.get("__name__", "<unknown>") + func = f.f_code.co_name + return f"{module}.{func}()" + + +class LogDatabase: + def __init__(self): + self.logs = {} + + def add_entry(self, level: str, caller: str, message: str) -> int: + log_id = len(self.logs) + 1 + timestamp = datetime.datetime.now().isoformat() + self.logs[log_id] = { + "id": log_id, + "timestamp": timestamp, + "level": level, + "caller": caller, + "message": message + } + return log_id + +class Logger: + def __init__(self, bark: bool = True, log_db_inp: LogDatabase | None = None): + self.bark = bark + self.log_db = log_db_inp + def log(self, caller: str = "Unknown", m: str | None = None, level: str = "INFO") -> int: + if self.log_db is None: + raise ValueError("No log database provided") + if m is None: + m = "No message provided" + if self.bark: + print(f"[{level}] {caller}: {m}") + log_id = log_db.add_entry(level, caller, m) + return log_id + + def debug(self, caller: str | None = None, m: str | None = None) -> int: + if caller is None: + caller = _get_caller() + return self.log(caller, m, "DEBUG") + + def info(self, caller: str | None = None, m: str | None = None) -> int: + if caller is None: + caller = _get_caller() + return self.log(caller, m, "INFO") + + def warning(self, caller: str | None = None, m: str | None = None) -> int: + if caller is None: + caller = _get_caller() + return self.log(caller, m, "WARNING") + + def error(self, caller: str | None = None, m: str | None = None) -> int: + if caller is None: + caller = _get_caller() + return self.log(caller, m, "ERROR") + + def critical(self, caller: str | None = None, m: str | None = None) -> int: + if caller is None: + caller = _get_caller() + return self.log(caller, m, "CRITICAL") + + def alarm(self, caller: str | None = None, m: str | None = None) -> int: + if caller is None: + caller = _get_caller() + return self.log(caller, m, "ALARM") + +# If already imported dont reinit +if 'logger' not in globals(): + log_db = LogDatabase() + logger = Logger(bark=True, log_db_inp=log_db) + logger.info(m="Logger initialized successfully") +else: + logger.info(m="Logger already initialized, skipping reinitialization") \ No newline at end of file diff --git a/lab/orion/core/layout.py b/lab/orion/core/layout.py index 083bb2b..29c3183 100644 --- a/lab/orion/core/layout.py +++ b/lab/orion/core/layout.py @@ -66,6 +66,47 @@ label { text-transform: uppercase; } + +.gray-span { + color: gray; + font-style: italic; +} + +.log-debug { + color: gray; +} + +.log-info { + color: #4da6ff; +} +.log-warning { + color: black; + background-color: yellow; +} +.log-error { + color: white; + background-color: red; +} + +.log-error-flash { + background-color: red; + color: white; + padding-top: 0.5em; + padding-bottom: 0.5em; + animation: flash-text 1s infinite; +} + +.flash { + animation: flash-text 1s infinite; +} + +@keyframes flash-text { + 0% { opacity: 1; } + 49% { opacity: 1; } + 50% { opacity: 0; } + 100% { opacity: 0; } +} + .error { background-color: red; color: white; @@ -74,6 +115,14 @@ label { animation: pulse_error 1s; } +.error-flash { + background-color: red; + color: white; + padding-top: 0.5em; + padding-bottom: 0.5em; + animation: flash-text 1s infinite; +} + @keyframes pulse_error { 0% { background-color: #ff8f8f; } 100% { background-color: red; } diff --git a/lab/orion/core/logbridge.py b/lab/orion/core/logbridge.py new file mode 100644 index 0000000..b005ac5 --- /dev/null +++ b/lab/orion/core/logbridge.py @@ -0,0 +1,17 @@ +import logging + +class logBridge(logging.Handler): + def __init__(self, orionLoggerBridge): + super().__init__() + self.orionLoggerBridge = orionLoggerBridge + + def emit(self, record: logging.LogRecord): + try: + msg = self.format(record) + self.orionLoggerBridge.log( + f"BRIDGE -> {record.name}.{record.funcName}()", + msg, + record.levelname, + ) + except Exception: + self.handleError(record) diff --git a/lab/orion/main.py b/lab/orion/main.py index 53d82db..f080ba8 100644 --- a/lab/orion/main.py +++ b/lab/orion/main.py @@ -1,19 +1,39 @@ from fastapi import FastAPI, Request -from fastapi.responses import FileResponse, RedirectResponse +from fastapi.responses import FileResponse -from pages import command,about -from core import auth +from core.logbridge import logBridge +from pages import command, about, console +from core import auth, console from core import page as p - import commands.system.open - import commands.system.manual as manual import commands.echo +import logging -app = FastAPI() +handler = logBridge(console.logger) +handler.setFormatter(logging.Formatter("%(message)s")) +root = logging.getLogger() +root.handlers.clear() +root.addHandler(handler) +root.setLevel(logging.DEBUG) +for name in ( + "uvicorn", + "uvicorn.error", + "uvicorn.access", + "fastapi", +): + log = logging.getLogger(name) + log.handlers.clear() + log.addHandler(handler) + log.propagate = False + + +app = FastAPI() + +console.logger.info(m="Starting Orion Web Application") app.middleware("http")(auth.auth_middleware) @@ -22,6 +42,8 @@ app.include_router(command.router) app.include_router(about.router) app.include_router(manual.router) +console.logger.info(m=app.router.routes) + @app.exception_handler(404) async def not_found(request: Request, exc): return p.static( @@ -37,4 +59,10 @@ async def favicon(): if __name__ == "__main__": import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8000) + uvicorn.run( + app, + host="0.0.0.0", + port=8000, + log_config=None, + access_log=True, + )[COMMIT END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.