=Start=
缘由:
学习、提高需要
正文:
参考解答:
之前在写某个daemon程序时用的syslog()函数记录日志,时间长了之后就会产生很多日志,一个月下来的日志接近1.6G,就想着按日期切分一下,方便进行细粒度的分析和统计。之前想着用Python写个程序进行切分,但想了想好像还没那么简单,就先在网上找了其它方式的实现,后来自己也写了一个Python版本的实现,感觉还行吧(就是好久没写Python了一些语法都生疏了。。。)。
#这里 /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
&
#!/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 条评论
`
#先分别对各个文件中的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
`
滑动窗口
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)
`
日志:每个软件工程师都应该知道的有关实时数据的统一抽象
https://github.com/oldratlee/translations/blob/master/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/README.md
https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying
http://www.oschina.net/translate/log-what-every-software-engineer-should-know-about-real-time-datas-unifying
http://blog.jobbole.com/89674/
程序员史诗般必读文章
http://bryanpendleton.blogspot.hk/2014/01/the-log-epic-software-engineering.html
学习笔记:The Log(我所读过的最好的一篇分布式技术文章)
http://www.cnblogs.com/foreach-break/p/notes_about_distributed_system_and_The_log.html
优秀日志实践准则
https://mp.weixin.qq.com/s/c3dTTkbTNqnZTy_Da19I6Q
`
总结几个需要写日志的点:
编程语言提示异常:如今各类主流的编程语言都包括异常机制,业务相关的流行框架有完整的异常模块。这类捕获的异常是系统告知开发人员需要加以关注的,是质量非常高的报错。应当适当记录日志,根据实际结合业务的情况使用warn或者error级别。
业务流程预期不符:除开平台以及编程语言异常之外,项目代码中结果与期望不符时也是日志场景之一,简单来说所有流程分支都可以加入考虑。取决于开发人员判断能否容忍情形发生。常见的合适场景包括外部参数不正确,数据处理问题导致返回码不在合理范围内等等。
系统核心角色,组件关键动作:系统中核心角色触发的业务动作是需要多加关注的,是衡量系统正常运行的重要指标,建议记录INFO级别日志,比如电商系统用户从登录到下单的整个流程;微服务各服务节点交互;核心数据表增删改;核心组件运行等等,如果日志频度高或者打印量特别大,可以提炼关键点INFO记录,其余酌情考虑DEBUG级别。
系统初始化:系统或者服务的启动参数。核心模块或者组件初始化过程中往往依赖一些关键配置,根据参数不同会提供不一样的服务。务必在这里记录INFO日志,打印出参数以及启动完成态服务表述。
`
如何定义日志消息的级别?详解日志的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 发生了一个致命错误,我们要退出了。祝你好运!
`
任何成熟的日志记录 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 )