Toggle navigation
Toggle navigation
This project
Loading...
Sign in
万朱浩
/
Venue-Ops
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
戒酒的李白
2025-08-24 17:13:00 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
4d90f56b42124b58d2bb2676baaeab21be88654e
4d90f56b
1 parent
4de9a33c
Introduce the function of initially restoring the real-time output of console information.
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
138 additions
and
132 deletions
app.py
templates/index.html
app.py
View file @
4d90f56
...
...
@@ -74,27 +74,69 @@ def read_log_from_file(app_name, tail_lines=None):
def
read_process_output
(
process
,
app_name
):
"""读取进程输出并写入文件"""
import
select
import
sys
while
True
:
try
:
if
process
.
poll
()
is
not
None
:
# 进程结束,读取剩余输出
remaining_output
=
process
.
stdout
.
read
()
if
remaining_output
:
lines
=
remaining_output
.
decode
(
'utf-8'
,
errors
=
'replace'
)
.
split
(
'
\n
'
)
for
line
in
lines
:
line
=
line
.
strip
()
if
line
:
timestamp
=
datetime
.
now
()
.
strftime
(
'
%
H:
%
M:
%
S'
)
formatted_line
=
f
"[{timestamp}] {line}"
write_log_to_file
(
app_name
,
formatted_line
)
socketio
.
emit
(
'console_output'
,
{
'app'
:
app_name
,
'line'
:
formatted_line
})
break
output
=
process
.
stdout
.
readline
()
if
output
:
# 使用UTF-8解码,忽略错误字符
line
=
output
.
decode
(
'utf-8'
,
errors
=
'replace'
)
.
strip
()
if
line
:
timestamp
=
datetime
.
now
()
.
strftime
(
'
%
H:
%
M:
%
S'
)
formatted_line
=
f
"[{timestamp}] {line}"
# 写入日志文件
write_log_to_file
(
app_name
,
formatted_line
)
# 发送到前端
socketio
.
emit
(
'console_output'
,
{
'app'
:
app_name
,
'line'
:
formatted_line
})
# 使用非阻塞读取
if
sys
.
platform
==
'win32'
:
# Windows下使用不同的方法
output
=
process
.
stdout
.
readline
()
if
output
:
line
=
output
.
decode
(
'utf-8'
,
errors
=
'replace'
)
.
strip
()
if
line
:
timestamp
=
datetime
.
now
()
.
strftime
(
'
%
H:
%
M:
%
S'
)
formatted_line
=
f
"[{timestamp}] {line}"
# 写入日志文件
write_log_to_file
(
app_name
,
formatted_line
)
# 发送到前端
socketio
.
emit
(
'console_output'
,
{
'app'
:
app_name
,
'line'
:
formatted_line
})
else
:
# 没有输出时短暂休眠
time
.
sleep
(
0.1
)
else
:
# Unix系统使用select
ready
,
_
,
_
=
select
.
select
([
process
.
stdout
],
[],
[],
0.1
)
if
ready
:
output
=
process
.
stdout
.
readline
()
if
output
:
line
=
output
.
decode
(
'utf-8'
,
errors
=
'replace'
)
.
strip
()
if
line
:
timestamp
=
datetime
.
now
()
.
strftime
(
'
%
H:
%
M:
%
S'
)
formatted_line
=
f
"[{timestamp}] {line}"
# 写入日志文件
write_log_to_file
(
app_name
,
formatted_line
)
# 发送到前端
socketio
.
emit
(
'console_output'
,
{
'app'
:
app_name
,
'line'
:
formatted_line
})
except
Exception
as
e
:
error_msg
=
f
"Error reading output for {app_name}: {e}"
print
(
error_msg
)
...
...
@@ -126,16 +168,19 @@ def start_streamlit_app(app_name, script_path, port):
'--server.port'
,
str
(
port
),
'--server.headless'
,
'true'
,
'--browser.gatherUsageStats'
,
'false'
,
'--logger.level'
,
'info'
'--logger.level'
,
'debug'
,
# 增加日志详细程度
'--server.enableCORS'
,
'false'
]
# 设置环境变量确保UTF-8编码
# 设置环境变量确保UTF-8编码
和减少缓冲
env
=
os
.
environ
.
copy
()
env
.
update
({
'PYTHONIOENCODING'
:
'utf-8'
,
'PYTHONUTF8'
:
'1'
,
'LANG'
:
'en_US.UTF-8'
,
'LC_ALL'
:
'en_US.UTF-8'
'LC_ALL'
:
'en_US.UTF-8'
,
'PYTHONUNBUFFERED'
:
'1'
,
# 禁用Python缓冲
'STREAMLIT_BROWSER_GATHER_USAGE_STATS'
:
'false'
})
# 使用当前工作目录而不是脚本目录
...
...
@@ -143,11 +188,12 @@ def start_streamlit_app(app_name, script_path, port):
cmd
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
,
bufsize
=
1
,
bufsize
=
0
,
# 无缓冲
universal_newlines
=
False
,
cwd
=
os
.
getcwd
(),
env
=
env
,
encoding
=
None
# 让我们手动处理编码
encoding
=
None
,
# 让我们手动处理编码
creationflags
=
subprocess
.
CREATE_NO_WINDOW
if
sys
.
platform
==
'win32'
else
0
)
processes
[
app_name
][
'process'
]
=
process
...
...
@@ -314,6 +360,27 @@ def get_output(app_name):
'output'
:
output_lines
})
@app.route
(
'/api/test_log/<app_name>'
)
def
test_log
(
app_name
):
"""测试日志写入功能"""
if
app_name
not
in
processes
:
return
jsonify
({
'success'
:
False
,
'message'
:
'未知应用'
})
# 写入测试消息
test_msg
=
f
"[{datetime.now().strftime('
%
H:
%
M:
%
S')}] 测试日志消息 - {datetime.now()}"
write_log_to_file
(
app_name
,
test_msg
)
# 通过Socket.IO发送
socketio
.
emit
(
'console_output'
,
{
'app'
:
app_name
,
'line'
:
test_msg
})
return
jsonify
({
'success'
:
True
,
'message'
:
f
'测试消息已写入 {app_name} 日志'
})
@app.route
(
'/api/search'
,
methods
=
[
'POST'
])
def
search
():
"""统一搜索接口"""
...
...
templates/index.html
View file @
4d90f56
...
...
@@ -172,32 +172,16 @@
/* 控制台输出 */
.console-output
{
flex
:
1
;
padding
:
15px
;
background-color
:
#000000
;
color
:
#00ff00
;
font-family
:
'Courier New'
,
monospace
;
font-size
:
12px
;
overflow
:
hidden
;
/* 隐藏滚动条,由内部面板控制 */
position
:
relative
;
min-height
:
0
;
/* 允许内容缩小 */
max-height
:
100%
;
/* 限制最大高度 */
}
/* 控制台面板 */
.console-panel
{
position
:
absolute
;
top
:
0
;
left
:
0
;
width
:
100%
;
height
:
100%
;
padding
:
15px
;
overflow-y
:
auto
;
white-space
:
pre-wrap
;
word-break
:
break-all
;
display
:
none
;
/* 默认隐藏 */
}
.console-panel.active
{
display
:
block
;
/* 激活时显示 */
min-height
:
0
;
/* 允许内容缩小 */
max-height
:
100%
;
/* 限制最大高度 */
}
.console-line
{
...
...
@@ -320,20 +304,7 @@
<!-- 控制台输出 -->
<div
class=
"console-output"
id=
"consoleOutput"
>
<!-- Insight Engine 控制台 -->
<div
class=
"console-panel active"
id=
"console-insight"
>
<div
class=
"console-line"
>
[系统] Insight Engine 控制台
</div>
</div>
<!-- Media Engine 控制台 -->
<div
class=
"console-panel"
id=
"console-media"
>
<div
class=
"console-line"
>
[系统] Media Engine 控制台
</div>
</div>
<!-- Query Engine 控制台 -->
<div
class=
"console-panel"
id=
"console-query"
>
<div
class=
"console-line"
>
[系统] Query Engine 控制台
</div>
</div>
<div
class=
"console-line"
>
[系统] 等待连接...
</div>
</div>
</div>
</div>
...
...
@@ -367,13 +338,10 @@
checkStatus
();
setInterval
(
checkStatus
,
5000
);
// 初始化行计数
lastLineCount
=
{
insight
:
1
,
media
:
1
,
query
:
1
};
// 跳过初始消息
// 定期刷新控制台输出
setInterval
(()
=>
{
refreshConsoleOutput
();
},
2
000
);
},
1
000
);
// 延迟预加载iframe以确保应用启动完成
setTimeout
(()
=>
{
...
...
@@ -395,16 +363,8 @@
});
socket
.
on
(
'console_output'
,
function
(
data
)
{
// 直接添加到对应应用的控制台面板,不依赖currentApp
const
consolePanel
=
document
.
getElementById
(
`
console
-
$
{
data
.
app
}
`
);
if
(
consolePanel
)
{
const
div
=
document
.
createElement
(
'div'
);
div
.
className
=
'console-line'
;
div
.
textContent
=
data
.
line
;
consolePanel
.
appendChild
(
div
);
// 自动滚动到底部
consolePanel
.
scrollTop
=
consolePanel
.
scrollHeight
;
if
(
data
.
app
===
currentApp
)
{
addConsoleOutput
(
data
.
line
);
}
});
...
...
@@ -489,24 +449,12 @@
currentApp
=
app
;
// 切换控制台面板显示
document
.
querySelectorAll
(
'.console-panel'
).
forEach
(
panel
=>
{
panel
.
classList
.
remove
(
'active'
);
});
document
.
getElementById
(
`
console
-
$
{
app
}
`
).
classList
.
add
(
'active'
);
// 清空并加载新的控制台输出
document
.
getElementById
(
'consoleOutput'
).
innerHTML
=
'<div class="console-line">[系统] 切换到 '
+
app
+
' 应用</div>'
;
// 只在面板为空时加载输出,不重置行计数
const
consolePanel
=
document
.
getElementById
(
`
console
-
$
{
app
}
`
);
if
(
consolePanel
&&
consolePanel
.
children
.
length
<=
1
)
{
// 只有初始消息
loadConsoleOutput
(
app
);
}
// 切换后滚动到底部
setTimeout
(()
=>
{
if
(
consolePanel
)
{
consolePanel
.
scrollTop
=
consolePanel
.
scrollHeight
;
}
},
100
);
// 重置行计数
lastLineCount
[
app
]
=
0
;
loadConsoleOutput
(
app
);
// 更新嵌入页面
updateEmbeddedPage
(
app
);
...
...
@@ -521,7 +469,7 @@
.
then
(
response
=>
response
.
json
())
.
then
(
data
=>
{
if
(
data
.
success
&&
data
.
output
.
length
>
0
)
{
const
console
Panel
=
document
.
getElementById
(
`
console
-
$
{
app
}
`
);
const
console
Output
=
document
.
getElementById
(
'consoleOutput'
);
// 只添加新的行
const
lastCount
=
lastLineCount
[
app
]
||
0
;
...
...
@@ -531,11 +479,11 @@
const
div
=
document
.
createElement
(
'div'
);
div
.
className
=
'console-line'
;
div
.
textContent
=
line
;
console
Panel
.
appendChild
(
div
);
console
Output
.
appendChild
(
div
);
});
lastLineCount
[
app
]
=
data
.
output
.
length
;
console
Panel
.
scrollTop
=
consolePanel
.
scrollHeight
;
console
Output
.
scrollTop
=
consoleOutput
.
scrollHeight
;
}
})
.
catch
(
error
=>
{
...
...
@@ -543,57 +491,48 @@
});
}
// 刷新
所有
应用的控制台输出
// 刷新
当前
应用的控制台输出
function
refreshConsoleOutput
()
{
// 为每个应用刷新输出,不只是当前应用
Object
.
keys
(
appStatus
).
forEach
(
app
=>
{
if
(
appStatus
[
app
]
===
'running'
||
appStatus
[
app
]
===
'starting'
)
{
fetch
(
`
/
api
/
output
/
$
{
app
}
`
)
.
then
(
response
=>
response
.
json
())
.
then
(
data
=>
{
if
(
data
.
success
&&
data
.
output
.
length
>
0
)
{
const
consolePanel
=
document
.
getElementById
(
`
console
-
$
{
app
}
`
);
// 只添加新的行
const
lastCount
=
lastLineCount
[
app
]
||
0
;
const
newLines
=
data
.
output
.
slice
(
lastCount
);
if
(
appStatus
[
currentApp
]
===
'running'
||
appStatus
[
currentApp
]
===
'starting'
)
{
fetch
(
`
/
api
/
output
/
$
{
currentApp
}
`
)
.
then
(
response
=>
response
.
json
())
.
then
(
data
=>
{
if
(
data
.
success
&&
data
.
output
.
length
>
0
)
{
const
consoleOutput
=
document
.
getElementById
(
'consoleOutput'
);
// 只添加新的行
const
lastCount
=
lastLineCount
[
currentApp
]
||
0
;
const
newLines
=
data
.
output
.
slice
(
lastCount
);
if
(
newLines
.
length
>
0
)
{
newLines
.
forEach
(
line
=>
{
const
div
=
document
.
createElement
(
'div'
);
div
.
className
=
'console-line'
;
div
.
textContent
=
line
;
consoleOutput
.
appendChild
(
div
);
});
if
(
newLines
.
length
>
0
)
{
newLines
.
forEach
(
line
=>
{
const
div
=
document
.
createElement
(
'div'
);
div
.
className
=
'console-line'
;
div
.
textContent
=
line
;
consolePanel
.
appendChild
(
div
);
});
lastLineCount
[
app
]
=
data
.
output
.
length
;
// 只有当前显示的面板才自动滚动
if
(
app
===
currentApp
)
{
consolePanel
.
scrollTop
=
consolePanel
.
scrollHeight
;
}
}
lastLineCount
[
currentApp
]
=
data
.
output
.
length
;
consoleOutput
.
scrollTop
=
consoleOutput
.
scrollHeight
;
}
})
.
catch
(
error
=>
{
console
.
error
(
`刷新
$
{
app
}
输出失败
:
`
,
error
);
});
}
});
}
})
.
catch
(
error
=>
{
console
.
error
(
'刷新输出失败:'
,
error
);
});
}
}
// 添加控制台输出
function
addConsoleOutput
(
line
)
{
// 根据当前应用添加到对应的控制台面板
const
consolePanel
=
document
.
getElementById
(
`
console
-
$
{
currentApp
}
`
);
if
(
consolePanel
)
{
const
div
=
document
.
createElement
(
'div'
);
div
.
className
=
'console-line'
;
div
.
textContent
=
line
;
consolePanel
.
appendChild
(
div
);
// 自动滚动到底部显示最新内容
consolePanel
.
scrollTop
=
consolePanel
.
scrollHeight
;
}
const
consoleOutput
=
document
.
getElementById
(
'consoleOutput'
);
const
div
=
document
.
createElement
(
'div'
);
div
.
className
=
'console-line'
;
div
.
textContent
=
line
;
consoleOutput
.
appendChild
(
div
);
// 自动滚动到底部显示最新内容
consoleOutput
.
scrollTop
=
consoleOutput
.
scrollHeight
;
}
// 预加载的iframe存储
...
...
Please
register
or
login
to post a comment