更新
- 2020/06/13 修正 Unity 进程启动失败时日志线程未正确退出导致 Jenkins 卡死
- 2019/05/19 初次发布
介绍
Unity 编辑器在 macOS 平台上可以使用 -logfile
将日志重定向到标准输出中,即可以在终端中看到日志。但是在 Windows 平台上此参数无效。
原理
因此在 Windows 平台上需要使用辅助工具,由于整个构建流程需要支持跨平台,Python 成为最佳选择,因此使用 Python 编写一个 tail 线程输出日志。
环境
需求
编码
支持 Windows 命令行的 GB18030 编码,输出中文无乱码。
在实现时需要将标准输出的编码改为系统 GB18030 编码。
完整
在 Unity 编辑器进程出错退出时,可以完整输出所有日志,而不是正好缺少崩溃部分。
在实现时需要使用 Thread.join
等待日志线程读取完成,可以设置超时时间如 5 秒。
兼容性
正确处理换行符,保证在与其他持续集成软件结合时换行符不会多或少,如 Jenkins。
在实现时需要将从日志文件中读取到的换行符都删除掉,然后使用 Python 自己的换行符输出。有两点好处:
- 统一换行符,Unity 内部在输出时有时会混合使用不同换行符,导致日志看起来很奇怪。
- 可以根据需要设置统一换行符为任意字符,甚至删除换行符。
代码
Python 启动线程记录日志,主要参考下面的项目实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import os
import time
import sys
import io
from threading import Thread
class Tail(Thread):
def __init__(self, filename):
self._filename = filename
self._stop_reading = False
Thread.__init__(self)
def run(self):
while not self._stop_reading and not os.path.exists(self._filename):
time.sleep(0.1)
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb18030')
with self.open_default_encoding(self._filename, mode='r') as file:
while True:
where = file.tell()
line = file.readline()
if self._stop_reading and not line:
break
if not line:
time.sleep(1)
file.seek(where)
else:
if sys.stdout.closed:
return
print(line.rstrip())
sys.stdout.flush()
def stop(self):
self._stop_reading = True
# Wait for thread read the remaining log after process quit in 5 seconds
self.join(5)
@staticmethod
def open_default_encoding(file, mode):
return open(file, mode=mode, encoding='utf-8-sig')
|
使用方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
log_file = os.path.join(project_path, 'UnityEditor.log')
cmd = [
'C:\Program Files\Unity\Editor\Unity.exe',
'-batchmode',
'-quit',
'-nographics',
'-silent-crashes',
'-projectpath', project_path,
'-logfile', log_file,
]
tail = lib.tail.Tail(log_file)
tail.start()
status = os.system(' '.join(cmd))
tail.stop()
|