免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1801 | 回复: 6

[文本处理] 急等awk处理maillog大文件 [复制链接]

论坛徽章:
1
发表于 2017-10-19 18:06 |显示全部楼层
CUer,大家好,
我现在遇到一个问题,就是awk处理3个G的文件,非常的慢,等很长时间也没有结果。机器配置挺高的。
我的例子文件只有10000行,awk很快就能检索出我的需要的数据。
但是我们生产环境的mail log都是几千万行级别的,我是每分钟需要检索数据来自于上次行号到这次末行的记录。

请大家帮我优化一下awk,如果能够实现单行perl也行,我可以嵌套到shell里面。





awk 'BEGIN {sent=0;reject=0} {
                   if (NR>'"$_last_line"' && NR<='"$_current_line"' && $0 ~ /to=.*status=sent/){sent++}
                   else if ($0 ~ /postfix.*reject:/){reject++}
                   };
                   END {printf("Sent Messages: %.1f\n" "Reject Messages: %.1f\n",sent/60,reject/60) }' /var/log/maillog





论坛徽章:
25
程序设计版块每日发帖之星
日期:2016-05-03 06:20:0015-16赛季CBA联赛之八一
日期:2018-07-05 10:34:09黑曼巴
日期:2018-07-06 15:19:5015-16赛季CBA联赛之佛山
日期:2018-08-03 13:19:3315-16赛季CBA联赛之山西
日期:2018-08-07 19:46:2315-16赛季CBA联赛之广夏
日期:2018-08-08 19:31:5015-16赛季CBA联赛之青岛
日期:2018-11-26 15:21:5015-16赛季CBA联赛之上海
日期:2018-12-11 09:45:3219周年集字徽章-年
日期:2020-04-18 23:54:5215-16赛季CBA联赛之深圳
日期:2020-04-19 21:40:19黑曼巴
日期:2022-04-03 17:55:1315-16赛季CBA联赛之八一
日期:2018-07-03 16:56:46
发表于 2017-10-19 19:13 |显示全部楼层
awk没有多少优化空间,刚才用你的代码测试了一个10M大小、10万行记录的maillog只需要1秒,建议你分割一下maillog然后再运行代码。

论坛徽章:
24
申猴
日期:2014-10-10 15:56:39射手座
日期:2014-10-10 15:57:18黑曼巴
日期:2018-05-14 11:05:122016科比退役纪念章
日期:2018-05-14 11:05:0715-16赛季CBA联赛之北控
日期:2018-05-14 11:05:0015-16赛季CBA联赛之江苏
日期:2017-02-27 18:11:0715-16赛季CBA联赛之上海
日期:2018-08-15 09:48:5415-16赛季CBA联赛之佛山
日期:2018-07-20 17:14:2315-16赛季CBA联赛之佛山
日期:2019-09-10 18:08:4615-16赛季CBA联赛之山西
日期:2020-03-26 09:40:5115-16赛季CBA联赛之佛山
日期:2020-05-08 09:03:54
发表于 2017-10-20 11:06 |显示全部楼层
本帖最后由 chengchow 于 2017-10-20 11:26 编辑

这个用tail去做,awk/sed/grep都是将文件全文读取到内存再处理,处理大文件效率非常低下,给你个我这边处理日志的脚本,自己去看
思路是,想通过tail从后往前,每次读取1000行,直到满足自己要求为止,目前监控最后2分钟日志,最多的一个项目每次读取大约50000多行,全文不低于2000W行,3G+,JAVA日志
最后对已经读取的日志做处理,目前用于生产,处理每天几个G日志关键词过滤,基本上抓取下2-3秒,全文抓取20秒以上
  1. #!/usr/bin/env python
  2. #coding:utf-8

  3. """
  4.         log_path:        日志相对路径,取gluster[*]之后路径
  5.         key_value:        日志中出现的关键词
  6.         point_of_time:        日志时间点,单位(minutes)
  7.         how_many_times:        关键词出现次数
  8. """

  9. import os
  10. import sys
  11. import time
  12. #import re

  13. ## 规范参数数量
  14. if len(sys.argv) != 5 :
  15.         print "\nUsage: " + __file__ + " %log_path% %key_value% %point_of_time% %how_many_times%"
  16.         print __doc__
  17.         sys.exit()

  18. ## 定义参数
  19. LogHome=['/data/logs/gluster1','/data/logs/gluster2','/data/logs/gluster3'] ## 集群路径,列表模式
  20. ThorldCount=0        ## 关键词出现次数初始值
  21. RowCount=1000        ## 每次过滤日志行数
  22. RowNum=200                ## 总过滤次数
  23. LogList=[]                ## 设置一个空列表给日志路径

  24. ## 读取带入参数
  25. LogFile=sys.argv[1]
  26. KeyWord=sys.argv[2]
  27. DiffMin=sys.argv[3]
  28. KeyWordCountThorld=sys.argv[4]

  29. ## 连接日志路径
  30. for i in LogHome :
  31.         if os.path.isfile(i + '/' + LogFile) :
  32.                 LogList.append(i + '/' + LogFile)

  33. if len(LogList)==0 :
  34.         print "NULL"
  35.         sys.exit(2)

  36. ## 轮询处理日志列表
  37. for log in LogList :
  38.         NowTimeStamp=int(time.time())
  39.         OldTimeStamp=int(time.time())-int(DiffMin)*60
  40.         NowTime=time.strftime('%Y-%m-%d %H:%M',time.localtime(NowTimeStamp))
  41.         OldTime=time.strftime('%Y-%m-%d %H:%M',time.localtime(OldTimeStamp))

  42. ## 以RowCount为单位找出需求时间内最短日志
  43.         for num in range(1,RowNum+1) :
  44.                 HeadTime=os.popen('tail -' + str(RowCount*num)  + ' ' + log + ' | awk -F, \'NR==1{print $1}\'').read().strip('\r\n')
  45.                 try:
  46.                         HeadTimeStamp=int(time.mktime(time.strptime(str(HeadTime),'%Y-%m-%d %H:%M:%S')))
  47.                 except:
  48.                         continue
  49.                 if HeadTimeStamp <= OldTimeStamp :
  50.                         break
  51.                 elif num==RowNum :
  52.                         break

  53. ## 找出需求时间内最早日志时间
  54.         for i in range(1,int(DiffMin)+1) :
  55.                 ReCode=os.system('tail -' + str(RowCount*num)  + ' ' + log + ' | grep -P \'' + OldTime + '\' > /dev/null 2>&1')
  56.                 if ReCode<>0 :
  57.                         OldTimeStamp+=i*60
  58.                         OldTime=time.strftime('%Y-%m-%d %H:%M',time.localtime(OldTimeStamp))
  59.                 else :
  60.                         OldTimeStamp=OldTimeStamp
  61.                         OldTime=time.strftime('%Y-%m-%d %H:%M',time.localtime(OldTimeStamp))
  62.                         break
  63. ## 获取日志中关键词出现次数并自加到ThorldCount
  64.         ThorldCount+=int(os.popen('tail -' + str(RowCount*num)  + ' ' + log + ' | sed -n "/^' + OldTime + '/,/^' + NowTime + '/p" | grep "' + KeyWord + '" | wc -l').read().strip('\r\n'))
  65.                
  66. ## 规范输出
  67. if ThorldCount<=int(KeyWordCountThorld) :
  68.         print 'OK --- 关键词: ' + KeyWord + '; 触发: ' + str(ThorldCount) + " (次); 读取日志: " + str(RowCount) + '*' + str(num) + ' (行); 开始时间: ' + str(OldTime) + '; 结束时间: ' + str(NowTime)
  69.         sys.exit(0)
  70. else :
  71.         print 'WARNING --- 关键词: ' + KeyWord + '; 触发: ' + str(ThorldCount) + " (次); 读取日志: " + str(RowCount) + '*' + str(num) + ' (行); 开始时间: ' + str(OldTime) + '; 结束时间: ' + str(NowTime)
  72.         sys.exit(2)
复制代码

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
发表于 2017-10-20 11:09 |显示全部楼层
回复 1# guobaofu

1. awk 无法解决你的问题
  没有 file seek function

2. 有file seek function 功能可以
C/C++, Perl, Python,Java,...

3. 其他方法
数据库,分割大文件,...

论坛徽章:
25
程序设计版块每日发帖之星
日期:2016-05-03 06:20:0015-16赛季CBA联赛之八一
日期:2018-07-05 10:34:09黑曼巴
日期:2018-07-06 15:19:5015-16赛季CBA联赛之佛山
日期:2018-08-03 13:19:3315-16赛季CBA联赛之山西
日期:2018-08-07 19:46:2315-16赛季CBA联赛之广夏
日期:2018-08-08 19:31:5015-16赛季CBA联赛之青岛
日期:2018-11-26 15:21:5015-16赛季CBA联赛之上海
日期:2018-12-11 09:45:3219周年集字徽章-年
日期:2020-04-18 23:54:5215-16赛季CBA联赛之深圳
日期:2020-04-19 21:40:19黑曼巴
日期:2022-04-03 17:55:1315-16赛季CBA联赛之八一
日期:2018-07-03 16:56:46
发表于 2017-10-20 11:45 |显示全部楼层
回复 1# guobaofu



用tail把maillog中的从第${_last_line}行到最后一行的记录重定向到新文件1.tmp,再用awk处理1.tmp:
  1. tail -n +${_last_line}  /var/log/maillog > 1.tmp
  2. awk 'BEGIN{sent=0;reject=0}/to=.*status=sent/{sent++}/postfix.*reject:/{reject++};END{printf("Sent Messages: %.1f\nReject Messages: %.1f\n",sent/60,reject/60)}' 1.tmp
复制代码

论坛徽章:
0
发表于 2017-10-20 12:31 |显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
1
发表于 2017-10-20 15:34 |显示全部楼层
谢谢各位大神的帮助~~
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP