协议管理平台 – 解析日志

这里的解析日志指的是对日志文件进行解析,提取有用的数据;协议配置平台里边,一开始的需求并不是很明确,但我加了非常详细的日志,后续扩充功能,数据可以从日志中补全。关于协议配置平台,参照这里,第一个就是。

项目中,解析日志,是为了从日志中获取用户的访问信息,导入数据库,方便查看 / 统计访问人数,为后续优化做准备;

之前设计时,并未考虑访问相关的数据,所以这部分是没有存到数据库的,只能通过日志导入(前提是日志里存了这些数据);

日志格式

日志文件都存放在一个文件夹下,日志文件名格式为 all-log.txt.年-月-日-小时,比如:all-log.txt.2018-03-29-18 表示18年3月29日18时的日志文件;

关于登录后返回的信息,日志中存储的模拟格式如下:

[2018-03-29T18:02:19.445] [INFO] util – auth.a.com 成功返回数据:{“data”:{“id”:111111,”name”:”测试用户”,”email”:”supericesun@gmail.com”,”mobile”:”13210241024″”orgName”:”研发部”,”username”:”sunchao”},”result”:true}

解析

逻辑:获取 logs 下的所有文件  –> 打开文件,逐行获取内容,匹配是否符合规则,找到需要的数据 –> 导入到数据库中

获取logs下的所有文件

假设 logs 文件夹和脚本在同一目录下

  • 此处又用到了 os.walk,文件遍历器;
def main():
    cur_path = os.path.abspath('./logs/')
    cur_path = os.path.normpath(cur_path)
 
    # root 当前目录路径  # dirs 当前路径下所有子目录  # files 当前路径下所有非目录子文件
    for root, dirs, files in os.walk(cur_path):
        for file_name in files:
            file_path = root + '/' + str(file_name)
            insert(file_path)

打开文件,逐行匹配内容

  • 打开文件调用 open;
  • 逐行获取内容用 for in;
  • fs.readLines() 是获取到所有行,作为一个”集合”;
  • get_cont 方法接收一行字符串,返回登录用户的描述信息:username 为 xx 的用户在 datetime 的时候访问了本站,详细信息在 remark 里;
def insert(file_path):
    f = open(file_path, 'r')
    for res in f.readlines():
        info = get_cont(res)
        if info is not None:
            data = info
            update_db(data)
    f.close()
 
def get_cont(res):
    mts = re.search('\{"data":([\s\S]+),"res"', res)
    info = re.search('"username":"([\w\d]+)"', res)
    date_str = re.search('^\[([\d-]+)T([\d:]+)', res)
 
    if (info is not None and mts is not None and date_str is not None):
        remark = mts.group(1)
        username = info.group(1)
        d = '{0} {1}'.format(date_str.group(1), date_str.group(2))
        return {'username': username, "remark": remark, 'datetime': d}

导入数据库

数据库新增 visitor 表,结构如下:

字段名称idusernameuvremarkupdatedTimecreatedTime
描述自增登录人的用户名该登录人访问本站的次数登录信息中的 REQ_DATA 字段最后一次访问时间首次访问时间

因为该表的设计是统计每人登录了多少次,并不是单纯的插入,所以需要多做一些处理;

每次获取到信息,先检查数据库中有没有该用户名,如果有,执行更新操作,uv+1,updatedTime 更新;如果没有,执行插入操作;

python 操作 mysql 数据库,需要先安装 MySQLdb,pip install MySQL-python 

def update_db(data):
    # 打开数据库连接
    db = MySQLdb.connect(host="localhost", port=3306, user="username", passwd="password", db="dbName", charset='utf8')
 
    # 使用cursor()方法获取操作游标
    cursor = db.cursor()
 
    has_one = False
    # SQL 查询语句
    sql = "SELECT * FROM visitor WHERE username='{0}'".format(data['username'])
    uv = 0
 
    try:
        # 执行SQL语句
        cursor.execute(sql)
        # 获取所有记录列表
        result = cursor.fetchone()
 
        if (result is not None):
            uv = result[2]
            has_one = True
    except:
        print "Error: unable to fecth data"
 
    if has_one:
        sql = "update visitor set uv='{0}', updatedtime='{1}' where username='{2}'".format(uv + 1, data['datetime'],data['username'])
    else:
        sql = "INSERT INTO visitor(username, remark, createdtime, updatedtime) VALUES ('{0}', '{1}', '{2}', '{3}')".format(
            data['username'], data['remark'], data['datetime'], data['datetime'])
 
    try:
        # 执行sql语句
        cursor.execute(sql)
        # 提交到数据库执行
        db.commit()
    except:
        # Rollback in case there is any error
        db.rollback()
 
    # 关闭数据库连接
    db.close() 

* 对比 Nodejs 操作 MySql

var mysql = require('mysql');
 
var opts = {
    "host": "localhost",
    "user": "username",
    "password": "password",
    "port": "3306",
    "database": "dbName"
};
 
var conn = mysql.createConnection(opts);
var sql = "SELECT * FROM visitor WHERE username=?";
var params = "sunchao21";
 
conn.connect();
conn.query(sql, params, function (err, result) {
    if (err) return console.log('error : ', err.message);
    console.log("success : ", result);
});
conn.end();

如果 sql 语句中有参数,通过 query 的第二个参数传递

如果这篇文章对你有用,可以点击下面的按钮告诉我

0

发表回复