python 将增量文件日志存入数据库

36 篇文章 0 订阅

    我们在操作数据的时候经常遇到这样的情况,需要对一些产生环境的日志数据进行分析,而某些大公司的朋友,经常没有服务器的管理权限,因此,我们就需要将数据自动导入的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()


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值