more logs
This commit is contained in:
parent
f61801e855
commit
2715c56b4f
2 changed files with 105 additions and 0 deletions
|
|
@ -1,4 +1,46 @@
|
||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from "react-dom/client";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
|
||||||
|
const backendBase =
|
||||||
|
(import.meta.env.VITE_BACKEND_URL as string | undefined) ?? "http://localhost:8000";
|
||||||
|
|
||||||
|
const sendFrontLog = (message: string, level: "info" | "warn" | "error" = "info") => {
|
||||||
|
fetch(`${backendBase}/logs`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ message, level, source: "frontend" }),
|
||||||
|
}).catch(() => {});
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("error", (event) => {
|
||||||
|
const err = event.error instanceof Error ? event.error : null;
|
||||||
|
const details = err?.stack || err?.message || String(event.message || "unknown error");
|
||||||
|
sendFrontLog(`window.error: ${details}`, "error");
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("unhandledrejection", (event) => {
|
||||||
|
const reason = event.reason instanceof Error ? event.reason.stack || event.reason.message : String(event.reason);
|
||||||
|
sendFrontLog(`unhandledrejection: ${reason}`, "error");
|
||||||
|
});
|
||||||
|
|
||||||
|
const _consoleError = console.error.bind(console);
|
||||||
|
console.error = (...args: unknown[]) => {
|
||||||
|
try {
|
||||||
|
sendFrontLog(`console.error: ${args.map(String).join(" ")}`, "error");
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
_consoleError(...args);
|
||||||
|
};
|
||||||
|
|
||||||
|
const _consoleWarn = console.warn.bind(console);
|
||||||
|
console.warn = (...args: unknown[]) => {
|
||||||
|
try {
|
||||||
|
sendFrontLog(`console.warn: ${args.map(String).join(" ")}`, "warn");
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
_consoleWarn(...args);
|
||||||
|
};
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(<App />);
|
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(<App />);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
@ -12,19 +14,80 @@ def _env(name: str, default: str) -> str:
|
||||||
return v if v is not None and v != "" else default
|
return v if v is not None and v != "" else default
|
||||||
|
|
||||||
|
|
||||||
|
class _TeeStream:
|
||||||
|
def __init__(self, primary, secondary):
|
||||||
|
self._primary = primary
|
||||||
|
self._secondary = secondary
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
try:
|
||||||
|
self._primary.write(data)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
self._secondary.write(data)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return len(data)
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
try:
|
||||||
|
self._primary.flush()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
self._secondary.flush()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def isatty(self):
|
||||||
|
try:
|
||||||
|
return self._primary.isatty()
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_uvicorn_logs_to_file(log_path: Path) -> None:
|
||||||
|
import logging
|
||||||
|
|
||||||
|
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
file_handler = logging.FileHandler(log_path, encoding="utf-8")
|
||||||
|
file_handler.setLevel(logging.INFO)
|
||||||
|
file_handler.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(name)s: %(message)s"))
|
||||||
|
|
||||||
|
for name in ("uvicorn", "uvicorn.error", "uvicorn.access"):
|
||||||
|
logger = logging.getLogger(name)
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
if not any(
|
||||||
|
isinstance(h, logging.FileHandler) and getattr(h, "baseFilename", None) == str(log_path)
|
||||||
|
for h in logger.handlers
|
||||||
|
):
|
||||||
|
logger.addHandler(file_handler)
|
||||||
|
logger.propagate = True
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Optional[list[str]] = None) -> int:
|
def main(argv: Optional[list[str]] = None) -> int:
|
||||||
parser = argparse.ArgumentParser(prog="gnss", description="GNSS Backend (FastAPI)")
|
parser = argparse.ArgumentParser(prog="gnss", description="GNSS Backend (FastAPI)")
|
||||||
parser.add_argument("--host", default=_env("GNSS_HOST", "0.0.0.0"))
|
parser.add_argument("--host", default=_env("GNSS_HOST", "0.0.0.0"))
|
||||||
parser.add_argument("--port", type=int, default=int(_env("GNSS_PORT", "8000")))
|
parser.add_argument("--port", type=int, default=int(_env("GNSS_PORT", "8000")))
|
||||||
parser.add_argument("--log-level", default=_env("GNSS_LOG_LEVEL", "info"))
|
parser.add_argument("--log-level", default=_env("GNSS_LOG_LEVEL", "info"))
|
||||||
|
parser.add_argument("--log-file", default=_env("GNSS_BACKEND_LOG_FILE", "logs/backend.log"))
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
|
log_path = Path(args.log_file).expanduser()
|
||||||
|
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
backend_log_file = log_path.open("a", encoding="utf-8", buffering=1)
|
||||||
|
sys.stdout = _TeeStream(sys.stdout, backend_log_file) # type: ignore[assignment]
|
||||||
|
sys.stderr = _TeeStream(sys.stderr, backend_log_file) # type: ignore[assignment]
|
||||||
|
_ensure_uvicorn_logs_to_file(log_path)
|
||||||
|
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
app,
|
app,
|
||||||
host=args.host,
|
host=args.host,
|
||||||
port=args.port,
|
port=args.port,
|
||||||
log_level=args.log_level,
|
log_level=args.log_level,
|
||||||
access_log=True,
|
access_log=True,
|
||||||
|
log_config=None,
|
||||||
workers=1,
|
workers=1,
|
||||||
)
|
)
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue