From fb0bf7d33f0e988b318e87832befc6d7805e452f Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 08:54:24 -0600 Subject: [PATCH 01/26] update logging in electron main to prevent redundant dates+times of logs --- electron/ui/public/main.js | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/electron/ui/public/main.js b/electron/ui/public/main.js index 6aebc7dc..a6e34c69 100644 --- a/electron/ui/public/main.js +++ b/electron/ui/public/main.js @@ -17,8 +17,16 @@ let uiReady = false const serverURL = `http://localhost:${PY_PORT}` const uiURL = `http://localhost:${UI_PORT}` -log.transports.file.resolvePath = () => path.join(__dirname, '/logsmain.log'); +if(isDev) { + log.transports.file.resolvePath = () => path.join(__dirname, '/logsdev.log'); +} else { + log.transports.file.resolvePath = () => path.join(__dirname, '/logsmain.log'); +} + log.transports.file.level = "info"; +// log.transports.console.format = '{h}:{i}:{s} {text}' +log.transports.console.format = '{text}' +log.transports.file.format = '{text}' exports.log = (entry) => log.info(entry) @@ -62,6 +70,7 @@ function createWindow() { } console.log("storing user preferences in: ",app.getPath('userData')); + log.info("storing user preferences in: ",app.getPath('userData')) // save size of window when resized win.on("resized", () => saveBounds(win.getSize())); @@ -85,22 +94,20 @@ const installExtensions = () => { ] ); - log.info("installation started"); - console.log("installation started"); + log.info("installing idaes extensions"); + console.log("installing idaes extensions"); var scriptOutput = ""; installationProcess.stdout.setEncoding('utf8'); installationProcess.stdout.on('data', function(data) { - // console.log('stdout: ' + data); - log.info('stdout: ' + data); + log.info('backend: ' + data); data=data.toString(); scriptOutput+=data; }); installationProcess.stderr.setEncoding('utf8'); installationProcess.stderr.on('data', function(data) { - // console.log('stderr: ' + data); - log.info('stderr: ' + data); + log.info('backend: ' + data); data=data.toString(); scriptOutput+=data; }); @@ -124,7 +131,7 @@ const startServer = () => { { cwd: '../backend/app' } - ); + ); // log.info("Python process started in dev mode"); // console.log("Python process started in dev mode"); } else { @@ -139,7 +146,7 @@ const startServer = () => { backendProcess.stdout.setEncoding('utf8'); backendProcess.stdout.on('data', function(data) { console.log('stdout: ' + data); - log.info('stdout: ' + data); + log.info('backend: ' + data); data=data.toString(); scriptOutput+=data; }); @@ -147,7 +154,7 @@ const startServer = () => { backendProcess.stderr.setEncoding('utf8'); backendProcess.stderr.on('data', function(data) { console.log('stderr: ' + data); - log.info('stderr: ' + data); + log.info('backend: ' + data); data=data.toString(); scriptOutput+=data; }); @@ -176,8 +183,8 @@ app.whenReady().then(() => { let serverProcess let installationProcess = installExtensions() installationProcess.on('exit', code => { - log.info('installation exit code is', code) - console.log('installation exit code is', code) + // log.info('installation exit code is', code) + // console.log('installation exit code is', code) log.info('starting server') console.log('starting server') serverProcess = startServer() From f22b319cfa850b2ad5e03a9aef9e23c12ed5700e Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 08:55:13 -0600 Subject: [PATCH 02/26] put backend in parentheses --- electron/ui/public/main.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/electron/ui/public/main.js b/electron/ui/public/main.js index a6e34c69..3584a25f 100644 --- a/electron/ui/public/main.js +++ b/electron/ui/public/main.js @@ -100,14 +100,14 @@ const installExtensions = () => { var scriptOutput = ""; installationProcess.stdout.setEncoding('utf8'); installationProcess.stdout.on('data', function(data) { - log.info('backend: ' + data); + log.info('(backend): ' + data); data=data.toString(); scriptOutput+=data; }); installationProcess.stderr.setEncoding('utf8'); installationProcess.stderr.on('data', function(data) { - log.info('backend: ' + data); + log.info('(backend): ' + data); data=data.toString(); scriptOutput+=data; }); @@ -146,7 +146,7 @@ const startServer = () => { backendProcess.stdout.setEncoding('utf8'); backendProcess.stdout.on('data', function(data) { console.log('stdout: ' + data); - log.info('backend: ' + data); + log.info('(backend): ' + data); data=data.toString(); scriptOutput+=data; }); @@ -154,7 +154,7 @@ const startServer = () => { backendProcess.stderr.setEncoding('utf8'); backendProcess.stderr.on('data', function(data) { console.log('stderr: ' + data); - log.info('backend: ' + data); + log.info('(backend): ' + data); data=data.toString(); scriptOutput+=data; }); From 2c911714633d9925d85ef29e9f66993a75cf2254 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 09:29:26 -0600 Subject: [PATCH 03/26] remove (backend) from electron log --- electron/ui/public/main.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/electron/ui/public/main.js b/electron/ui/public/main.js index 3584a25f..16815d0a 100644 --- a/electron/ui/public/main.js +++ b/electron/ui/public/main.js @@ -100,14 +100,14 @@ const installExtensions = () => { var scriptOutput = ""; installationProcess.stdout.setEncoding('utf8'); installationProcess.stdout.on('data', function(data) { - log.info('(backend): ' + data); + log.info(data); data=data.toString(); scriptOutput+=data; }); installationProcess.stderr.setEncoding('utf8'); installationProcess.stderr.on('data', function(data) { - log.info('(backend): ' + data); + log.info(data); data=data.toString(); scriptOutput+=data; }); @@ -146,7 +146,7 @@ const startServer = () => { backendProcess.stdout.setEncoding('utf8'); backendProcess.stdout.on('data', function(data) { console.log('stdout: ' + data); - log.info('(backend): ' + data); + log.info(data); data=data.toString(); scriptOutput+=data; }); @@ -154,7 +154,7 @@ const startServer = () => { backendProcess.stderr.setEncoding('utf8'); backendProcess.stderr.on('data', function(data) { console.log('stderr: ' + data); - log.info('(backend): ' + data); + log.info(data); data=data.toString(); scriptOutput+=data; }); From 88622fd82cacde42d67a0101d4d66361587a7080 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 09:59:28 -0600 Subject: [PATCH 04/26] add logging panel component with hardcoded sample data --- .../components/LoggingPanel/LoggingPanel.js | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 electron/ui/src/components/LoggingPanel/LoggingPanel.js diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js new file mode 100644 index 00000000..61740b97 --- /dev/null +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -0,0 +1,125 @@ +import {useEffect, useState} from 'react'; +import { Grid, Box, Modal, TextField, IconButton, Typography, Button } from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; + +const sampleData = [ + "[2024-01-08 08:30:53.961] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.feed.properties: Initialization Complete.\n", + "\n", + "[2024-01-08 08:30:53.983] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.feed: Initialization complete: optimal - Optimal Solution Found.\n", + "\n", + "[2024-01-08 08:30:53.984] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_in: Initialization Complete.\n", + "\n", + "[2024-01-08 08:30:53.984] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_treated: Initialization Complete.\n", + "2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_byproduct: Initialization Complete.\n", + "\n", + "[2024-01-08 08:30:54.007] [info] stdout: 2024-01-08 08:30:54 [ERROR] idaes.init.fs.magprex.properties_in: State Released.\n", + "\n", + "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.magprex: Initialization Complete: optimal - Optimal Solution Found\n", + "\n", + "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_in: Initialization Complete.\n", + "\n", + "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_treated: Initialization Complete.\n", + "2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_byproduct: Initialization Complete.\n", + "[2024-01-08 08:30:53.961] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.feed.properties: Initialization Complete.\n", + "\n", + "[2024-01-08 08:30:53.983] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.feed: Initialization complete: optimal - Optimal Solution Found.\n", + "\n", + "[2024-01-08 08:30:53.984] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_in: Initialization Complete.\n", + "\n", + "[2024-01-08 08:30:53.984] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_treated: Initialization Complete.\n", + "2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_byproduct: Initialization Complete.\n", + "\n", + "[2024-01-08 08:30:54.007] [info] stdout: 2024-01-08 08:30:54 [ERROR] idaes.init.fs.magprex.properties_in: State Released.\n", + "\n", + "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.magprex: Initialization Complete: optimal - Optimal Solution Found\n", + "\n", + "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_in: Initialization Complete.\n", + "\n", + "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_treated: Initialization Complete.\n", + "2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_byproduct: Initialization Complete.\n", + ] + +export default function LoggingPanel(props) { + const { open, onClose } = props; + const [ logData, setLogData ] = useState(sampleData) + // const [ open, setOpen ] = useState(true) + const styles = { + modalStyle: { + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: "80vw", + height: "60vh", + bgcolor: 'black', + border: '1px solid #AEAEAE', + borderRadius:2, + boxShadow: 24, + p: 2, + overflowY: "scroll", + overflowX: "scroll", + color: "white" + }, + header:{ + marginTop:5 + }, + button: { + borderRadius: '8px', + width: 200, + }, + console: { + overflowX: "scroll" + }, + consoleText: { + // display: "flex", + // overflowX: "scroll", + }, + + } + + const handleClose = () => { + onClose() + }; + + + return ( + + + + +

Backend Logs

+
+ + + + + + + + + + {logData.map((line, idx) => { + if (line.includes('ERROR')) { + return ( +

{line}

+ ) + } else { + return ( +

{line}

+ ) + } + })} +
+ +
+
+
+
+ ); +} + From 407d19c7fdf37d6dfd51f483efbda10a23d61099 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 10:00:06 -0600 Subject: [PATCH 05/26] add actions to header: view logs, return to list page --- .../components/Boilerplate/Header/Header.js | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/electron/ui/src/components/Boilerplate/Header/Header.js b/electron/ui/src/components/Boilerplate/Header/Header.js index 17a34898..49b38634 100644 --- a/electron/ui/src/components/Boilerplate/Header/Header.js +++ b/electron/ui/src/components/Boilerplate/Header/Header.js @@ -1,14 +1,31 @@ import './Header.css'; import React from 'react'; import logo from "../../../assets/nawi-logo-color.png"; +import LoggingPanel from '../../LoggingPanel/LoggingPanel'; import { useNavigate } from "react-router-dom"; -import Button from '@mui/material/Button'; - +import { Button, Menu, MenuItem, IconButton } from '@mui/material'; +import ListIcon from '@mui/icons-material/List'; + export default function Header(props) { let navigate = useNavigate(); + const [ showLogs, setShowLogs ] = React.useState(false) + const [ actionsList, setActionsList ] = React.useState(false) + const [ anchorEl, setAnchorEl ] = React.useState(null); + const handleNavigateHome = () => { + setActionsList(!actionsList) navigate("/flowsheets", {replace: true}) } + + const handleShowLogs = () => { + setShowLogs(!showLogs) + setActionsList(false) + } + + const handleShowActions = (event) => { + setActionsList(!actionsList) + setAnchorEl(event.currentTarget); + } return ( props.show && ); } From c55f94ccb66277bc54579473e52ee4a6862d93cd Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 13:04:19 -0600 Subject: [PATCH 06/26] added api endpoint for fetching logs; added functionality to only return log entries that occurred after last time app was started; updated color scheme for displaying logs --- backend/app/internal/flowsheet_manager.py | 5 ++++ backend/app/routers/flowsheets.py | 27 ++++++++++++++++- .../components/Boilerplate/Header/Header.js | 3 +- .../components/LoggingPanel/LoggingPanel.js | 29 ++++++++++++++++++- electron/ui/src/services/flowsheet.service.js | 9 +++++- 5 files changed, 68 insertions(+), 5 deletions(-) diff --git a/backend/app/internal/flowsheet_manager.py b/backend/app/internal/flowsheet_manager.py index 8b0e6f8a..25190fcb 100644 --- a/backend/app/internal/flowsheet_manager.py +++ b/backend/app/internal/flowsheet_manager.py @@ -76,6 +76,7 @@ def __init__(self, **kwargs): """ self.app_settings = AppSettings(**kwargs) self._objs, self._flowsheets = {}, {} + self.startup_time = time.time() # Add custom flowsheets path to the system path self.custom_flowsheets_path = Path.home() / ".watertap" / "custom_flowsheets" @@ -539,6 +540,10 @@ def add_custom_flowsheets(self): except Exception as e: _log.error(f"unable to add flowsheet module: {e}") + def get_logs_path(self): + """Return logs path.""" + return self.app_settings.log_dir + @staticmethod def _get_flowsheet_interface(module: ModuleType) -> Optional[FlowsheetInterface]: """Get a a flowsheet interface for module. diff --git a/backend/app/routers/flowsheets.py b/backend/app/routers/flowsheets.py index 19ae71bb..531bbf0f 100644 --- a/backend/app/routers/flowsheets.py +++ b/backend/app/routers/flowsheets.py @@ -2,7 +2,7 @@ Handle flowsheet-related API requests from web client. """ # stdlib -import csv +import time import io import aiofiles from pathlib import Path @@ -130,6 +130,7 @@ async def solve(flowsheet_id: str, request: Request): # set last run in tiny db flowsheet_manager.set_last_run(info.id_) except Exception as err: + _log.error(f"Solve failed: {err}") raise HTTPException(500, detail=f"Solve failed: {err}") return flowsheet.fs_exp @@ -472,3 +473,27 @@ async def download_sweep(flowsheet_id: str) -> Path: df.to_csv(path, index=False) # # User can now download the contents of that file return path + +@router.get("/get_logs") +async def get_logs() -> List[str]: + """Get backend logs. + + Returns: + Logs formatted as a list + """ + result = [] + logs_path = flowsheet_manager.get_logs_path() / "ui_backend_logs.log" + log_file = open(logs_path, 'r') + all_logs = log_file.read() + logs = all_logs.split('\n[') + for line in logs: + log_time = line.split(' ')[1:3] + log_time_string = f'{log_time[0]} {log_time[1]}'.split(',')[0] + stripped_time = time.strptime(log_time_string, "%Y-%m-%d %H:%M:%S") + asctime = time.mktime(stripped_time) + if asctime > flowsheet_manager.startup_time: + result.append(line) + # print(f'asctime: {asctime}') + # break + # print(f'app startup time was : {flowsheet_manager.startup_time}') + return result \ No newline at end of file diff --git a/electron/ui/src/components/Boilerplate/Header/Header.js b/electron/ui/src/components/Boilerplate/Header/Header.js index 49b38634..838bfce7 100644 --- a/electron/ui/src/components/Boilerplate/Header/Header.js +++ b/electron/ui/src/components/Boilerplate/Header/Header.js @@ -13,7 +13,7 @@ export default function Header(props) { const [ anchorEl, setAnchorEl ] = React.useState(null); const handleNavigateHome = () => { - setActionsList(!actionsList) + // setActionsList(!actionsList) navigate("/flowsheets", {replace: true}) } @@ -38,7 +38,6 @@ export default function Header(props) { WaterTAP
- {/* */} { + getLogs() + .then(response => response.json()) + .then((data) => { + console.log('got logs: ') + setLogData(data) + // console.log(data) + }) + },[props]) + // const [ open, setOpen ] = useState(true) const styles = { modalStyle: { @@ -108,11 +120,26 @@ export default function LoggingPanel(props) { return (

{line}

) - } else { + } else if (line.includes('INFO')) { return (

{line}

) } + else if (line.includes('DEBUG')) { + return ( +

{line}

+ ) + } + else if (line.includes('WARNING')) { + return ( +

{line}

+ ) + } + else { + return ( +

{line}

+ ) + } })} diff --git a/electron/ui/src/services/flowsheet.service.js b/electron/ui/src/services/flowsheet.service.js index 15d0d695..99bb990f 100644 --- a/electron/ui/src/services/flowsheet.service.js +++ b/electron/ui/src/services/flowsheet.service.js @@ -36,4 +36,11 @@ export const selectOption = (id, data) => { mode: 'cors', body: JSON.stringify(data) }); -}; \ No newline at end of file +}; + +export const getLogs = () => { + return fetch('http://localhost:8001/flowsheets/get_logs', { + method: 'GET', + mode: 'cors' + }); +} \ No newline at end of file From a316c0ff7ad6192f46709484f3d46af07f184def Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 13:32:09 -0600 Subject: [PATCH 07/26] switch from mui modal to mui dialog --- .../components/LoggingPanel/LoggingPanel.js | 162 +++++++++++------- 1 file changed, 96 insertions(+), 66 deletions(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 5ea4ba4c..b9857c30 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -1,5 +1,6 @@ -import {useEffect, useState} from 'react'; +import {useEffect, useState, useRef} from 'react'; import { Grid, Box, Modal, TextField, IconButton, Typography, Button } from '@mui/material'; +import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import { getLogs } from '../../services/flowsheet.service'; @@ -45,16 +46,18 @@ export default function LoggingPanel(props) { const [ logData, setLogData ] = useState(sampleData) useEffect(() => { - getLogs() - .then(response => response.json()) - .then((data) => { - console.log('got logs: ') - setLogData(data) - // console.log(data) - }) + if (open)( + getLogs() + .then(response => response.json()) + .then((data) => { + console.log('got logs: ') + setLogData(data) + // console.log(data) + }) + ) + },[props]) - // const [ open, setOpen ] = useState(true) const styles = { modalStyle: { position: 'absolute', @@ -68,8 +71,9 @@ export default function LoggingPanel(props) { borderRadius:2, boxShadow: 24, p: 2, - overflowY: "scroll", - overflowX: "scroll", + // overflowY: "scroll", + // overflowX: "scroll", + overflow: "hidden", color: "white" }, header:{ @@ -80,12 +84,33 @@ export default function LoggingPanel(props) { width: 200, }, console: { - overflowX: "scroll" + overflow: "scroll", }, consoleText: { // display: "flex", // overflowX: "scroll", }, + dialogTitle: { + backgroundColor: "black", + color: "white", + }, + dialogContent: { + backgroundColor: "black", + color: "white", + }, + dialogContentText: { + backgroundColor: "black", + color: "white", + }, + dialog: { + // maxWidth: "80vw", + }, + dialogPaper: { + minHeight: '60vh', + maxHeight: '60vh', + minWidth: '60vw', + maxWidth: '60vw', + }, } @@ -93,60 +118,65 @@ export default function LoggingPanel(props) { onClose() }; + const descriptionElementRef = useRef(null); + useEffect(() => { + if (open) { + const { current: descriptionElement } = descriptionElementRef; + if (descriptionElement !== null) { + descriptionElement.focus(); + } + } + }, [open]); - return ( - - - - -

Backend Logs

-
- - - - - - - - - - {logData.map((line, idx) => { - if (line.includes('ERROR')) { - return ( -

{line}

- ) - } else if (line.includes('INFO')) { - return ( -

{line}

- ) - } - else if (line.includes('DEBUG')) { - return ( -

{line}

- ) - } - else if (line.includes('WARNING')) { - return ( -

{line}

- ) - } - else { - return ( -

{line}

- ) - } - })} -
- -
-
-
-
- ); + return ( + + Backend Logs + + + {logData.map((line, idx) => { + if (line.includes('ERROR')) { + return ( +

{line}

+ ) + } else if (line.includes('INFO')) { + return ( +

{line}

+ ) + } + else if (line.includes('DEBUG')) { + return ( +

{line}

+ ) + } + else if (line.includes('WARNING')) { + return ( +

{line}

+ ) + } + else { + return ( +

{line}

+ ) + } + })} +
+
+
+ ) } From 3c40f2709944123569f3ddbd4d57637b5d2db641 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 13:50:33 -0600 Subject: [PATCH 08/26] auto scroll to bottom of log panel --- .../components/LoggingPanel/LoggingPanel.js | 141 ++++++------------ 1 file changed, 45 insertions(+), 96 deletions(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index b9857c30..077a4869 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -1,49 +1,14 @@ -import {useEffect, useState, useRef} from 'react'; +import {useEffect, useState, useRef } from 'react'; import { Grid, Box, Modal, TextField, IconButton, Typography, Button } from '@mui/material'; import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import { getLogs } from '../../services/flowsheet.service'; -const sampleData = [ - "[2024-01-08 08:30:53.961] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.feed.properties: Initialization Complete.\n", - "\n", - "[2024-01-08 08:30:53.983] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.feed: Initialization complete: optimal - Optimal Solution Found.\n", - "\n", - "[2024-01-08 08:30:53.984] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_in: Initialization Complete.\n", - "\n", - "[2024-01-08 08:30:53.984] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_treated: Initialization Complete.\n", - "2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_byproduct: Initialization Complete.\n", - "\n", - "[2024-01-08 08:30:54.007] [info] stdout: 2024-01-08 08:30:54 [ERROR] idaes.init.fs.magprex.properties_in: State Released.\n", - "\n", - "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.magprex: Initialization Complete: optimal - Optimal Solution Found\n", - "\n", - "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_in: Initialization Complete.\n", - "\n", - "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_treated: Initialization Complete.\n", - "2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_byproduct: Initialization Complete.\n", - "[2024-01-08 08:30:53.961] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.feed.properties: Initialization Complete.\n", - "\n", - "[2024-01-08 08:30:53.983] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.feed: Initialization complete: optimal - Optimal Solution Found.\n", - "\n", - "[2024-01-08 08:30:53.984] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_in: Initialization Complete.\n", - "\n", - "[2024-01-08 08:30:53.984] [info] stdout: 2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_treated: Initialization Complete.\n", - "2024-01-08 08:30:53 [INFO] idaes.init.fs.magprex.properties_byproduct: Initialization Complete.\n", - "\n", - "[2024-01-08 08:30:54.007] [info] stdout: 2024-01-08 08:30:54 [ERROR] idaes.init.fs.magprex.properties_in: State Released.\n", - "\n", - "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.magprex: Initialization Complete: optimal - Optimal Solution Found\n", - "\n", - "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_in: Initialization Complete.\n", - "\n", - "[2024-01-08 08:30:54.008] [info] stdout: 2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_treated: Initialization Complete.\n", - "2024-01-08 08:30:54 [INFO] idaes.init.fs.centrifuge.properties_byproduct: Initialization Complete.\n", - ] export default function LoggingPanel(props) { const { open, onClose } = props; - const [ logData, setLogData ] = useState(sampleData) + const [ logData, setLogData ] = useState([]) + const divRef = useRef(null); useEffect(() => { if (open)( @@ -53,43 +18,24 @@ export default function LoggingPanel(props) { console.log('got logs: ') setLogData(data) // console.log(data) + // window.scrollTo(0, document.body.scrollHeight); }) ) },[props]) + useEffect(() => { + if (open) { + console.log('log data was updated') + // scrollToBottom("test-div") + divRef.current.scrollIntoView({ behavior: 'smooth' }); + } + + },[logData]) + + + const styles = { - modalStyle: { - position: 'absolute', - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - width: "80vw", - height: "60vh", - bgcolor: 'black', - border: '1px solid #AEAEAE', - borderRadius:2, - boxShadow: 24, - p: 2, - // overflowY: "scroll", - // overflowX: "scroll", - overflow: "hidden", - color: "white" - }, - header:{ - marginTop:5 - }, - button: { - borderRadius: '8px', - width: 200, - }, - console: { - overflow: "scroll", - }, - consoleText: { - // display: "flex", - // overflowX: "scroll", - }, dialogTitle: { backgroundColor: "black", color: "white", @@ -117,6 +63,7 @@ export default function LoggingPanel(props) { const handleClose = () => { onClose() }; + const descriptionElementRef = useRef(null); useEffect(() => { @@ -147,33 +94,35 @@ export default function LoggingPanel(props) { ref={descriptionElementRef} tabIndex={-1} style={styles.dialogContentText} - > - {logData.map((line, idx) => { - if (line.includes('ERROR')) { - return ( -

{line}

- ) - } else if (line.includes('INFO')) { - return ( -

{line}

- ) - } - else if (line.includes('DEBUG')) { - return ( -

{line}

- ) - } - else if (line.includes('WARNING')) { - return ( -

{line}

- ) - } - else { - return ( -

{line}

- ) - } - })} + aria-labelledby="console-dialog-content-text" + > + {logData.map((line, idx) => { + if (line.includes('ERROR')) { + return ( +

{line}

+ ) + } else if (line.includes('INFO')) { + return ( +

{line}

+ ) + } + else if (line.includes('DEBUG')) { + return ( +

{line}

+ ) + } + else if (line.includes('WARNING')) { + return ( +

{line}

+ ) + } + else { + return ( +

{line}

+ ) + } + })} +
From 691c8ee2ca21a713c0394b12701089df5212e309 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 13:58:03 -0600 Subject: [PATCH 09/26] make text wrap in log panel --- .../components/LoggingPanel/LoggingPanel.js | 33 +++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 077a4869..d515d050 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -47,6 +47,7 @@ export default function LoggingPanel(props) { dialogContentText: { backgroundColor: "black", color: "white", + // overflowX: "auto" }, dialog: { // maxWidth: "80vw", @@ -64,6 +65,13 @@ export default function LoggingPanel(props) { onClose() }; + const getTextColor = (line) => { + if (line.includes('ERROR')) return "#FF042E" + else if (line.includes('INFO')) return "#28FF24" + else if (line.includes('DEBUG')) return "#3B90FF" + else if (line.includes('WARNING')) return "#FFF42C" + else return "white" + } const descriptionElementRef = useRef(null); useEffect(() => { @@ -97,30 +105,7 @@ export default function LoggingPanel(props) { aria-labelledby="console-dialog-content-text" > {logData.map((line, idx) => { - if (line.includes('ERROR')) { - return ( -

{line}

- ) - } else if (line.includes('INFO')) { - return ( -

{line}

- ) - } - else if (line.includes('DEBUG')) { - return ( -

{line}

- ) - } - else if (line.includes('WARNING')) { - return ( -

{line}

- ) - } - else { - return ( -

{line}

- ) - } + return {line} })}
From 2537548a6db3278b25728eb87d168b5719ab07f1 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 13:58:22 -0600 Subject: [PATCH 10/26] remove logging inside get diagram --- backend/app/internal/flowsheet_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/internal/flowsheet_manager.py b/backend/app/internal/flowsheet_manager.py index 25190fcb..9a8ea091 100644 --- a/backend/app/internal/flowsheet_manager.py +++ b/backend/app/internal/flowsheet_manager.py @@ -203,7 +203,7 @@ def get_diagram(self, id_: str) -> bytes: data = b"" info = self.get_info(id_) - _log.info(f"inide get diagram:: info is - {info}") + # _log.info(f"inside get diagram:: info is - {info}") if info.custom: # do this data_path = ( From 1d55efb88fb40ac9b0e3c4a1deb96c2cbb7829c6 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 14:24:40 -0600 Subject: [PATCH 11/26] reword log --- backend/app/internal/flowsheet_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/internal/flowsheet_manager.py b/backend/app/internal/flowsheet_manager.py index 9a8ea091..7819a72d 100644 --- a/backend/app/internal/flowsheet_manager.py +++ b/backend/app/internal/flowsheet_manager.py @@ -532,7 +532,7 @@ def add_custom_flowsheets(self): for f in files: if "_ui.py" in f: try: - _log.info(f"attempting to add custom flowsheet module: {f}") + _log.info(f"adding imported flowsheet module: {f}") module_name = f.replace(".py", "") custom_module = importlib.import_module(module_name) fsi = self._get_flowsheet_interface(custom_module) From a9316cf4d0c3d5c38d364f43ed52e5bb080f9d20 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 8 Jan 2024 14:24:55 -0600 Subject: [PATCH 12/26] add x button on log panel --- .../components/LoggingPanel/LoggingPanel.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index d515d050..74e47e3e 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -1,6 +1,6 @@ import {useEffect, useState, useRef } from 'react'; -import { Grid, Box, Modal, TextField, IconButton, Typography, Button } from '@mui/material'; -import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } from '@mui/material'; +import { Grid, Box, Modal, TextField, IconButton, Button } from '@mui/material'; +import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Typography } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import { getLogs } from '../../services/flowsheet.service'; @@ -26,8 +26,6 @@ export default function LoggingPanel(props) { useEffect(() => { if (open) { - console.log('log data was updated') - // scrollToBottom("test-div") divRef.current.scrollIntoView({ behavior: 'smooth' }); } @@ -96,6 +94,18 @@ export default function LoggingPanel(props) { > Backend Logs + + + Date: Thu, 18 Jan 2024 14:52:43 -0600 Subject: [PATCH 13/26] add solver_log wrapper around solve (should do this for build and sweep too?) --- backend/app/routers/flowsheets.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/app/routers/flowsheets.py b/backend/app/routers/flowsheets.py index 531bbf0f..a487dd6f 100644 --- a/backend/app/routers/flowsheets.py +++ b/backend/app/routers/flowsheets.py @@ -25,6 +25,7 @@ CURRENT = "current" _log = idaeslog.getLogger(__name__) +_solver_log = idaeslog.getLogger(__name__+'.solver') router = APIRouter( prefix="/flowsheets", @@ -126,7 +127,8 @@ async def solve(flowsheet_id: str, request: Request): # run solve try: - flowsheet.solve() + with idaeslog.solver_log(_log, level=idaeslog.INFO) as slc: + flowsheet.solve() # set last run in tiny db flowsheet_manager.set_last_run(info.id_) except Exception as err: From 7c6010552fe04ca1bb68b686bba5c95d22c53878 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Fri, 19 Jan 2024 13:44:32 -0600 Subject: [PATCH 14/26] rework logging api to send dictionaries for each log entry, then format those on frontend --- backend/app/routers/flowsheets.py | 46 +++++++++++++++++-- .../components/LoggingPanel/LoggingPanel.js | 2 +- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/backend/app/routers/flowsheets.py b/backend/app/routers/flowsheets.py index a487dd6f..b3a3a8f3 100644 --- a/backend/app/routers/flowsheets.py +++ b/backend/app/routers/flowsheets.py @@ -15,6 +15,7 @@ import pandas as pd from pydantic import BaseModel from pydantic.error_wrappers import ValidationError +import re # package-local from app.internal.flowsheet_manager import FlowsheetManager, FlowsheetInfo @@ -484,18 +485,57 @@ async def get_logs() -> List[str]: Logs formatted as a list """ result = [] + log_entries = [] logs_path = flowsheet_manager.get_logs_path() / "ui_backend_logs.log" log_file = open(logs_path, 'r') all_logs = log_file.read() logs = all_logs.split('\n[') for line in logs: - log_time = line.split(' ')[1:3] + log_split = line.split(' ') + log_time = log_split[1:3] log_time_string = f'{log_time[0]} {log_time[1]}'.split(',')[0] stripped_time = time.strptime(log_time_string, "%Y-%m-%d %H:%M:%S") asctime = time.mktime(stripped_time) if asctime > flowsheet_manager.startup_time: result.append(line) + + + log_level = line.split(']')[0] + log_name = log_split[3] + log_file_lineno = log_split[4] + log_file = log_file_lineno.split(":")[0] + log_lineno = log_file_lineno.split(":")[1] + log_message = line.split(log_file_lineno)[1] + if len(log_file) > 0: + log_file = log_file[1:] + if len(log_lineno) > 0: + log_lineno = log_lineno[:-1] + if len(log_message) > 0: + log_message = log_message[1:] + log_entry = { + "log_time": asctime, + "log_level": log_level, + "log_name": log_name, + "log_file": log_file, + "log_lineno": log_lineno, + "log_message": log_message, + } + log_entries.append(log_entry) # print(f'asctime: {asctime}') # break - # print(f'app startup time was : {flowsheet_manager.startup_time}') - return result \ No newline at end of file + # print(f'log_entries: {log_entries}') + # logLevelRegex = "(\[^DEBUG$|^INFO$|^WARNING$|^ERROR$\])" + # logLevelRegex = "(?:\[(DEBUG)|(INFO)|(WARNING)|(ERROR)\])" + # logLevelRegex = r"(\[(?:DEBUG|INFO|WARNING|ERROR)\])" + # split_logs = re.split(logLevelRegex, all_logs) + # logLevelRegex = r"^\[(?:DEBUG|INFO|WARNING|ERROR)].*" + # split_logs = re.findall(logLevelRegex, all_logs, re.M) + # for line in split_logs: + # log_time = line.split(' ')[1:3] + # log_time_string = f'{log_time[0]} {log_time[1]}'.split(',')[0] + # stripped_time = time.strptime(log_time_string, "%Y-%m-%d %H:%M:%S") + # asctime = time.mktime(stripped_time) + # if asctime > flowsheet_manager.startup_time: + # result.append(line) + + return log_entries \ No newline at end of file diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 74e47e3e..8179d207 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -115,7 +115,7 @@ export default function LoggingPanel(props) { aria-labelledby="console-dialog-content-text" > {logData.map((line, idx) => { - return {line} + return [{line.log_level}] {line.log_name}: {line.log_message} })}
From ba7dfcfc741ff29159373a83b171b811b6853201 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Fri, 19 Jan 2024 13:50:41 -0600 Subject: [PATCH 15/26] make logging panel draggable --- electron/ui/package-lock.json | 23 +++++++++++++++++++ electron/ui/package.json | 1 + .../components/LoggingPanel/LoggingPanel.js | 8 +++++++ 3 files changed, 32 insertions(+) diff --git a/electron/ui/package-lock.json b/electron/ui/package-lock.json index dc602938..73121632 100644 --- a/electron/ui/package-lock.json +++ b/electron/ui/package-lock.json @@ -26,6 +26,7 @@ "react": "^18.1.0", "react-dom": "^18.1.0", "react-drag-drop-files": "^2.3.10", + "react-draggable": "^4.4.6", "react-plotly.js": "^2.6.0", "react-plotlyjs": "^0.4.4", "react-router-dom": "^6.3.0", @@ -19274,6 +19275,19 @@ "react-dom": "^18.0.0" } }, + "node_modules/react-draggable": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", + "integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==", + "dependencies": { + "clsx": "^1.1.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, "node_modules/react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", @@ -36993,6 +37007,15 @@ "styled-components": "^5.3.0" } }, + "react-draggable": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", + "integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==", + "requires": { + "clsx": "^1.1.1", + "prop-types": "^15.8.1" + } + }, "react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", diff --git a/electron/ui/package.json b/electron/ui/package.json index 123f099f..a80d3e92 100644 --- a/electron/ui/package.json +++ b/electron/ui/package.json @@ -23,6 +23,7 @@ "react": "^18.1.0", "react-dom": "^18.1.0", "react-drag-drop-files": "^2.3.10", + "react-draggable": "^4.4.6", "react-plotly.js": "^2.6.0", "react-plotlyjs": "^0.4.4", "react-router-dom": "^6.3.0", diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 8179d207..8221294f 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -3,6 +3,7 @@ import { Grid, Box, Modal, TextField, IconButton, Button } from '@mui/material'; import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Typography } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import { getLogs } from '../../services/flowsheet.service'; +import Draggable from 'react-draggable'; export default function LoggingPanel(props) { @@ -55,6 +56,8 @@ export default function LoggingPanel(props) { maxHeight: '60vh', minWidth: '60vw', maxWidth: '60vw', + // backgroundColor: "transparent", + // boxShadow: 'none', }, } @@ -82,6 +85,7 @@ export default function LoggingPanel(props) { }, [open]); return ( + Backend Logs @@ -121,6 +128,7 @@ export default function LoggingPanel(props) {
+ ) } From a21ea17cdbc268d135f35531a5831de1402b6a7c Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Fri, 19 Jan 2024 14:09:05 -0600 Subject: [PATCH 16/26] make logging panel draggable; add fullscreen button; add download logs button - still needs to be hooked up to api --- .../components/LoggingPanel/LoggingPanel.js | 58 ++++++++++++++++--- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 8221294f..b6864987 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -4,11 +4,17 @@ import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, T import CloseIcon from '@mui/icons-material/Close'; import { getLogs } from '../../services/flowsheet.service'; import Draggable from 'react-draggable'; +import FullscreenIcon from '@mui/icons-material/Fullscreen'; +import FullscreenExitIcon from '@mui/icons-material/FullscreenExit'; +import DownloadIcon from '@mui/icons-material/Download'; export default function LoggingPanel(props) { const { open, onClose } = props; const [ logData, setLogData ] = useState([]) + const [ dialogHeight, setDialogHeight ] = useState('60vh') + const [ dialogWidth, setDialogWidth ] = useState('60vw') + const [ fullscreen, setFullscreen] = useState(false) const divRef = useRef(null); useEffect(() => { @@ -52,12 +58,10 @@ export default function LoggingPanel(props) { // maxWidth: "80vw", }, dialogPaper: { - minHeight: '60vh', - maxHeight: '60vh', - minWidth: '60vw', - maxWidth: '60vw', - // backgroundColor: "transparent", - // boxShadow: 'none', + minHeight: dialogHeight, + maxHeight: dialogHeight, + minWidth: dialogWidth, + maxWidth: dialogWidth, }, } @@ -65,6 +69,21 @@ export default function LoggingPanel(props) { const handleClose = () => { onClose() }; + + const handleFullscreen = () => { + if (fullscreen) { + setDialogHeight('60vh') + setDialogWidth('60vw') + } else { + setDialogHeight('100vh') + setDialogWidth('100vw') + } + setFullscreen(!fullscreen) + } + + const handleDownloadLogs = () => { + console.log('call api to download logs') + }; const getTextColor = (line) => { if (line.includes('ERROR')) return "#FF042E" @@ -98,15 +117,38 @@ export default function LoggingPanel(props) { BackdropProps={{ sx: {backgroundColor: "transparent"} }} - > Backend Logs + + + + + {fullscreen ? : } + Date: Mon, 22 Jan 2024 07:19:48 -0600 Subject: [PATCH 17/26] add download logs api and connect it to logging panel --- backend/app/routers/flowsheets.py | 13 ++++++++++++- .../ui/src/components/LoggingPanel/LoggingPanel.js | 12 ++++++++++-- electron/ui/src/services/flowsheet.service.js | 7 +++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/backend/app/routers/flowsheets.py b/backend/app/routers/flowsheets.py index b3a3a8f3..e66b3673 100644 --- a/backend/app/routers/flowsheets.py +++ b/backend/app/routers/flowsheets.py @@ -538,4 +538,15 @@ async def get_logs() -> List[str]: # if asctime > flowsheet_manager.startup_time: # result.append(line) - return log_entries \ No newline at end of file + return log_entries + +@router.post("/download_logs", response_class=FileResponse) +async def download_logs() -> Path: + """Download full backend logs. + + Returns: + Log file + """ + _log.info('DOWNLOADING LOGS') + path = Path.home() / ".watertap" / "logs" / "ui_backend_logs.log" + return path \ No newline at end of file diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index b6864987..5d827e0b 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -2,7 +2,7 @@ import {useEffect, useState, useRef } from 'react'; import { Grid, Box, Modal, TextField, IconButton, Button } from '@mui/material'; import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Typography } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; -import { getLogs } from '../../services/flowsheet.service'; +import { getLogs, downloadLogs } from '../../services/flowsheet.service'; import Draggable from 'react-draggable'; import FullscreenIcon from '@mui/icons-material/Fullscreen'; import FullscreenExitIcon from '@mui/icons-material/FullscreenExit'; @@ -82,7 +82,15 @@ export default function LoggingPanel(props) { } const handleDownloadLogs = () => { - console.log('call api to download logs') + downloadLogs().then(response => response.blob()) + .then((data) => { + console.log(data) + let logsUrl = window.URL.createObjectURL(data); + let tempLink = document.createElement('a'); + tempLink.href = logsUrl; + tempLink.setAttribute('download', 'watertap-ui-logs.log'); + tempLink.click(); + }) }; const getTextColor = (line) => { diff --git a/electron/ui/src/services/flowsheet.service.js b/electron/ui/src/services/flowsheet.service.js index 99bb990f..50538176 100644 --- a/electron/ui/src/services/flowsheet.service.js +++ b/electron/ui/src/services/flowsheet.service.js @@ -43,4 +43,11 @@ export const getLogs = () => { method: 'GET', mode: 'cors' }); +} + +export const downloadLogs = () => { + return fetch('http://localhost:8001/flowsheets/download_logs', { + method: 'POST', + mode: 'cors' + }); } \ No newline at end of file From b47a5e65fcdb3d2331a389bd9121001ef5e698b6 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 22 Jan 2024 07:21:51 -0600 Subject: [PATCH 18/26] add tooltip around download logs button: Download full logs --- .../components/LoggingPanel/LoggingPanel.js | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 5d827e0b..08ac8ea4 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -1,5 +1,5 @@ import {useEffect, useState, useRef } from 'react'; -import { Grid, Box, Modal, TextField, IconButton, Button } from '@mui/material'; +import { Grid, Box, Modal, TextField, IconButton, Button, Tooltip } from '@mui/material'; import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Typography } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import { getLogs, downloadLogs } from '../../services/flowsheet.service'; @@ -127,18 +127,20 @@ export default function LoggingPanel(props) { }} > Backend Logs - - - + + + + + Date: Mon, 22 Jan 2024 07:27:45 -0600 Subject: [PATCH 19/26] add solver_log wrapper around parameter sweep call; add try/catch around parsing of each line from log file --- backend/app/routers/flowsheets.py | 93 +++++++++++++------------------ 1 file changed, 40 insertions(+), 53 deletions(-) diff --git a/backend/app/routers/flowsheets.py b/backend/app/routers/flowsheets.py index e66b3673..ff62890a 100644 --- a/backend/app/routers/flowsheets.py +++ b/backend/app/routers/flowsheets.py @@ -167,10 +167,11 @@ async def sweep(flowsheet_id: str, request: Request): info.updated(built=True) _log.info("trying to sweep") - results_table = run_parameter_sweep( - flowsheet=flowsheet, - info=info, - ) + with idaeslog.solver_log(_log, level=idaeslog.INFO) as slc: + results_table = run_parameter_sweep( + flowsheet=flowsheet, + info=info, + ) flowsheet.fs_exp.sweep_results = results_table # set last run in tiny db flowsheet_manager.set_last_run(info.id_) @@ -268,11 +269,9 @@ async def upload_flowsheet(files: List[UploadFile]) -> str: try: # get file contents new_files = [] - - print("trying to read files with aiofiles") for file in files: # for file in files: - print(file.filename) + _log.info(f'reading {file.filename}') new_files.append(file.filename) if "_ui.py" in file.filename: new_id = file.filename.replace(".py", "") @@ -489,54 +488,42 @@ async def get_logs() -> List[str]: logs_path = flowsheet_manager.get_logs_path() / "ui_backend_logs.log" log_file = open(logs_path, 'r') all_logs = log_file.read() + log_file.close() logs = all_logs.split('\n[') for line in logs: - log_split = line.split(' ') - log_time = log_split[1:3] - log_time_string = f'{log_time[0]} {log_time[1]}'.split(',')[0] - stripped_time = time.strptime(log_time_string, "%Y-%m-%d %H:%M:%S") - asctime = time.mktime(stripped_time) - if asctime > flowsheet_manager.startup_time: - result.append(line) - - - log_level = line.split(']')[0] - log_name = log_split[3] - log_file_lineno = log_split[4] - log_file = log_file_lineno.split(":")[0] - log_lineno = log_file_lineno.split(":")[1] - log_message = line.split(log_file_lineno)[1] - if len(log_file) > 0: - log_file = log_file[1:] - if len(log_lineno) > 0: - log_lineno = log_lineno[:-1] - if len(log_message) > 0: - log_message = log_message[1:] - log_entry = { - "log_time": asctime, - "log_level": log_level, - "log_name": log_name, - "log_file": log_file, - "log_lineno": log_lineno, - "log_message": log_message, - } - log_entries.append(log_entry) - # print(f'asctime: {asctime}') - # break - # print(f'log_entries: {log_entries}') - # logLevelRegex = "(\[^DEBUG$|^INFO$|^WARNING$|^ERROR$\])" - # logLevelRegex = "(?:\[(DEBUG)|(INFO)|(WARNING)|(ERROR)\])" - # logLevelRegex = r"(\[(?:DEBUG|INFO|WARNING|ERROR)\])" - # split_logs = re.split(logLevelRegex, all_logs) - # logLevelRegex = r"^\[(?:DEBUG|INFO|WARNING|ERROR)].*" - # split_logs = re.findall(logLevelRegex, all_logs, re.M) - # for line in split_logs: - # log_time = line.split(' ')[1:3] - # log_time_string = f'{log_time[0]} {log_time[1]}'.split(',')[0] - # stripped_time = time.strptime(log_time_string, "%Y-%m-%d %H:%M:%S") - # asctime = time.mktime(stripped_time) - # if asctime > flowsheet_manager.startup_time: - # result.append(line) + try: + log_split = line.split(' ') + log_time = log_split[1:3] + log_time_string = f'{log_time[0]} {log_time[1]}'.split(',')[0] + stripped_time = time.strptime(log_time_string, "%Y-%m-%d %H:%M:%S") + asctime = time.mktime(stripped_time) + if asctime > flowsheet_manager.startup_time: + result.append(line) + + + log_level = line.split(']')[0] + log_name = log_split[3] + log_file_lineno = log_split[4] + log_file = log_file_lineno.split(":")[0] + log_lineno = log_file_lineno.split(":")[1] + log_message = line.split(log_file_lineno)[1] + if len(log_file) > 0: + log_file = log_file[1:] + if len(log_lineno) > 0: + log_lineno = log_lineno[:-1] + if len(log_message) > 0: + log_message = log_message[1:] + log_entry = { + "log_time": asctime, + "log_level": log_level, + "log_name": log_name, + "log_file": log_file, + "log_lineno": log_lineno, + "log_message": log_message, + } + log_entries.append(log_entry) + except Exception as e: + _log.error(f'unable to parse log line: {e}') return log_entries From 448bec1a067963450d7f7c2b6d8f513a4ea947a8 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 22 Jan 2024 07:42:56 -0600 Subject: [PATCH 20/26] add search bar to log panel --- .../components/LoggingPanel/LoggingPanel.js | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 08ac8ea4..627b4bef 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -1,5 +1,5 @@ import {useEffect, useState, useRef } from 'react'; -import { Grid, Box, Modal, TextField, IconButton, Button, Tooltip } from '@mui/material'; +import { Grid, Box, InputAdornment, TextField, IconButton, Button, Tooltip } from '@mui/material'; import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Typography } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import { getLogs, downloadLogs } from '../../services/flowsheet.service'; @@ -7,6 +7,7 @@ import Draggable from 'react-draggable'; import FullscreenIcon from '@mui/icons-material/Fullscreen'; import FullscreenExitIcon from '@mui/icons-material/FullscreenExit'; import DownloadIcon from '@mui/icons-material/Download'; +import SearchIcon from '@mui/icons-material/Search'; export default function LoggingPanel(props) { @@ -15,6 +16,7 @@ export default function LoggingPanel(props) { const [ dialogHeight, setDialogHeight ] = useState('60vh') const [ dialogWidth, setDialogWidth ] = useState('60vw') const [ fullscreen, setFullscreen] = useState(false) + const [ searchTerm, setSearchTerm ] = useState("") const divRef = useRef(null); useEffect(() => { @@ -67,6 +69,7 @@ export default function LoggingPanel(props) { } const handleClose = () => { + setSearchTerm("") onClose() }; @@ -127,6 +130,31 @@ export default function LoggingPanel(props) { }} > Backend Logs + setSearchTerm(event.target.value)} + sx={{ + position: 'absolute', + left: 160, + top: 12, + color: "white", + backgroundColor: "#292f30", + borderRadius: 10, + input: { color: 'white' }, + }} + InputProps={{ + startAdornment: ( + + + + ), + }} + // fullWidth + // disabled={disabled} + /> {logData.map((line, idx) => { - return [{line.log_level}] {line.log_name}: {line.log_message} + if (line.log_message.toLowerCase().includes(searchTerm.toLowerCase())) { + return [{line.log_level}] {line.log_name}: {line.log_message} + } + })}
From e02e713e6a2da771dc796eb0ab298876f24d8ffe Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 22 Jan 2024 07:51:26 -0600 Subject: [PATCH 21/26] change draggable aspect of logging panel to only work from header part - this allows for highlighting of text inside the console --- electron/ui/src/components/LoggingPanel/LoggingPanel.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 627b4bef..2942a643 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -70,6 +70,7 @@ export default function LoggingPanel(props) { const handleClose = () => { setSearchTerm("") + if(fullscreen) handleFullscreen() onClose() }; @@ -115,7 +116,7 @@ export default function LoggingPanel(props) { }, [open]); return ( - + Backend Logs + Date: Mon, 22 Jan 2024 09:07:37 -0600 Subject: [PATCH 22/26] add filter options for log level --- .../components/LoggingPanel/LoggingPanel.js | 66 +++++++++++++++++-- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 2942a643..2f911e68 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -1,5 +1,5 @@ import {useEffect, useState, useRef } from 'react'; -import { Grid, Box, InputAdornment, TextField, IconButton, Button, Tooltip } from '@mui/material'; +import { InputAdornment, TextField, IconButton, Tooltip, MenuItem, Checkbox, ListItemText, Menu } from '@mui/material'; import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Typography } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import { getLogs, downloadLogs } from '../../services/flowsheet.service'; @@ -8,6 +8,7 @@ import FullscreenIcon from '@mui/icons-material/Fullscreen'; import FullscreenExitIcon from '@mui/icons-material/FullscreenExit'; import DownloadIcon from '@mui/icons-material/Download'; import SearchIcon from '@mui/icons-material/Search'; +import FilterListIcon from '@mui/icons-material/FilterList'; export default function LoggingPanel(props) { @@ -17,6 +18,9 @@ export default function LoggingPanel(props) { const [ dialogWidth, setDialogWidth ] = useState('60vw') const [ fullscreen, setFullscreen] = useState(false) const [ searchTerm, setSearchTerm ] = useState("") + const [ filters, setFilters ] = useState(["DEBUG", "INFO", "WARNING", "ERROR"]) + const [ showFilters, setShowFilters ] = useState(false) + const [ anchorEl, setAnchorEl ] = useState(null); const divRef = useRef(null); useEffect(() => { @@ -70,6 +74,8 @@ export default function LoggingPanel(props) { const handleClose = () => { setSearchTerm("") + setShowFilters(false) + setFilters(["DEBUG", "INFO", "WARNING", "ERROR"]) if(fullscreen) handleFullscreen() onClose() }; @@ -96,6 +102,22 @@ export default function LoggingPanel(props) { tempLink.click(); }) }; + + const handleShowLogFilters = (event) => { + setShowFilters(!showFilters) + setAnchorEl(event.currentTarget); + } + + const handleFilter = (level) => { + let tempFilters = [...filters] + const index = tempFilters.indexOf(level); + if (index > -1) { + tempFilters.splice(index, 1); + } else { + tempFilters.push(level) + } + setFilters(tempFilters) + } const getTextColor = (line) => { if (line.includes('ERROR')) return "#FF042E" @@ -140,7 +162,7 @@ export default function LoggingPanel(props) { onChange={(event) => setSearchTerm(event.target.value)} sx={{ position: 'absolute', - left: 160, + right: 160, top: 12, color: "white", backgroundColor: "#292f30", @@ -154,9 +176,43 @@ export default function LoggingPanel(props) { ), }} - // fullWidth - // disabled={disabled} /> + + + + setShowFilters(false)} + > + handleFilter("DEBUG")}> + + + + handleFilter("INFO")}> + + + + handleFilter("WARNING")}> + + + + handleFilter("ERROR")}> + + + + + {logData.map((line, idx) => { - if (line.log_message.toLowerCase().includes(searchTerm.toLowerCase())) { + if (line.log_message.toLowerCase().includes(searchTerm.toLowerCase()) && filters.includes(line.log_level)) { return [{line.log_level}] {line.log_name}: {line.log_message} } From 9db1c9a64ec8901f5722815154aeea6434a806f9 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 22 Jan 2024 09:14:17 -0600 Subject: [PATCH 23/26] move parse_log functionality to separate python file --- backend/app/internal/log_parser.py | 46 +++++++++++++++++++++++++++ backend/app/routers/flowsheets.py | 50 +++--------------------------- 2 files changed, 50 insertions(+), 46 deletions(-) create mode 100644 backend/app/internal/log_parser.py diff --git a/backend/app/internal/log_parser.py b/backend/app/internal/log_parser.py new file mode 100644 index 00000000..bf9db8b0 --- /dev/null +++ b/backend/app/internal/log_parser.py @@ -0,0 +1,46 @@ +import time + +def parse_logs(logs_path, time_since): + """ + Assume a log format of: + "[%(levelname)s] %(asctime)s %(name)s (%(filename)s:%(lineno)s): %(message)s" + """ + result = [] + log_entries = [] + log_file = open(logs_path, 'r') + all_logs = log_file.read() + log_file.close() + logs = all_logs.split('\n[') + for line in logs: + try: + log_split = line.split(' ') + log_time = log_split[1:3] + log_time_string = f'{log_time[0]} {log_time[1]}'.split(',')[0] + stripped_time = time.strptime(log_time_string, "%Y-%m-%d %H:%M:%S") + asctime = time.mktime(stripped_time) + if asctime > time_since: + result.append(line) + log_level = line.split(']')[0] + log_name = log_split[3] + log_file_lineno = log_split[4] + log_file = log_file_lineno.split(":")[0] + log_lineno = log_file_lineno.split(":")[1] + log_message = line.split(log_file_lineno)[1] + if len(log_file) > 0: + log_file = log_file[1:] + if len(log_lineno) > 0: + log_lineno = log_lineno[:-1] + if len(log_message) > 0: + log_message = log_message[1:] + log_entry = { + "log_time": asctime, + "log_level": log_level, + "log_name": log_name, + "log_file": log_file, + "log_lineno": log_lineno, + "log_message": log_message, + } + log_entries.append(log_entry) + except Exception as e: + print(f'unable to parse log line: {e}') + return log_entries \ No newline at end of file diff --git a/backend/app/routers/flowsheets.py b/backend/app/routers/flowsheets.py index ff62890a..981732f8 100644 --- a/backend/app/routers/flowsheets.py +++ b/backend/app/routers/flowsheets.py @@ -2,7 +2,6 @@ Handle flowsheet-related API requests from web client. """ # stdlib -import time import io import aiofiles from pathlib import Path @@ -20,6 +19,7 @@ # package-local from app.internal.flowsheet_manager import FlowsheetManager, FlowsheetInfo from app.internal.parameter_sweep import run_parameter_sweep +from app.internal.log_parser import parse_logs from watertap.ui.fsapi import FlowsheetInterface, FlowsheetExport import idaes.logger as idaeslog @@ -483,49 +483,8 @@ async def get_logs() -> List[str]: Returns: Logs formatted as a list """ - result = [] - log_entries = [] logs_path = flowsheet_manager.get_logs_path() / "ui_backend_logs.log" - log_file = open(logs_path, 'r') - all_logs = log_file.read() - log_file.close() - logs = all_logs.split('\n[') - for line in logs: - try: - log_split = line.split(' ') - log_time = log_split[1:3] - log_time_string = f'{log_time[0]} {log_time[1]}'.split(',')[0] - stripped_time = time.strptime(log_time_string, "%Y-%m-%d %H:%M:%S") - asctime = time.mktime(stripped_time) - if asctime > flowsheet_manager.startup_time: - result.append(line) - - - log_level = line.split(']')[0] - log_name = log_split[3] - log_file_lineno = log_split[4] - log_file = log_file_lineno.split(":")[0] - log_lineno = log_file_lineno.split(":")[1] - log_message = line.split(log_file_lineno)[1] - if len(log_file) > 0: - log_file = log_file[1:] - if len(log_lineno) > 0: - log_lineno = log_lineno[:-1] - if len(log_message) > 0: - log_message = log_message[1:] - log_entry = { - "log_time": asctime, - "log_level": log_level, - "log_name": log_name, - "log_file": log_file, - "log_lineno": log_lineno, - "log_message": log_message, - } - log_entries.append(log_entry) - except Exception as e: - _log.error(f'unable to parse log line: {e}') - - return log_entries + return parse_logs(logs_path, flowsheet_manager.startup_time) @router.post("/download_logs", response_class=FileResponse) async def download_logs() -> Path: @@ -534,6 +493,5 @@ async def download_logs() -> Path: Returns: Log file """ - _log.info('DOWNLOADING LOGS') - path = Path.home() / ".watertap" / "logs" / "ui_backend_logs.log" - return path \ No newline at end of file + logs_path = flowsheet_manager.get_logs_path() / "ui_backend_logs.log" + return logs_path \ No newline at end of file From a6eb4bed7591d78c1986f2b42142267d914053d1 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Mon, 22 Jan 2024 09:41:45 -0600 Subject: [PATCH 24/26] color code log level filters --- .../components/LoggingPanel/LoggingPanel.js | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 2f911e68..86cf8e84 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -69,7 +69,18 @@ export default function LoggingPanel(props) { minWidth: dialogWidth, maxWidth: dialogWidth, }, - + DEBUG: { + color: "#3B90FF", + }, + INFO: { + color: "#28FF24", + }, + WARNING: { + color: "#FFF42C", + }, + ERROR: { + color: "#FF042E", + } } const handleClose = () => { @@ -120,10 +131,10 @@ export default function LoggingPanel(props) { } const getTextColor = (line) => { - if (line.includes('ERROR')) return "#FF042E" - else if (line.includes('INFO')) return "#28FF24" - else if (line.includes('DEBUG')) return "#3B90FF" - else if (line.includes('WARNING')) return "#FFF42C" + if (line.includes('ERROR')) return styles.ERROR.color + else if (line.includes('INFO')) return styles.INFO.color + else if (line.includes('DEBUG')) return styles.DEBUG.color + else if (line.includes('WARNING')) return styles.WARNING.color else return "white" } @@ -194,23 +205,26 @@ export default function LoggingPanel(props) { anchorEl={anchorEl} open={showFilters} onClose={() => setShowFilters(false)} + sx={{ + "& .MuiPaper-root": { + backgroundColor: "#292f30" + } + }} > - handleFilter("DEBUG")}> - - - - handleFilter("INFO")}> - - - - handleFilter("WARNING")}> - - - - handleFilter("ERROR")}> - - - + {["DEBUG", "INFO", "WARNING", "ERROR"].map((loglevel, idx) => ( + handleFilter(loglevel)} sx={{color: "white"}}> + + + + ))}
From 097c767c9238b00830826e6fa060f5918dd5f4f7 Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Wed, 24 Jan 2024 13:38:31 -0600 Subject: [PATCH 25/26] handle a couple frontend warnings --- electron/ui/src/components/LoggingPanel/LoggingPanel.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/electron/ui/src/components/LoggingPanel/LoggingPanel.js b/electron/ui/src/components/LoggingPanel/LoggingPanel.js index 86cf8e84..59d187b6 100644 --- a/electron/ui/src/components/LoggingPanel/LoggingPanel.js +++ b/electron/ui/src/components/LoggingPanel/LoggingPanel.js @@ -212,7 +212,7 @@ export default function LoggingPanel(props) { }} > {["DEBUG", "INFO", "WARNING", "ERROR"].map((loglevel, idx) => ( - handleFilter(loglevel)} sx={{color: "white"}}> + handleFilter(loglevel)} sx={{color: "white"}}> {logData.map((line, idx) => { if (line.log_message.toLowerCase().includes(searchTerm.toLowerCase()) && filters.includes(line.log_level)) { From 03a5ffed299e3f858ada5ab9179e2799ed50febb Mon Sep 17 00:00:00 2001 From: MichaelPesce Date: Wed, 24 Jan 2024 13:44:33 -0600 Subject: [PATCH 26/26] update name of logs file --- backend/app/internal/settings.py | 2 +- backend/app/routers/flowsheets.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/app/internal/settings.py b/backend/app/internal/settings.py index 2ebfeb9f..fcbefba4 100644 --- a/backend/app/internal/settings.py +++ b/backend/app/internal/settings.py @@ -31,7 +31,7 @@ def validate_log_dir(cls, v): v.mkdir(parents=True, exist_ok=True) loggingFormat = "[%(levelname)s] %(asctime)s %(name)s (%(filename)s:%(lineno)s): %(message)s" - loggingFileHandler = logging.handlers.RotatingFileHandler(v / "ui_backend_logs.log", backupCount=2, maxBytes=5000000) + loggingFileHandler = logging.handlers.RotatingFileHandler(v / "watertap-ui_backend_logs.log", backupCount=2, maxBytes=5000000) logging.basicConfig(level=logging.INFO, format=loggingFormat, handlers=[loggingFileHandler]) return v diff --git a/backend/app/routers/flowsheets.py b/backend/app/routers/flowsheets.py index 981732f8..3f29eb5b 100644 --- a/backend/app/routers/flowsheets.py +++ b/backend/app/routers/flowsheets.py @@ -483,7 +483,7 @@ async def get_logs() -> List[str]: Returns: Logs formatted as a list """ - logs_path = flowsheet_manager.get_logs_path() / "ui_backend_logs.log" + logs_path = flowsheet_manager.get_logs_path() / "watertap-ui_backend_logs.log" return parse_logs(logs_path, flowsheet_manager.startup_time) @router.post("/download_logs", response_class=FileResponse) @@ -493,5 +493,5 @@ async def download_logs() -> Path: Returns: Log file """ - logs_path = flowsheet_manager.get_logs_path() / "ui_backend_logs.log" + logs_path = flowsheet_manager.get_logs_path() / "watertap-ui_backend_logs.log" return logs_path \ No newline at end of file