一个从远程获取安装日志, 以文件流的形式返回前端的逻辑
先贴代码:
class LogFile(LoginRequiredMixin, View):
"""获取日志文件
"""
def get(self, request, *args, **kwargs):
data = json.loads(request.GET.get('data', '{}'))
host = data.get('host', None)
user = data.get('user', None)
pwd = data.get('password', None)
if host and user and pwd:
c = Connection(host, user, connect_kwargs={'password': pwd})
try:
logs = c.run(
'ls -t ' + DEPLOYMENT_LOG_PATH +
' | grep install', pty=True)
logs = logs.stdout.split('\n')
return JsonResponse({'logs': logs})
except (AuthenticationException, NoValidConnectionsError,
UnexpectedExit) as e:
return JsonResponse({'error': e.__str__()})
else:
return HttpResponse(0)
def post(self, request, *args, **kwargs):
data = json.loads(request.POST.get('data', '{}'))
host = data.get('host', None)
user = data.get('user', None)
pwd = data.get('password', None)
seek = data.get('seek', None)
log_name = data.get('logfile', None)
log_name = log_name[:-1] if log_name else None
if host and log_name and (isinstance(seek, int) or seek.isdigit()):
if not (user and pwd) and (user or pwd):
return JsonResponse({'error': 'args error'})
elif user and pwd:
c = Connection(host, user, connect_kwargs={'password': pwd})
try:
c.get(DEPLOYMENT_LOG_PATH + log_name, '%s/log/%s' % (
settings.BASE_DIR, log_name))
log_file = '%s/log/%s' % (settings.BASE_DIR, log_name)
except (IOError, AuthenticationException,
NoValidConnectionsError, UnexpectedExit) as e:
return JsonResponse({'error': e.__str__()})
else:
log_file = '/var/log/' + log_name
def read_log(log_file):
with open(log_file, 'rb') as f:
f.seek(0, 2)
if f.tell() == int(seek):
yield '\nseek:' + seek
else:
f.seek(int(seek))
while 1:
log = f.read(512)
if log:
yield log
else:
break
yield '\nseek:' + str(f.tell())
os.remove(log_file)
response = StreamingHttpResponse(read_log(log_file))
return response
else:
return JsonResponse({'error': 'args error'})
前端在迭代完之后,会等待 2 秒再发送下一个请求, 在匹配到安装完成的关键字后就不再请求
上周五走的时候,放着测试
21:13:22 开始查看日志
21:53:18 返回的错误信息
错误信息在这一段
c = Connection(host, user, connect_kwargs={'password': pwd})
try:
c.get(DEPLOYMENT_LOG_PATH + log_name, '%s/log/%s' % (
settings.BASE_DIR, log_name))
log_file = '%s/log/%s' % (settings.BASE_DIR, log_name)
except (IOError, AuthenticationException,
NoValidConnectionsError, UnexpectedExit) as e:
return JsonResponse({'error': e.__str__()})
查了一下说是达到了系统限制的打开文件句柄数量
但奇怪的是,我的逻辑是每次获取请求后,
拉取文件,读文件,关闭文件,删除文件,
按说,一个请求结束,文件也就没了,打开的文件句柄也就没了呀,
怎么会报这个错呢?
难道说, 要整个 django 进程都关闭了才算?
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.