这里的解析日志指的是对日志文件进行解析,提取有用的数据;协议配置平台里边,一开始的需求并不是很明确,但我加了非常详细的日志,后续扩充功能,数据可以从日志中补全。关于协议配置平台,参照这里,第一个就是。
项目中,解析日志,是为了从日志中获取用户的访问信息,导入数据库,方便查看 / 统计访问人数,为后续优化做准备;
之前设计时,并未考虑访问相关的数据,所以这部分是没有存到数据库的,只能通过日志导入(前提是日志里存了这些数据);
日志格式
日志文件都存放在一个文件夹下,日志文件名格式为 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 表,结构如下:
字段名称 | id | username | uv | remark | updatedTime | createdTime |
---|---|---|---|---|---|---|
描述 | 自增 | 登录人的用户名 | 该登录人访问本站的次数 | 登录信息中的 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 的第二个参数传递