From a77436eec3f33ffa671983333573db2a25d8c560 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Mon, 19 Aug 2024 08:53:33 -0600 Subject: [PATCH] Add button for downloading full set of logs (#13188) --- frigate/api/app.py | 16 +++++++ web/src/pages/Logs.tsx | 103 ++++++++++++++++++++++++++++++----------- 2 files changed, 93 insertions(+), 26 deletions(-) diff --git a/frigate/api/app.py b/frigate/api/app.py index 732cdcf76..46a2b9c13 100644 --- a/frigate/api/app.py +++ b/frigate/api/app.py @@ -456,6 +456,19 @@ def vainfo(): @bp.route("/logs/", methods=["GET"]) def logs(service: str): + def download_logs(service_location: str): + try: + file = open(service_location, "r") + contents = file.read() + file.close() + return jsonify(contents) + except FileNotFoundError as e: + logger.error(e) + return make_response( + jsonify({"success": False, "message": "Could not find log file"}), + 500, + ) + log_locations = { "frigate": "/dev/shm/logs/frigate/current", "go2rtc": "/dev/shm/logs/go2rtc/current", @@ -470,6 +483,9 @@ def logs(service: str): 404, ) + if request.args.get("download", type=bool, default=False): + return download_logs(service_location) + start = request.args.get("start", type=int, default=0) end = request.args.get("end", type=int) diff --git a/web/src/pages/Logs.tsx b/web/src/pages/Logs.tsx index 582190098..f03c67116 100644 --- a/web/src/pages/Logs.tsx +++ b/web/src/pages/Logs.tsx @@ -21,16 +21,34 @@ import { cn } from "@/lib/utils"; import { MdVerticalAlignBottom } from "react-icons/md"; import { parseLogLines } from "@/utils/logUtil"; import useKeyboardListener from "@/hooks/use-keyboard-listener"; +import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; +import scrollIntoView from "scroll-into-view-if-needed"; +import { FaDownload } from "react-icons/fa"; type LogRange = { start: number; end: number }; function Logs() { const [logService, setLogService] = useState("frigate"); + const tabsRef = useRef(null); useEffect(() => { document.title = `${logService[0].toUpperCase()}${logService.substring(1)} Logs - Frigate`; }, [logService]); + useEffect(() => { + if (tabsRef.current) { + const element = tabsRef.current.querySelector( + `[data-nav-item="${logService}"]`, + ); + if (element instanceof HTMLElement) { + scrollIntoView(element, { + behavior: "smooth", + inline: "start", + }); + } + } + }, [tabsRef, logService]); + // log data handling const logPageSize = useMemo(() => { @@ -118,6 +136,27 @@ function Logs() { } }, [logs, logRange]); + const handleDownloadLogs = useCallback(() => { + axios + .get(`logs/${logService}?download=true`) + .then((resp) => { + const element = document.createElement("a"); + element.setAttribute( + "href", + "data:text/plain;charset=utf-8," + encodeURIComponent(resp.data), + ); + element.setAttribute("download", `${logService}-logs.txt`); + + element.style.display = "none"; + document.body.appendChild(element); + + element.click(); + + document.body.removeChild(element); + }) + .catch(() => {}); + }, [logService]); + // scroll to bottom const [initialScroll, setInitialScroll] = useState(false); @@ -266,33 +305,37 @@ function Logs() { -
- { - if (value) { - setLogs([]); - setLogLines([]); - setFilterSeverity(undefined); - setLogService(value); - } - }} // don't allow the severity to be unselected - > - {Object.values(logTypes).map((item) => ( - + +
+ { + if (value) { + setLogs([]); + setLogLines([]); + setFilterSeverity(undefined); + setLogService(value); + } + }} // don't allow the severity to be unselected > -
{item}
- - ))} -
+ {Object.values(logTypes).map((item) => ( + +
{item}
+
+ ))} + + +
+
+