mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	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 <felipecassiors@gmail.com>
This commit is contained in:
		
							parent
							
								
									4f79ca1bf0
								
							
						
					
					
						commit
						964bcc0733
					
				| @ -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 | ||||
|  | ||||
| @ -1142,3 +1142,24 @@ def vainfo(): | ||||
|             else "", | ||||
|         } | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| @bp.route("/logs/<service>", 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 | ||||
|  | ||||
| @ -48,6 +48,7 @@ export default function Sidebar() { | ||||
|       <Destination href="/storage" text="Storage" /> | ||||
|       <Destination href="/system" text="System" /> | ||||
|       <Destination href="/config" text="Config" /> | ||||
|       <Destination href="/logs" text="Logs" /> | ||||
|       <Separator /> | ||||
|       <div className="flex flex-grow" /> | ||||
|       {ENV !== 'production' ? ( | ||||
|  | ||||
| @ -38,6 +38,7 @@ export default function App() { | ||||
|                   <AsyncRoute path="/storage" getComponent={Routes.getStorage} /> | ||||
|                   <AsyncRoute path="/system" getComponent={Routes.getSystem} /> | ||||
|                   <AsyncRoute path="/config" getComponent={Routes.getConfig} /> | ||||
|                   <AsyncRoute path="/logs" getComponent={Routes.getLogs} /> | ||||
|                   <AsyncRoute path="/styleguide" getComponent={Routes.getStyleGuide} /> | ||||
|                   <Cameras default path="/" /> | ||||
|                 </Router> | ||||
|  | ||||
							
								
								
									
										51
									
								
								web/src/routes/Logs.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								web/src/routes/Logs.jsx
									
									
									
									
									
										Normal file
									
								
							| @ -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 ( | ||||
|     <div className="space-y-4 p-2 px-4"> | ||||
|       <Heading>Logs</Heading> | ||||
| 
 | ||||
|       <ButtonsTabbed viewModes={['frigate', 'go2rtc', 'nginx']} setViewMode={setLogService} /> | ||||
| 
 | ||||
|       <div className='overflow-auto font-mono text-sm text-gray-900 dark:text-gray-100 rounded bg-gray-100 dark:bg-gray-800 p-2 whitespace-pre-wrap'> | ||||
|         {logs} | ||||
|       </div> | ||||
|       <Button className="" onClick={handleCopyLogs}> | ||||
|         Copy to Clipboard | ||||
|       </Button> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| @ -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; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user