日志分析
概述
生成中会生成大量的系统日志、应用程序日志、安全日志等等日志,通过对日志的分析可以了解服务器的负载、健 康状况,可以分析客户的分布情况、客户的行为,甚至基于这些分析可以做出预测。
一般采集流程 日志产出 -> 采集(Logstash、Flume、Scribe) -> 存储 -> 分析 -> 存储(数据库、NoSQL) -> 可视化
开源实时日志分析ELK平台 Logstash收集日志,并存放到ElasticSearch集群中,Kibana则从ES集群中查询数据生成图表,返回浏览器端
- 半结构化数据
日志是半结构化数据,是有组织的,有格式的数据。可以分割成行和列,就可以当做表理解和处理了,当然也可以 分析里面的数据。 - 文本分析
日志是文本文件,需要依赖文件IO、字符串操作、正则表达式等技术。
通过这些技术就能够把日志中需要的数据提取出来。
日志文件下载地址
加载日志文件,解析日志
from pathlib import Path
import re,datetime,threading
from queue import Queue
from collections import defaultdict
from user_agents import parse
from urllib.parse import urlparse
expdict = {
"datetime":lambda x:datetime.datetime.strptime(x,"%d/%b/%Y:%H:%M:%S %z"),
"length":int,
"status":int,
"useragent":lambda ua: parse(ua)
}
#解析日志
def loganalysis(file:str,encoding=None):
restr = '''^(?P<address>[\d.]{7,}) - . \[(?P<datetime>[^\]]*)\] "(?P<method>[^ ]+) (?P<url>[^ ]+) (?P<protocol>[^ ]+)" (?P<status>\d{3}) (?P<length>\d)+ "[^ ]*" "(?P<useragent>[^"]+)"'''
req = re.compile(restr)
with Path(file).open(encoding=encoding) as f:
for line in f:
regex = req.match(line)
if regex: #日志行解析成功
yield {
k:expdict.get(k,lambda x:x)(v) for k,v in regex.groupdict().items()}
else: #解析失败
raise Exception("No match. {}".format(line))
#加载日志文件
def load(*paths,ext:str="*.log",recursive:bool=False,encoding:str="utf8"):
for filepath in paths:
path = Path(filepath)
ext = [ext] if isinstance(ext,str) else list(ext)
if path.is_dir(): #是目录
for et in ext:
for f in (path.rglob if recursive else path.rglob)(et):
yield from loganalysis(f.absolute(),encoding)
else: #是文件,直接读取
yield from loganalysis(path.absolute(),encoding)
构建消息队列分发器
生产者消费者模型
一个系统的健康运行,需要监控并处理很多数据,包括日志。对其中已有数据进行采集、分析。 被监控对象就是数据的生产者producer,数据的处理程序就是数据的消费者consumer。
- 传统的生产者和消费者模型
传统的生产者消费者模型,生产者生产,消费者消费。但这种模型有些问题。 生产者和消费者代码耦合太高,代码实现上要么是生产者产生一个数据就调用消费者,要么就是消费者处理完一个 数据就调用生产者一次。如果生成规模扩大,不易扩展,生产和消费的速度很难匹配等。 - 带入消息队列的生产者和消费者模型
- 作用——解耦、缓冲。
日志生产者往往会部署好几个程序,日志产生的也很多,而消费者也会有多个程序,去提取日志分析处理
数据的生产是不稳定的!可能会造成短时间数据的“潮涌”,需要缓冲。 消费者消费能力不一样,有快有慢,消费者可以自己决定消费缓冲区中的数据。
单机时,可以使用标准库queue模块的类来构建进程内的队列,满足多个线程间的生产消费需要。 大型系统可以使用第三方消息中间件——RabbitMQ、RocketMQ、Kafka等。
数据处理所需模块—队列 - queue模块–多队列,提供了一个先进先出的队列Queue
- threading模块–线程。帮助队列不断获取数据。
为了让生产者的生产数据和消费者的消费数据同时进行,可以使用不同的线程。
数据处理流程
- 生产者(数据源)生产数据,缓冲到消息队列中
分发器的实现
数据分析的程序有很多,例如PV分析、IP分析、UserAgent分析等。
同一套数据可能要被多个分析程序并行处理:
- 需要使用多线程来并行处理
- 多个分析程序又需要同一份数据,这就是一份变多份
这是一个典型的分发器 - 注册统计分析函数,并为其提供一个单独的数据队列
- 收集日志数据
- 将一份日志数据发送到多个已注册的分析函数的队列中去
- 为了并行,每一个分析函数都在一个独立的线程中执行
######消息队列分发
def dispatchar(src):
handler = []
queueler = []
#队列注册
def reg(fun):
q = Queue()
handler.append(threading.Thread(target=fun,args=(q,)))
queueler.append(q