我们在操作数据的时候经常遇到这样的情况,需要对一些产生环境的日志数据进行分析,而某些大公司的朋友,经常没有服务器的管理权限,因此,我们就需要将数据自动导入的mysql中,本内容就是基于。
文章重点:
1 日志文件按行读取,防止日志数据过大,操作时使用行读取,不占用内存空间
2 数据库使用长链接,进行写操作,mysql的长连接文章在我们的“python mysql 长连接一篇有写到” 【http://blog.csdn.net/wzm112/article/details/7745835】
3 日志数据统一归并到一个日志目录下,由于我在实际生产环境中使用log作为日志目录这里不做调整
4 在指定数据库中自动创建和日志文件相同的表名,自动进行数据导入工作,当然可以进行自己的改进,做成规则,根据你定义的规则进行导入,比如某个或某几个后缀的文件进行导入,数据存储的方式这些都可以事先定义成规则。
5 对增量日志,从增量点开始读取,记录增量位置是文件名.seek的文件
6 定时删除任务,每晚三点(根据log.time中的时间来操作)删除日志中的日志文件(txt)和文件名.seek(统计读到的文件位置)
7 整个操作基本都是基于文件,这里操作的日志文件后缀都为txt,各人可根据各人情况进行调整
8 执行方式,将此文件作为守护进程,使用nohup 方式,在服务器上挂起
#!/usr/bin/env python
#coding=utf-8
import os,sys,time,traceback
from libs.mysql import mysql
from libs.config import _config #调用配置文件,配置文件解析类
reload(sys)
sys.setdefaultencoding('utf8')
class read_log:
def __init__ (self):
self.dir_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) #找到项目的根目录
self.logDbConfig =_config['db_config'] #读取数据库配置
self.logDb = None
self.get_log_conn() #连接数据库
pass
def get_log_conn (self):
host = self.logDbConfig['host']
user = self.logDbConfig['user']
passwd = self.logDbConfig['passwd']
db = self.logDbConfig['db']
self.logDb = mysql(host, user, passwd, db)
def write_time_log (self,itime = 0): #写入当前时间
f = open(os.path.join(self.dir_path,'log_time_log.time'),'w')
f.write(str(itime))
f.close()
def read_time_log (self): #读出时间
#return int(time.strftime('%H',time.localtime(time.time())))
_f_name = os.path.join(self.dir_path,'log_time_log.time')
if os.path.exists(_f_name):
f = open(_f_name,'r')
result = f.read()
f.close()
if result: return long(result)
return 0
def delete_txt_file (self): #删除txt后缀的日志文件和txt.seek的后缀文件
for filename in self.read_dir():
idir = '%s/log' % self.dir_path
fname = '%s/%s' % (idir,filename)
try:
os.remove(fname)
os.remove('%s.%s' % (fname,'seek'))
except:
pass
def run (self): #主执行程序
while True:
self.read_file_content() #将日志写入数据库
if self.read_time_log()==0 and int(time.strftime('%H',time.localtime(time.time())))==3: #每晚3点进行日志清理
self.delete_txt_file()
self.write_time_log(int(time.time()))
elif int(time.strftime('%H',time.localtime(time.time())))==3 and time.strftime('%Y%m%d',time.localtime(time.time())) != time.strftime('%Y%m%d',time.localtime(self.read_time_log())) :
self.delete_txt_file()
self.write_time_log(int(time.time()))
time.sleep(60) #程序循环操作,每隔1分钟循环一次,时间根据自己情况而定
def create_table (self,table_name = ''): #创建日志写入的表结构
if table_name:
sql = '''
CREATE TABLE IF NOT EXISTS `log_%s` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`task_id` varchar(30) NOT NULL DEFAULT '0',
`entid` varchar(20) NOT NULL DEFAULT '0',
`source` varchar(20) NOT NULL DEFAULT '0',
`data` longtext NOT NULL,
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
''' % table_name
self.logDb.query(sql)
def write_seek (self,filename = '',seek = 0): #写入当前的seek位置
f = open(os.path.join(self.dir_path,'%s.seek' % filename ),'w')
f.write(str(seek))
f.close()
def read_seek (self,filename = '',seek = 0): #读取文件的seek位置
_f_name = os.path.join(self.dir_path,'%s.seek' % filename )
if os.path.exists(_f_name):
f = open(_f_name,'r')
result = f.read()
f.close()
if result: return long(result)
return 0
def read_dir (self): #读取日志目录的包含.txt后缀的不包含seek的文件
print self.dir_path
idir = '%s/log' % self.dir_path
print idir
return [ row for row in os.listdir(idir) if '.txt' in row and 'seek' not in row ]
def read_file_content (self): #将所有符合规则的文件读到对应的数据库
for filename in self.read_dir():
idir = '%s/log' % self.dir_path
fname = '%s/%s' % (idir,filename)
if len(filename)>4:
table_name = filename[:-4]
self.create_table(table_name) #create table
self._read_content(fname,table_name) #read file name
def _read_content (self,filename = '',table =''): #子方法,读取单个文件,单个行写入数据库
file_seek = self.read_seek(filename)
f = open(filename,'r')
f.seek(file_seek) #找到上次读完的seek文件,从此位置继续往下读写
while True:
_row = f.readline() #单行,循环
file_seek +=len(_row) #计算seek位置
self.write_seek(filename,file_seek) #保持新的seek位置
result_row = ''
try:
if _row.find('{')==0: #查找符合条件的字典数据,这个根据自己情况,如果自己的日志内容根据固定可不需要校验
result_row = eval(_row) #字符转字典
task_id = result_row.get('msgId','')
entid = result_row.get('entId','')
source = result_row.get('source','')
data = _row.replace("\\","\\\\").replace("'","\\'")
sql = "INSERT INTO `log_%s` (`task_id` ,`entid` ,`source` ,`data` ) VALUES ('%s', '%s', '%s', '%s')" % (table,task_id,entid,source,data)
self.logDb.query(sql)
except:
pass
if not _row: break
f.close()
_read_log = read_log()
if __name__=='__main__':
_read_log.run()