diff --git a/pkg/core/bootutils/log.py b/pkg/core/bootutils/log.py index dea961b5..ce53efd5 100644 --- a/pkg/core/bootutils/log.py +++ b/pkg/core/bootutils/log.py @@ -36,8 +36,8 @@ async def init_logging(extra_handlers: list[logging.Handler] = None) -> logging. qcg_logger.setLevel(level) color_formatter = colorlog.ColoredFormatter( - fmt="%(log_color)s[%(asctime)s.%(msecs)03d] %(pathname)s (%(lineno)d) - [%(levelname)s] :\n %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", + fmt="%(log_color)s[%(asctime)s.%(msecs)03d] %(filename)s (%(lineno)d) - [%(levelname)s] : %(message)s", + datefmt="%m-%d %H:%M:%S", log_colors=log_colors_config, ) diff --git a/web/package-lock.json b/web/package-lock.json index 205a2956..a1b258ae 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -15,6 +15,7 @@ "ajv-errors": "^3.0.0", "ajv-formats": "^3.0.1", "ajv-i18n": "^4.2.0", + "ansi_up": "^6.0.2", "axios": "^1.7.7", "codemirror": "^5.65.18", "core-js": "^3.37.1", @@ -1334,6 +1335,15 @@ "ajv": "^8.0.0-beta.0" } }, + "node_modules/ansi_up": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ansi_up/-/ansi_up-6.0.2.tgz", + "integrity": "sha512-3G3vKvl1ilEp7J1u6BmULpMA0xVoW/f4Ekqhl8RTrJrhEBkonKn5k3bUc5Xt+qDayA6iDX0jyUh3AbZjB/l0tw==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", diff --git a/web/package.json b/web/package.json index c02f2737..2420dd2b 100644 --- a/web/package.json +++ b/web/package.json @@ -15,6 +15,7 @@ "ajv-errors": "^3.0.0", "ajv-formats": "^3.0.1", "ajv-i18n": "^4.2.0", + "ansi_up": "^6.0.2", "axios": "^1.7.7", "codemirror": "^5.65.18", "core-js": "^3.37.1", diff --git a/web/src/pages/Logs.vue b/web/src/pages/Logs.vue index fbdfb72a..e85d7adc 100644 --- a/web/src/pages/Logs.vue +++ b/web/src/pages/Logs.vue @@ -1,14 +1,18 @@ @@ -25,6 +29,7 @@ const snackbar = inject('snackbar'); const { proxy } = getCurrentInstance() const logContent = ref('') +const logContentHTML = ref('') const refresh = () => { refreshLog() @@ -35,6 +40,10 @@ let logPointer = { "start_offset": 0 } +import { AnsiUp } from 'ansi_up'; + +const ansiUp = new AnsiUp() + const refreshLog = () => { proxy.$axios.get(`/logs`, { params: { @@ -47,8 +56,14 @@ const refreshLog = () => { return } logContent.value += response.data.data.logs + logContentHTML.value += ansiUp.ansi_to_html(response.data.data.logs) logPointer.start_page_number = response.data.data.end_page_number logPointer.start_offset = response.data.data.end_offset + + if (proxy.$store.state.autoScrollLog) { + // 滚动到最底部 + document.getElementById('log-content-html').scrollTop = document.getElementById('log-content-html').scrollHeight + } }).catch(error => { snackbar.error(error.message) }) @@ -73,7 +88,7 @@ onUnmounted(() => { \ No newline at end of file + +#log-content-html { + white-space: pre-wrap; + overflow-y: auto; +} + diff --git a/web/src/store/index.js b/web/src/store/index.js index eb041cbc..fa452a9b 100644 --- a/web/src/store/index.js +++ b/web/src/store/index.js @@ -6,6 +6,7 @@ export default createStore({ state: { apiBaseUrl: 'http://localhost:5300/api/v1', autoRefreshLog: false, + autoScrollLog: true, settingsPageTab: '', version: 'v0.0.0', debug: false,