关于日志的那些事儿

日志的作用

1.审计

  • 商业分析:比如从日志中提取用户行为(比如,一个点击事件流)并结合用户的其他详情(比如,最终购买行为)来生成报告或者推荐相关产品。
  • 接口调用情况统计:调用量、调用成功率、平均响应时间
  • 软件使用情况统计

2.诊断

  • 根据日志的错误信息的上下文定位和追踪问题
  • 根据相关日志信息了解软件的运行状态
  • ...

3.监控告警

在运维中,经常需要实时监控日志内容,根据某种策略来判断是否发出邮件告警,通知相关人员及时处理。读取日志的时间间隔可以根据实际情况来设定,可以1分钟、或者5分钟。

告警策略:

  • 基于关键字告警: 出现某些关键字,如SQLException,则发出邮件告警。
  • 基于统计告警:比如统计接口的成功率,低于某个值则告警;复杂一点的比如某个接口出现次数大于多少,成功率低于多少则告警;又如接口平均响应时间大于多少则告警。

实时读取日志的三种方法:

  • 增量读取:每次读取日志把文件的大小保存下来,下一次从一次的记录的位置开始读取。
  • 根据日志的时间读取,比如只读取最近两分钟的内容。这用方法不用记录读取的位置,日志文件不大时候,可采用这种方法,如果日志文件很大则此方法不适合。
  • 使用类似watchdog的库实时监控日志的变化,日志一用增加则读取增加部分,这种方法实时性较高。

碎碎念

  • 程序未动,log先行: 编程一开始就把日志打印纳入开发计划,打印日志是软件开发不可或缺的一部分,一开始就要规划好。
  • 克制,勿让无用信息干扰有用信息:比如在一个会循环很多次的for循环里面,我们需要打印日志但又不想每次都打印,可以每100次打印一次,每1000次打印一次,打印频率具体情况具体分析。
  • 另一种打印日志的方式:使用nohup启动程序,比如使用nohup启动Python脚本,代码中使用print打印的内容会被重定向到nohup.out文件中,省去了配置logging参数的麻烦。简单的脚本中可采用这种方法。
  • 在Python中使用logging.error(e, exc_info=True)打印异常信息, 而不是logging.error(e), logging.error(e)不会打印异常上下文;还可以使用logging.exception(e), 这种方法也会打印上下文。
  • ...

使用Python统计大日志的技巧

  • Python和shell命令结合 Python语言简单,功能强大,适合数据统计。有些shell命令过滤文本的效率很高,使用也很简单,比如grep。可以把Python的统计能力和shell命令高效过滤结合在一下提高统计大日志的效率

  • 采用多进程 如果有很多日志文件要统计,可以采用多进程和shell结合,每个进程统计一个日志,最后再把各进程统计出来的结果汇总起来。这里是不是有一点MapReduce的味道。

下面给出一个Demo的代码框架:

# -*- coding: utf-8 -*-

import os
from glob import glob
from functools import reduce
from multiprocessing import Pool

LOG_PATH = '/applogs/face*/log.*'


def get_all_logs():
    return glob(LOG_PATH)


def processing_fun(log_path):
    result = {}
    cmd = 'grep userid {file}'.format(file=log_path)
    
    r = os.popen(cmd)  # Python 调用grep命令过滤日志
    text = r.read()  # 获取过滤后的日志内容
    
    # do something  # 统计日志

    return result


def reduce_fun(x, y):
    # 合并统计结果
    
    ret = {}
    
    # do something
    
    return ret


def main():
    all_logs = get_all_logs()
    pool = Pool(processes=4)
    map_result = pool.map_async(func=processing_fun, iterable=all_logs)
    pool.close()
    pool.join()

    data = map_result.get()
    result = reduce(reduce_fun, data)  # 最终的统计结果

    print(result)


if __name__ == '__main__':
    main()

你可能感兴趣的:(Python)