update to 6.8.37

This commit is contained in:
zhw
2024-04-29 15:35:04 +08:00
parent fa9a865beb
commit ed34994f45
474 changed files with 125711 additions and 34665 deletions
+141
View File
@@ -0,0 +1,141 @@
#coding: utf-8
import os,sys,time,json
panelPath = os.getenv('BT_PANEL')
if not panelPath:
panelPath = "/www/server/panel"
os.chdir(panelPath)
if not panelPath + "/class/" in sys.path:
sys.path.insert(0, panelPath + "/class/")
import public,re
class logsBase:
def __init__(self):
pass
def find_line_str(self,_line,search):
"""
@name 查找字符串
"""
if search:
if _line.lower().find(search.lower()) != -1:
return True
else:
return True
return False
def return_line_area(self,logs_list,ip_list):
"""
@name 日志行返回归属地
"""
if len(logs_list) <= 0: return logs_list
n_data = '\r\n'.join(logs_list)
res = public.get_ips_area(ip_list)
for ip in ip_list:
area = 'Unknown'
if 'status' in res:
area = '**** (Professional version exclusive)'
elif ip in res:
area = res[ip]['info']
n_data = n_data.replace(ip,'{}({})'.format(ip,area))
log_list = n_data.split('\r\n')
return log_list
def GetNumLines(self,path, num, p=1,search = None):
"""
@name 取文件指定尾行数
@param path 文件路径
@param num 取尾行数
@param p 当前页
@param search 搜索关键字
@return list
"""
pyVersion = sys.version_info[0]
max_len = 1024 * 128 * 1024
try:
from html import escape
if not os.path.exists(path): return ""
start_line = (p - 1) * num
count = start_line + num
fp = open(path, 'rb')
buf = ""
fp.seek(-1, 2)
if fp.read(1) == "\n": fp.seek(-1, 2)
data = []
total_len = 0
b = True
n = 0
for i in range(count):
while True:
newline_pos = str.rfind(str(buf), "\n")
pos = fp.tell()
if newline_pos != -1:
if n >= start_line:
line = buf[newline_pos + 1:]
is_res = True
if search:
is_res = False
if line.find(search) >= 0 or re.search(search,line):
is_res = True
if is_res:
line_len = len(line)
total_len += line_len
sp_len = total_len - max_len
if sp_len > 0:
line = line[sp_len:]
try:
data.insert(0, escape(line))
except:
pass
buf = buf[:newline_pos]
n += 1
break
else:
if pos == 0:
b = False
break
to_read = min(4096, pos)
fp.seek(-to_read, 1)
t_buf = fp.read(to_read)
if pyVersion == 3:
try:
if type(t_buf) == bytes: t_buf = t_buf.decode('utf-8',errors='ignore')
except:
try:
if type(t_buf) == bytes: t_buf = t_buf.decode('gbk',errors='ignore')
except:
t_buf = str(t_buf)
buf = t_buf + buf
fp.seek(-to_read, 1)
if pos - to_read == 0:
buf = "\n" + buf
if total_len >= max_len: break
if not b: break
fp.close()
result = "\n".join(data)
if not result: raise Exception('null')
except:
result = ''
if len(result) > max_len:
result = result[-max_len:]
try:
try:
result = json.dumps(result)
return json.loads(result).strip()
except:
if pyVersion == 2:
result = result.decode('utf8', errors='ignore')
else:
result = result.encode('utf-8', errors='ignore').decode("utf-8", errors="ignore")
return result.strip()
except:
return ""
+469
View File
@@ -0,0 +1,469 @@
#coding: utf-8
# + -------------------------------------------------------------------
# | 宝塔Linux面板
# + -------------------------------------------------------------------
# | Copyright (c) 2015-2016 宝塔软件(http:#bt.cn) All rights reserved.
# + -------------------------------------------------------------------
# | Author: hezhihong <272267659@@qq.cn>
# + -------------------------------------------------------------------
import public, os, time
from logsModel.base import logsBase
try:
from BTPanel import session
except:
pass
#英文转月份缩写
month_list = {
"Jan": "1",
"Feb": "2",
"Mar": "3",
"Apr": "4",
"May": "5",
"Jun": "6",
"Jul": "7",
"Aug": "8",
"Sept": "9",
"Sep": "9",
"Oct": "10",
"Nov": "11",
"Dec": "12"
}
class main(logsBase):
def __init__(self):
self.__messages_file = "/var/log/"
self.__ftp_backup_path = public.get_backup_path() + '/pure-ftpd/'
if not os.path.isdir(self.__ftp_backup_path):
public.ExecShell('mkdir -p {}'.format(self.__ftp_backup_path))
self.__script_py = public.get_panel_path() + '/script/ftplogs_cut.py'
def get_file_list(self, path, is_bakcup=False):
"""
@name 取所有messages日志文件
@param path: 日志文件路径
@return: 返回日志文件列表
"""
files = os.listdir(path)
if is_bakcup:
file_name_list = [{
"file": "/var/log/pure-ftpd.log",
"time": int(time.time())
}]
else:
file_name_list = []
for i in files:
tmp_dict = {}
if not i: continue
file_path = path + i
tmp_dict['file'] = file_path
if is_bakcup:
if os.path.isfile(file_path) and i.find('pure-ftpd.log') != -1:
tmp_dict['time'] = int(
public.to_date(
times=os.path.basename(file_path).split('_')[0] +
' 00:00:00'))
file_name_list.append(tmp_dict)
else:
if os.path.isfile(file_path) and i.find('messages') != -1:
tmp_dict['time'] = int(
public.to_date(
times=os.path.basename(file_path).split('-')[1] +
' 00:00:00'))
file_name_list.append(tmp_dict)
file_name_list = sorted(file_name_list,
key=lambda x: x['time'],
reverse=False)
return file_name_list
def set_ftp_log(self, get):
"""
@name 开启、关闭、获取日志状态
@author hezhihong
@param get.exec_name 执行的动作
"""
if not hasattr(get, 'exec_name'):
return public.returnMsg(False, 'The parameter is incorrect!')
conf_path = '/etc/rsyslog.conf'
conf = public.readFile(conf_path)
import re
search_str = r"ftp\.\*.*\t*.*\t*.*-/var/log/pure-ftpd.log"
search_str_two = "ftp.none"
rep_str = '\nftp.*\t\t-/var/log/pure-ftpd.log\n'
result = re.search(search_str, conf)
#获取日志状态
if get.exec_name == 'getlog':
if result:
return_result = 'start'
else:
return_result = 'stop'
return public.returnMsg(True, return_result)
#开启日志审计
elif get.exec_name == 'start':
if result:
conf = conf.replace(search_str, rep_str)
else:
conf += rep_str
#禁止ftp日志写入/var/log/messages
d_conf = conf[conf.rfind('info;'):]
d_conf = d_conf[:d_conf.find('/')]
s_conf = d_conf.replace(',', ';')
if s_conf.find(search_str_two) == -1:
str_index = s_conf.rfind(';')
s_conf = s_conf[:str_index +
1] + search_str_two + s_conf[str_index + 1:]
conf = conf.replace(d_conf, s_conf)
self.add_crontab()
#关闭日志审计
elif get.exec_name == 'stop':
if result:
conf = re.sub(search_str, '', conf)
#取消禁止ftp日志写入/var/log/messages
if conf.find(search_str_two) != -1:
conf = conf.replace(search_str_two, '')
for i in [';;', ',,', ';,', ',;']:
if conf.find(i) != -1: conf = conf.replace(i, '')
self.del_crontab()
public.writeFile(conf_path, conf)
public.ExecShell('systemctl restart rsyslog')
return public.returnMsg(True, 'successfully set')
def get_format_time(self, englist_time):
"""
@name 时间英文转换
"""
chinanese_time = ''
try:
for i in month_list.keys():
if i in englist_time:
tmp_time = englist_time.replace(i, month_list[i])
tmp_time = tmp_time.split()
chinanese_time = '{}-{} {}'.format(tmp_time[0], tmp_time[1],
tmp_time[2])
break
return chinanese_time
except:
return chinanese_time
def get_login_log(self, get):
"""
@name 取登录日志
@author hezhihong
@param get.user_name ftp用户名
return
"""
search_str = 'pure-ftpd:'
search_str2 = 'pure-ftpd['
if not hasattr(get, 'user_name'):
return public.returnMsg(False, 'The parameter is incorrect!')
args = public.dict_obj()
args.exec_name = 'getlog'
file_name = self.__ftp_backup_path
is_backup = True
if self.set_ftp_log(get) == 'stop':
file_name = self.__messages_file
is_backup = False
file_list = self.get_file_list(file_name, is_backup)
data = []
sortid = 0
tmp_dict = {}
login_all = []
for file in file_list:
if not os.path.isfile(file['file']): continue
conf = public.readFile(file['file'])
lines = conf.split('\n')
for line in lines:
if not line: continue
login_info = {}
if search_str not in line and search_str2 not in line:
continue
tmp_value = ' is now logged in'
info = line[:line.find(search_str)].strip()
if not info:
info = line[:line.find(search_str2)].strip()
hostname = info.split()[-1]
exec_time = info.split(hostname)[0].strip()
exec_time = self.get_format_time(exec_time)
ip = line[line.find('(') + 1:line.find(')')].split('@')[1]
#取登录成功日志
if tmp_value in line:
user = line.split(tmp_value)[0].strip().split()[-1]
if user == '?' or user != get.user_name: continue
dict_index = '{}__{}'.format(user, ip)
if dict_index not in tmp_dict:
tmp_dict[dict_index] = []
tmp_dict[dict_index].append(exec_time)
#取登出日志
tmp_value = '[INFO] Logout.'
tmp_value_two = 'Timeout - try typing a little faster next time'
if tmp_value in line or tmp_value_two in line:
user = line[line.find('(') +
1:line.find(')')].split('@')[0]
if user == '?' or user != get.user_name: continue
dict_index = '{}__{}'.format(user, ip)
try:
login_info['out_time'] = exec_time
login_info['in_time'] = tmp_dict[dict_index][0]
login_info['user'] = user
login_info['ip'] = ip
login_info['status'] = 'Success' #0为登录失败,1为登录成功
login_info['sortid'] = sortid
login_all.append(login_info)
tmp_dict[dict_index] = []
sortid += 1
except:
pass
#取登录失败日志
tmp_value = 'Authentication failed for user'
if tmp_value in line:
user = line.split(tmp_value)[-1].replace('[', '').replace(
']', '').strip()
if user == '?' or user != get.user_name: continue
login_info['user'] = user
login_info['ip'] = ip
login_info['status'] = 'Failure' #0为登录失败,1为登录成功
login_info['in_time'] = exec_time
login_info['out_time'] = exec_time
login_info['sortid'] = sortid
login_all.append(login_info)
sortid += 1
if tmp_dict:
for item in tmp_dict.keys():
if not tmp_dict[item]: continue
info = {
"status": "login successful",
"in_time": tmp_dict[item][0],
"out_time": "connecting",
"user": item.split('__')[0],
"ip": item.split('__')[1],
"sortid": sortid
}
sortid += 1
login_all.append(info)
#搜索过滤
if login_all and 'search' in get and get.search and get.search.strip():
for info in login_all:
try:
search_str = str(get.search).strip().lower()
# public.writeFile('/tmp/aa.aa', get.search)
if info['ip'].find(search_str) != -1 or info['user'].lower(
).find(search_str) != -1 or info['status'].find(
search_str) != -1 or info['in_time'].find(
search_str) != -1:
data.append(info)
elif info['out_time'] and info['out_time'].find(
search_str) != -1:
data.append(info)
except:
pass
else:
for info2 in login_all:
data.append(info2)
data = sorted(data, key=lambda x: x['sortid'], reverse=True)
return self.get_page(data, get)
def get_page(self, data, get):
"""
@name 取分页
@author hezhihong
@param data 需要分页的数据 list
@param get.p 第几页
@return 指定分页数据
"""
# 包含分页类
import page
# 实例化分页类
page = page.Page()
info = {}
info['count'] = len(data)
info['row'] = 10
info['p'] = 1
if hasattr(get, 'p'):
info['p'] = int(get['p'])
info['uri'] = {}
info['return_js'] = ''
# 获取分页数据
result = {}
result['page'] = page.GetPage(info, limit='1,2,3,4,5,8')
n = 0
result['data'] = []
for i in range(info['count']):
if n >= page.ROW: break
if i < page.SHIFT: continue
n += 1
result['data'].append(data[i])
return result
def get_action_log(self, get):
"""
@name 取操作日志
@author hezhihong
@param get.user_name ftp用户名
return {"upload":[],"download":[],"rename":[],"delete":[]}
"""
search_str = 'pure-ftpd:'
args = public.dict_obj()
args.exec_name = 'getlog'
file_name = self.__ftp_backup_path
is_backup = True
if self.set_ftp_log(get) == 'stop':
file_name = self.__messages_file
is_backup = False
file_list = self.get_file_list(file_name, is_backup)
if not hasattr(get, 'user_name'):
return public.returnMsg(False, 'The parameter is incorrect!')
data = []
tmp_data = []
sortid = 0
for file in file_list:
if not os.path.isfile(file['file']): continue
conf = public.readFile(file['file'])
lines = conf.split('\n')
for line in lines:
if not line: continue
action_info = {}
if search_str not in line: continue
tmp_v = line.split(search_str)
hostname = tmp_v[0].strip().split()[3].strip()
action_time = tmp_v[0].replace(hostname, '').strip()
action_info['time'] = self.get_format_time(action_time)
upload_value = ' uploaded '
download_value = ' downloaded '
rename_value = 'successfully renamed or moved:'
delete_value = ' Deleted '
ip = line[line.find('(') + 1:line.find(')')].split('@')[1]
action_info['ip'] = ip
action_info['type'] = ''
#取操作用户
user = ''
if upload_value in line or download_value in line or rename_value in line or delete_value in line:
user = line[line.find('(') +
1:line.find(')')].split('@')[0]
action_info['sortid'] = sortid
sortid = sortid + 1
if not user or user != get.user_name: continue
#取上传日志
if (get.type == 'all'
or get.type == 'upload') and upload_value in line:
line_list = line.split()
upload_index = line_list.index('uploaded')
# action_info['file'] = line_list[upload_index - 1].replace(
# '//', '/')
action_info['file'] = line[line.find(']') +
1:line.rfind('(')].replace(
'uploaded',
'').replace('//',
'/').strip()
action_info['type'] = 'upload'
tmp_data.append(action_info)
#取下载日志
if (get.type == 'all'
or get.type == 'download') and download_value in line:
line_list = line.split()
upload_index = line_list.index('downloaded')
action_info['file'] = line_list[upload_index - 1].replace(
'//', '/')
action_info['type'] = 'download'
tmp_data.append(action_info)
#取重命名日志
if (get.type == 'all'
or get.type == 'rename') and rename_value in line:
action_info['file'] = line.split(rename_value)[1].replace(
'->', 'Renamed to').strip().replace('//', '/')
action_info['type'] = 'rename'
tmp_data.append(action_info)
#取删除日志
if (get.type == 'all'
or get.type == 'delete') and delete_value in line:
action_info['file'] = line.split()[-1].strip().replace(
'//', '/')
action_info['type'] = 'delete'
tmp_data.append(action_info)
# f.close
#搜索过滤
if tmp_data and 'search' in get and get.search and get.search.strip():
for info in tmp_data:
search_str = str(get.search).strip().lower()
if info['ip'].find(search_str) != -1 or info['file'].lower(
).find(search_str) != -1 or info['type'].find(
search_str) != -1 or info['time'].find(
search_str) != -1 or get.user_name.lower().find(
search_str) != -1:
data.append(info)
else:
for info2 in tmp_data:
data.append(info2)
data = sorted(data, key=lambda x: x['sortid'], reverse=True)
return self.get_page(data, get)
def del_crontab(self):
"""
@name 删除项目定时清理任务
@auther hezhihong<2022-10-31>
@return
"""
cron_name = '[Do not delete] FTP audit log cutting task'
cron_path = public.GetConfigValue('setup_path') + '/cron/'
cron_list = public.M('crontab').where("name=?", (cron_name, )).select()
if cron_list:
for i in cron_list:
if not i: continue
cron_echo = public.M('crontab').where(
"id=?", (i['id'], )).getField('echo')
args = {"id": i['id']}
import crontab
crontab.crontab().DelCrontab(args)
del_cron_file = cron_path + cron_echo
public.ExecShell(
"crontab -u root -l| grep -v '{}'|crontab -u root -".
format(del_cron_file))
def add_crontab(self):
"""
@name 构造日志切割任务
"""
python_path = ''
try:
python_path = public.ExecShell('which btpython')[0].strip("\n")
except:
try:
python_path = public.ExecShell('which python')[0].strip("\n")
except:
pass
if not python_path: return False
if not public.M('crontab').where('name=?',
('[Do not delete] FTP audit log cutting task', )).count():
cmd = '{} {}'.format(python_path, self.__script_py)
args = {
"name": "[Do not delete] FTP audit log cutting task",
"type": 'day',
"where1": '',
"hour": '0',
"minute": '1',
"sName": "",
"sType": 'toShell',
"notice": '0',
"notice_channel": '',
"save": '',
"save_local": '1',
"backupTo": '',
"sBody": cmd,
"urladdress": ''
}
import crontab
res = crontab.crontab().AddCrontab(args)
if res and "id" in res.keys():
return True
return False
return True
+321
View File
@@ -0,0 +1,321 @@
#coding: utf-8
#-------------------------------------------------------------------
# 宝塔Linux面板
#-------------------------------------------------------------------
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
#-------------------------------------------------------------------
# Author: cjxin <bt_ahong@qq.com>
#-------------------------------------------------------------------
#------------------------------
# 面板日志类
#------------------------------
import os,re,json,time
from logsModel.base import logsBase
import public,db
from html import unescape,escape
class main(logsBase):
def __init__(self):
pass
def get_logs_info(self,args):
'''
@name 获取分类日志信息
'''
data = public.M('logs').query('''
select type,count(id) as 'count' from logs
group by type
order by count(id) desc
''')
result = []
for arrs in data:
item = {}
if not arrs: continue
item['count'] = arrs[1]
item['type'] = arrs[0]
result.append(item)
public.set_module_logs('get_logs_info','get_logs_info')
return result
def get_logs_bytype(self,args):
"""
@name 根据类型获取日志
@param args.type 日志类型
"""
p,limit = 1,20
if 'p' in args: p = int(args.p)
if 'limit' in args: limit = int(args.limit)
stype = args.stype
search = '[' + str(args.search) + ']'
where = "type=? and log like ? "
count = public.M('logs').where(where,(stype,'%'+search+'%')).count()
data = public.get_page(count,p,limit)
data['data'] = public.M('logs').where(where,(stype,'%'+search+'%')).limit('{},{}'.format(data['shift'], data['row'])).order('id desc').select()
return data
def __get_panel_dirs(self):
'''
@name 获取面板日志目录
'''
dirs = []
for filename in os.listdir('{}/logs/request'.format(public.get_panel_path())):
if filename.find('.json') != -1:
dirs.append(filename)
dirs = sorted(dirs,reverse=True)
return dirs
def get_panel_log(self,get):
"""
@name 获取面板日志
"""
p,limit,search = 1,20,''
if 'p' in get: p = int(get.p)
if 'limit' in get: limit = int(get.limit)
if 'search' in get: search = get.search
find_idx = 0
log_list = []
dirs = self.__get_panel_dirs()
for filename in dirs:
log_path = '{}/logs/request/{}'.format(public.get_panel_path(),filename)
if not os.path.exists(log_path): #文件不存在
continue
if len(log_list) >= limit:
break
p_num = 0 #分页计数器
next_file = False
while not next_file:
if len(log_list) >= limit:
break
p_num += 1
result = self.GetNumLines(log_path,10001,p_num).split('\r\n')
if len(result) < 10000:
next_file = True
result.reverse()
for _line in result:
if not _line: continue
if len(log_list) >= limit:
break
try:
if self.find_line_str(_line,search):
find_idx += 1
if find_idx > (p-1) * limit:
info = json.loads(unescape(_line))
for key in info:
if isinstance(info[key],str):
info[key] = escape(info[key])
info['address'] = info['ip'].split(':')[0]
log_list.append(info)
except:pass
return public.return_area(log_list,'address')
def get_panel_error_logs(self,get):
'''
@name 获取面板错误日志
'''
search = ''
if 'search' in get:
search = get.search
filename = '{}/logs/error.log'.format(public.get_panel_path())
if not os.path.exists(filename):
return public.returnMsg(False,'No error log')
res = {}
res['data'] = public.xssdecode(self.GetNumLines(filename,2000,1,search))
res['data'].reverse()
return res
def __get_ftp_log_files(self,path):
"""
@name 获取FTP日志文件列表
@param path 日志文件路径
@return list
"""
file_list = []
if os.path.exists(path):
for filename in os.listdir(path):
if filename.find('.log') == -1: continue
file_list.append('{}/{}'.format(path,filename))
file_list = sorted(file_list,reverse=True)
return file_list
def get_ftp_logs(self,get):
"""
@name 获取ftp日志
"""
p,limit,search,username = 1,500,'',''
if 'p' in get: p = int(get.p)
if 'limit' in get: limit = int(get.limit)
if 'search' in get: search = get.search
if 'username' in get: username = get.username
find_idx = 0
ip_list = []
log_list = []
dirs = self.__get_ftp_log_files('{}/ftpServer/Logs'.format(public.get_soft_path()))
for log_path in dirs:
if not os.path.exists(log_path): continue
if len(log_list) >= limit: break
p_num = 0 #分页计数器
next_file = False
while not next_file:
if len(log_list) >= limit:
break
p_num += 1
result = self.GetNumLines(log_path,10001,p_num).split('\r\n')
if len(result) < 10000:
next_file = True
result.reverse()
for _line in result:
if not _line.strip(): continue
if len(log_list) >= limit:
break
try:
if self.find_line_str(_line,search):
#根据用户名查找
if username and not re.search('-\s+({})\s+\('.format(username),_line):
continue
find_idx += 1
if find_idx > (p-1) * limit:
#获取ip归属地
for _ip in public.get_line_ips(_line):
if not _ip in ip_list: ip_list.append(_ip)
info = escape(_line)
log_list.append(info)
except:pass
return self.return_line_area(log_list,ip_list)
#取慢日志
def get_slow_logs(self,get):
'''
@name 获取慢日志
@get.search 搜索关键字
'''
search,p,limit = '',1,1000
if 'search' in get: search = get.search
if 'limit' in get: limit = get.limit
my_info = public.get_mysql_info()
if not my_info['datadir']:
return public.returnMsg(False,'MySQL is not installed!')
path = my_info['datadir'] + '/mysql-slow.log'
if not os.path.exists(path):
return public.returnMsg(False,'Log file does not exist!')
# mysql慢日志有顺序问题,倒序显示不利于排查问题
return public.returnMsg(True, public.xsssec(public.GetNumLines(path, limit)))
# find_idx = 0
# p_num = 0 #分页计数器
# next_file = False
# log_list = []
# while not next_file:
# if len(log_list) >= limit:
# break
# p_num += 1
# result = self.GetNumLines(path,10001,p_num).replace('\r\n','\n').split('\n')
# if len(result) < 10000:
# next_file = True
# result.reverse()
# for _line in result:
# if not _line: continue
# if len(log_list) >= limit:
# break
# try:
# if self.find_line_str(_line,search):
# find_idx += 1
# if find_idx > (p-1) * limit:
# info = escape(_line)
# log_list.append(info)
# except:pass
# return log_list
def IP_geolocation(self, get):
'''
@name 列出所有IP及其归属地
@return list {ip: {ip: ip_address, operation_num: 12 ,info: 归属地}, ...]
'''
result = dict()
data = public.M('logs').query('''
select * from logs
''')
for arrs in data:
if not arrs: continue
end = 0
# 获得IP的尾后索引
for ch in arrs[2]:
if ch.isnumeric() or ch == '.':
end += 1
else:
break
ip_addr = arrs[2][0:end]
if ip_addr:
if result.get(ip_addr) != None:
result[ip_addr]["operation_num"] = result[ip_addr]["operation_num"] + 1
else:
result[ip_addr] = {"ip":ip_addr,"operation_num":1, "info":None}
return_list = []
for k in result:
info = public.get_free_ip_info(k)
result[k]["info"] = info["info"]
return_list.append(result[k])
return return_list
def get_error_logs_by_search(self, args):
'''
@name 根据搜索内容, 获取运行日志中的内容
@args.search 匹配内容
@return 匹配该内容的所有日志
'''
log_file_path = "{}/logs/error.log".format(public.get_panel_path())
#return log_file_path
data = public.readFile(log_file_path)
if not data:
return None
data = data.split('\n')
result = []
for line in data:
if args.search == None:
result.append(line)
elif args.search in line:
result.append(line)
return result
+110
View File
@@ -0,0 +1,110 @@
#coding: utf-8
#-------------------------------------------------------------------
# 宝塔Linux面板
#-------------------------------------------------------------------
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
#-------------------------------------------------------------------
# Author: cjxin <bt_ahong@qq.com>
#-------------------------------------------------------------------
#------------------------------
# 面板日志类
#------------------------------
import os,re,json,time
from logsModel.base import logsBase
import public,db
from html import unescape,escape
class main(logsBase):
def __init__(self):
self.serverType = public.get_webserver()
def __get_iis_log_files(self,path):
"""
@name 获取IIS日志文件列表
@param path 日志文件路径
@return list
"""
file_list = []
if os.path.exists(path):
for filename in os.listdir(path):
if filename.find('.log') == -1: continue
file_list.append('{}/{}'.format(path,filename))
file_list = sorted(file_list,reverse=False)
return file_list
def get_iis_logs(self,get):
"""
@name 获取IIS网站日志
"""
p,limit,search = 1,2000,''
if 'p' in get: limit = int(get.p)
if 'limit' in get: limit = int(get.limit)
if 'search' in get: search = get.search
import panelSite
site_obj = panelSite.panelSite()
data = site_obj.get_site_info(get.siteName)
if not data:
return public.returnMsg(False,'【{}】网站路径获取失败,请检查IIS是否存在此站点,如IIS不存在请通过面板删除此网站后重新创建.'.format(get.siteName))
log_path = '{}/wwwlogs/W3SVC{}'.format(public.get_soft_path(), data['id'])
file_list = self.__get_iis_log_files(log_path)
find_idx = 0
log_list = []
for log_path in file_list:
if not os.path.exists(log_path): continue
if len(log_list) >= limit: break
p_num = 0 #分页计数器
next_file = False
while not next_file:
if len(log_list) >= limit:
break
p_num += 1
result = self.GetNumLines(log_path,10001,p_num).split('\r\n')
if len(result) < 10000:
next_file = True
for _line in result:
if not _line: continue
if len(log_list) >= limit:
break
try:
if self.find_line_str(_line,search):
find_idx += 1
if find_idx > (p-1) * limit:
info = escape(_line)
log_list.append(info)
except:pass
return log_list
# 取网站日志
def get_site_logs(self, get):
logPath = ''
if self.serverType == 'iis':
return self.get_iis_logs(get)
elif self.serverType == 'apache':
logPath = self.setupPath + '/wwwlogs/' + get.siteName + '-access.log'
else:
logPath = self.setupPath + '/wwwlogs/' + get.siteName + '.log'
data = {}
data['path'] = ''
data['path'] = os.path.dirname(logPath)
if os.path.exists(logPath):
data['status'] = True
data['msg'] = public.GetNumLines(logPath, 1000)
return data
data['status'] = False
data['msg'] = 'log is empty'
return data