Linux下如何根据日期切分日志文件?


=Start=

缘由:

学习、提高需要

正文:

参考解答:

之前在写某个daemon程序时用的syslog()函数记录日志,时间长了之后就会产生很多日志,一个月下来的日志接近1.6G,就想着按日期切分一下,方便进行细粒度的分析和统计。之前想着用Python写个程序进行切分,但想了想好像还没那么简单,就先在网上找了其它方式的实现,后来自己也写了一个Python版本的实现,感觉还行吧(就是好久没写Python了一些语法都生疏了。。。)。

用awk按日期切分syslog日志
#这里 /var/log/monitor.log 日志的格式就是常规的 syslog 日志格式,即:
#Jul 25 10:56:33 sec-test monitor: EXEC:[pid=21546, path=/bin/cat, mode=100755, cmdline=cat /var/log/monitor.log, uid=0, euid=0, gid=0, egid=0, sid=17074, owner_uid=0, owner_gid=0, file_mtime=1394622735]
 
awk 'BEGIN {
    split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ", months, " ")
    for (a = 1; a <= 12; a++)
        m[months[a]] = a
}
{
    year = 2017
    month = sprintf("%02d", m[$1])
    day = sprintf("%02d", $2)
 
    print > FILENAME"-"year""month""day
}' /var/log/monitor.log

&

用Python按日期切分syslog日志
#!/usr/bin/env python
# coding=utf-8

import sys, time

day_dict = {}
month_dict = {
	'Jan': 1,
	'Feb': 2,
	'Mar': 3,
	'Apr': 4,
	'May': 5,
	'Jun': 6,
	'Jul': 7,
	'Aug': 8,
	'Sep': 9,
	'Oct': 10,
	'Nov': 11,
	'Dec': 12,
}

# msg_size = 10*1024*1024    # 10MB
msg_write = 0

def main():
    # for k in month_dict:
    #     print '{0}({1})\t{2:02d}({3})'.format(k, type(k), month_dict[k], type(month_dict[k]))

    if len(sys.argv) < 2:
        print 'Usage:\n\t{0} filename\n'.format(sys.argv[0])
        sys.exit(0)
    file = sys.argv[1]
    with open(file) as fp:
        msg_size = 0
        for line in fp:
            line = line.strip()
            if line:
                month, day, _ = line.split(' ', 2)
                if line[:6] in day_dict:
                    day_dict[line[:6]].append(line)
                    msg_size += len(line)
                    if msg_size >= 10*1024*1024:
                        # print type(month_dict[month]), type(day); sys.exit(0)
                        with open('{0}-{1:02d}{2}'.format(file, month_dict[month], day.zfill(2)), 'ab') as fp_w:
                            fp_w.write('\n'.join(day_dict[line[:6]]))
                        print 'write {0} bytes to {1}.\n'.format(msg_size, '{0}-{1:02d}{2}'.format(file, month_dict[month], day.zfill(2)))
                        day_dict[line[:6]] = []
                        msg_size = 0
                else:
                    day_dict[line[:6]] = [line, ]
        for key in day_dict:
            print key
            # print '"{0}", "{1}"'.format(key[:3], key.split(' ', 1)[1].zfill(2))
            # print type(key[:3]), type(key.split()[-1]); sys.exit(0)
            with open('{0}-{1:02d}{2}'.format(file, month_dict[key[:3]], key.split()[-1].zfill(2)), 'ab') as fp_w:
                fp_w.write('\n'.join(day_dict[key]))

if __name__ == '__main__':
    time_start = time.time()
    try:
        main()
    except KeyboardInterrupt:
        print 'Killed by user'
        sys.exit(0)
    print "Spend {0} seconds.\n".format(time.time() - time_start)

 

参考链接:

https://stackoverflow.com/questions/11687054/split-access-log-file-by-dates-using-command-line-tools #根据日期切分access.log文件
https://stackoverflow.com/questions/11713978/how-to-split-existing-apache-logfile-by-month #根据月份切分access.log文件
https://unix.stackexchange.com/questions/274314/split-large-log-file-into-pieces-based-on-date
https://askubuntu.com/questions/826907/split-log-file-by-date

https://superuser.com/questions/439688/how-to-grep-a-log-file-within-a-specific-time-period
https://serverfault.com/questions/101744/fast-extraction-of-a-time-range-from-syslog-logfile #Python代码未测试

=END=

, , ,

《 “Linux下如何根据日期切分日志文件?” 》 有 7 条评论

  1. `
    #先分别对各个文件中的IP/某个字段进行去重、计数,并将结果都存入同一个文件
    files=$(find /var/log/nginx/ -type f -iname “*access.log*” | xargs ls)
    for xfile in $files; do
    # echo $xfile
    if [[ $xfile == *”.gz” ]]; then
    echo “#”$xfile | tee -a access.log.${HOSTNAME}
    zcat $xfile | awk ‘{print $6}’ | sort | uniq -c >> access.log.${HOSTNAME}
    else
    echo “#”$xfile | tee -a access.log.${HOSTNAME}
    cat $xfile | awk ‘{print $6}’ | sort | uniq -c >> access.log.${HOSTNAME}
    fi
    done

    #然后对刚才的结果文件用awk进行进一步去重计数
    awk ‘{dict[$2]+=$1} END{for (item in dict) print dict[item]”\t”item}’ ./access.log.${HOSTNAME} | sort -nr >${HOSTNAME}.visitor_ip.txt
    `

  2. 滑动窗口
    http://www.178linux.com/88218
    `
    import random
    import datetime
    import time

    # 数据源函数
    def f():
    while True:
    yield {‘value’:random.randrange(100), ‘time’:datetime.datetime.now()}
    time.sleep(5)

    def window(src, handler, width:int, interval:int):
    “””
    窗口函数
    :param src: 数据源,生成器,用来拿数据
    :param handler: 数据处理函数
    :param width: 时间窗口宽度,秒
    :param interval: 处理时间间隔,秒
    “””

    # 初始两个时间段
    start = datetime.datetime.strptime(‘20170101 00:00:00’, ‘%Y%m%d %H:%M:%S’)
    current = datetime.datetime.strptime(‘20170101 00:01:00’, ‘%Y%m%d %H:%M:%S’)

    buffer = [] # 窗口中待计算的数据
    delta = datetime.timedelta(seconds = width – interval)

    while True:
    # 从数据源获取数据
    data = next(src)

    # 存入临时缓冲等待计算
    if data: # 筛掉不符合的数据
    buffer.append(data)
    current = data[‘time’]

    # 进入循环开始操作
    if (current – start).total_seconds() >= interval:
    ret = handler(buffer)
    print(‘{:.2f}’.format(ret))
    start = current

    # 处理重叠的数据
    buffer = [x for x in buffer if x[‘time’] > current – delta]

    def handler(iterable):
    vals = [x[‘value’] for x in iterable]
    return sum(vals) / len(vals)
    `

  3. 优秀日志实践准则
    https://mp.weixin.qq.com/s/c3dTTkbTNqnZTy_Da19I6Q
    `
    总结几个需要写日志的点:

    编程语言提示异常:如今各类主流的编程语言都包括异常机制,业务相关的流行框架有完整的异常模块。这类捕获的异常是系统告知开发人员需要加以关注的,是质量非常高的报错。应当适当记录日志,根据实际结合业务的情况使用warn或者error级别。

    业务流程预期不符:除开平台以及编程语言异常之外,项目代码中结果与期望不符时也是日志场景之一,简单来说所有流程分支都可以加入考虑。取决于开发人员判断能否容忍情形发生。常见的合适场景包括外部参数不正确,数据处理问题导致返回码不在合理范围内等等。

    系统核心角色,组件关键动作:系统中核心角色触发的业务动作是需要多加关注的,是衡量系统正常运行的重要指标,建议记录INFO级别日志,比如电商系统用户从登录到下单的整个流程;微服务各服务节点交互;核心数据表增删改;核心组件运行等等,如果日志频度高或者打印量特别大,可以提炼关键点INFO记录,其余酌情考虑DEBUG级别。

    系统初始化:系统或者服务的启动参数。核心模块或者组件初始化过程中往往依赖一些关键配置,根据参数不同会提供不一样的服务。务必在这里记录INFO日志,打印出参数以及启动完成态服务表述。
    `

  4. 如何定义日志消息的级别?详解日志的5个级别
    https://mp.weixin.qq.com/s/StyWwiXkpo1Z_t5_Av_kdw
    https://www.aib42.net/article/five-levels-of-logging
    `
    Error 错误已经发生了,这是毫无疑问的。错误的来源可能是在外部,但不管怎样都需要看一下是怎么回事。可以用这个级别来表示需要引起人们注意(大多数时候需要采取行动)的错误。大多数难以优雅处理的异常都属于 Error 范畴。
    Warn 错误有可能已经发生了。我只是一条日志消息,无法分析到底发生了什么,或许需要其他人来看看是不是有问题。
    Info 通知用户一个操作或状态发生了变化。别紧张,继续手头的活。
    Debug 如果你能读懂这个级别的日志,那么你离程序已经很近了。这就是为什么你需要保存日志文件,在修复 bug 时需要这些日志。这是开发人员最关心的内容。
    Trace Trace 的信息是更加具体的调试信息,你可能并不想看到它(除非你向保存日志的人卖硬盘的时候需要)。它会包含比如说调用了什么函数(函数名),或是和客户端交换了什么网络包等内容。它善于找到一些低级错误,但通常你可以在调试消息中缩小范围,找到问题。
    Fatal 发生了一个致命错误,我们要退出了。祝你好运!
    `

  5. 任何成熟的日志记录 API 或库都应该有自己的日志级别(可能支持用户自定义)。以下是广泛使用的库,仅供参考:
    Linux 的 printk( https://en.wikipedia.org/wiki/Printk#Logging_Levels
    Python 的 logging( https://docs.python.org/library/logging.html#logging-levels
    Java 的 java.util.logging.Level( https://docs.oracle.com/javase/6/docs/api/java/util/logging/Level.html
    log4j 的 org.apache.log4j.Level( https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Level.html
    JavaScript 的 console.level 调用( WHATWG 或 Node.js 的 Console API 规范 )
    NLog 的日志级别( https://github.com/nlog/nlog/wiki/Log-levels

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注