From 964bcc0733bd4b595f96642e9d7fa1d3d2f65ec0 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Thu, 8 Dec 2022 19:15:00 -0700 Subject: [PATCH] Logs in UI (#4562) * Log all services to RAM * Gracefully handle shutdown * Add logs route * Remove tail * Return logs for services * Display log chooser with copy button * show logs for specific services * Clean up settings logs * Add copy functionality to logs * Add copy functionality to logs * Fix merge * Set archive count to 0 Co-authored-by: Felipe Santos --- Dockerfile | 4 ++-- frigate/http.py | 21 +++++++++++++++++ web/src/Sidebar.jsx | 1 + web/src/app.tsx | 1 + web/src/routes/Logs.jsx | 51 +++++++++++++++++++++++++++++++++++++++++ web/src/routes/index.js | 5 ++++ 6 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 web/src/routes/Logs.jsx diff --git a/Dockerfile b/Dockerfile index 9300d5d68..3999ff1f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -180,8 +180,8 @@ ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 # But this is not working currently because of: # https://github.com/just-containers/s6-overlay/issues/503 ENV S6_SERVICES_GRACETIME=30000 -# Configure logging to prepend timestamps, log to stdout, keep 1 archive and rotate on 10MB -ENV S6_LOGGING_SCRIPT="T 1 n1 s10000000 T" +# Configure logging to prepend timestamps, log to stdout, keep 0 archives and rotate on 10MB +ENV S6_LOGGING_SCRIPT="T 1 n0 s10000000 T" # TODO: remove after a new version of s6-overlay is released. See: # https://github.com/just-containers/s6-overlay/issues/460#issuecomment-1327127006 ENV S6_SERVICES_READYTIME=50 diff --git a/frigate/http.py b/frigate/http.py index 5a88385a1..43e03d0e6 100644 --- a/frigate/http.py +++ b/frigate/http.py @@ -1142,3 +1142,24 @@ def vainfo(): else "", } ) + + +@bp.route("/logs/", methods=["GET"]) +def logs(service: str): + log_locations = { + "frigate": "/dev/shm/logs/frigate/current", + "go2rtc": "/dev/shm/logs/go2rtc/current", + "nginx": "/dev/shm/logs/nginx/current", + } + service_location = log_locations.get(service) + + if not service: + return f"{service} is not a valid service", 404 + + try: + file = open(service_location, "r") + contents = file.read() + file.close() + return contents, 200 + except FileNotFoundError as e: + return f"Could not find log file: {e}", 500 diff --git a/web/src/Sidebar.jsx b/web/src/Sidebar.jsx index 6c4fd1d92..a7d7639e8 100644 --- a/web/src/Sidebar.jsx +++ b/web/src/Sidebar.jsx @@ -48,6 +48,7 @@ export default function Sidebar() { +
{ENV !== 'production' ? ( diff --git a/web/src/app.tsx b/web/src/app.tsx index bc7e1b562..124a0f3cb 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -38,6 +38,7 @@ export default function App() { + diff --git a/web/src/routes/Logs.jsx b/web/src/routes/Logs.jsx new file mode 100644 index 000000000..b48ae187d --- /dev/null +++ b/web/src/routes/Logs.jsx @@ -0,0 +1,51 @@ +import { h } from 'preact'; +import Heading from '../components/Heading'; +import { useCallback, useEffect, useState } from 'preact/hooks'; +import ButtonsTabbed from '../components/ButtonsTabbed'; +import useSWR from 'swr'; +import Button from '../components/Button'; + +export default function Logs() { + const [logService, setLogService] = useState('frigate'); + const [logs, setLogs] = useState('frigate'); + + const { data: frigateLogs } = useSWR('logs/frigate'); + const { data: go2rtcLogs } = useSWR('logs/go2rtc'); + const { data: nginxLogs } = useSWR('logs/nginx'); + + const handleCopyLogs = useCallback(() => { + async function copy() { + await window.navigator.clipboard.writeText(logs); + } + copy(); + }, [logs]); + + useEffect(() => { + switch (logService) { + case 'frigate': + setLogs(frigateLogs); + break; + case 'go2rtc': + setLogs(go2rtcLogs); + break; + case 'nginx': + setLogs(nginxLogs); + break; + } + }, [frigateLogs, go2rtcLogs, nginxLogs, logService, setLogs]); + + return ( +
+ Logs + + + +
+ {logs} +
+ +
+ ); +} diff --git a/web/src/routes/index.js b/web/src/routes/index.js index 1bf04f714..eeadbbb4f 100644 --- a/web/src/routes/index.js +++ b/web/src/routes/index.js @@ -43,6 +43,11 @@ export async function getConfig(_url, _cb, _props) { return module.default; } +export async function getLogs(_url, _cb, _props) { + const module = await import('./Logs.jsx'); + return module.default; +} + export async function getStyleGuide(_url, _cb, _props) { const module = await import('./StyleGuide.jsx'); return module.default;