常见日志
如果实际运行一下log_recent()函数的话,你就会发现,尽管log_recent()函数非常适用于记录当前发生的事情,但它并不擅长告诉你哪些消息时重要的,哪些消息是不重要的。为了解决这个问题,我们可以让程序记录特定消息出现的频率,并根据出现频率的高低来决定消息的排列顺序,从而帮助我们找出最重要的消息。
下面代码的log_comon()函数展示了记录并轮询最常见日志消息的方法:程序会将消息作为成员存储的有序集合里面,并将消息出现的频率设置为成员的分值。为了确保我们看见的常见消息都是最新的,程序会以每小时一次的频率对消息进行轮换,并在轮换日志的时候保留上一个小时记录的常见消息,从而防止没有任何消息存在的情况出现。
def log_common(conn,name,message,severity=logging.INFO,timeout=5):
# 尝试将日志的安全级别准还为简单的字符串
severity = str(SEVERITY.get(severity, severity)).lower()
#负责存储近期的常见日志消息的键
destination = 'common:%s:%s' % (name, severity)
#因为程序每小时需要轮换一次日志,所以它使用一个键来记录当前所处的小时数
start_key=destination+':start'
# 使用流水线来将通信往返次数降低为一次
pipe = conn.pipeline()
end=time.time()+timeout
while time.time()<end:
try:
#当记录当前小时数的键进行监视,确保轮换操作可以正确的执行
pipe.watch(start_key)
#取得当前时间
now=datetime.utcnow().timetuple()
#取得当前所处的小时数
hour_start=datetime(*now[:4].isoformat())
existing=pipe.get(start_key)
#创建一个事务
pipe.multi()
#如果这个常见日志消息列表记录的是上个小时的日志。。
if existing and existing<hour_start:
#将这些旧的常见日志消息归档
pipe.rename(destination,destination+':last')
pipe.rename(start_key,destination+':pstart')
#更新当前所处的小时数
pipe.set(start_key,hour_start)
elif not existing:
pipe.set(start_key,hour_start)
#对记录日志出现次数的计数器执行自增操作
pipe.zincrby(destination,message)
#log_recent()函数负责记录日志并调用execute()函数
log_recent(pipe,name,message,severity,pipe)
return
except redis.exceptions.WatchError:
continue
因为记录常见日志的函数需要小心地处理上一小时收集的日志,所以它比记录最新日志的函数要复杂的多:程序会在一个watch/multi/exec事务里面,对记录了上一小时的常见日志的有序集合进行改名,并对记录了当前所处小时数的键进行更新。除此之外,程序还会降流水线对象传递给log_recent()函数,以此来减少记录常见日志和记录最新日志时,客户端与Redis服务器之间的通信往返次数。
通过最新日志和常见日志,我们现在已经知道怎样将系统的运行信息存储到Redis里面了,那么还有什么其他信息是适合存储在Redis里面的呢?