概述
我们日常应用中都离不开日志。可以说日志是我们在排查问题的一个重要依据。但是日志并不是写了就好了,当你想查看日志的时候,你会发现线上日志堆积的长度已经超越了你一行行浏览的耐性的极限了。于是,很有必要通过一些手段来高效地辅助你来快速的从日志中找到你要找的问题。本文通过一个从项目中衍生出来的例子从查找日志,筛选日志和统计日志3个方面层层递进来简述日志文件查看中一些有用的手段。(注:在Linux环境下)
目录
例子背景:
后台跑一个定时任务,对指定时间段的订单数据表中的每一条记录进行以此任务处理。在日志中输出:
1.订单id
2.订单处理状态
3.日志类别
准备工具:sort, tail, less, uniqu,grep,sed,awk
示例日志:demo.log
0.一些最基础的日志查看命令
最简单的日志查看命令就是浏览日志文件了,一般会从有限浏览文件末尾的
以上命令具体使用详见本机man手册
1.查找关键日志记录 grep
浏览了日志文件后你会发现,日志文件成千上万行,怎么能找到我要找的内容呢。这时候,就可已用grep来进行日志的关键行提取了。
grep 简单使用
规则:grep [选项]...模式 [文件]... (模式是正则表达式)
例子1:
输出:
2011-08-23 19:57:00,610 [] INFO bo.CommodityCerOrderBO - =====>属性订正任务执行开始|每页读取100条数据
2011-08-23 19:57:05,012 [] INFO bo.CommodityCerOrderBO - 当前正在处理页数:1
2011-08-23 19:57:30,688 [] INFO bo.CommodityCerOrderBO - order-fix.curr_id:10117,status:attr_ids不含0跳过
...(略)
例子2:
输出:例子3:
输出:17
例子4:
grep 用法小结(转自网络图片):请点击直接查看大图
详细用法请man之
2.精简日志内容 sed
从n多行的日志文件中提取到一定数量的行后,可能你还会觉得有些功能不够,比如你每行并不需要有哪个类抛出的描述,比如你不需要日志时间,或者要把时间格式换个形式展示等等,这时候你就可以通过sed的替换命令来进行对日志文件提取具体内容了。
如果把grep比作过滤器,那sed就是个修改器了。
sed简单用法:
»'命令'的格式: [地址1[,地址2]][!] 指令 [参数]
» 地址的格式:用行号标识(1 表明匹配第一行),或者用正则表达式匹配('^INFO'表明该地址匹配以INFO打头的行)
» 指令的例子:p打印指令,s替换指令,d删除指令等等(以下表格摘自abs的sed小册子):
操作符 | 名字 | 效果 |
---|---|---|
[地址范围]/p |
打印 | 打印[指定的地址范围] |
[地址范围]/d |
删除 | 删除[指定的地址范围] |
s/pattern1/pattern2/ |
替换 | 将指定行中, 将第一个匹配到的pattern1, 替换为pattern2. |
[地址范围]/s/pattern1/pattern2/ |
替换 | 在地址范围指定的每一行中, 将第一个匹配到的pattern1, 替换为pattern2. |
[地址范围]/y/pattern1/pattern2/ |
transform | 在地址范围指定的每一行中, 将pattern1中的每个匹配到pattern2的字符都使用pattern2的相应字符作替换. (等价于tr命令) |
g |
全局 | 在每个匹配的输入行中, 将每个模式匹配都作相应的操作. (译者注: 不只局限于第一个匹配) |
例1:(摘自abs的sed小册子)
8d |
删除输入的第8行. |
/^$/d |
删除所有空行. |
1,/^$/d |
从输入的开头一直删除到第1个空行(第一个空行也删除掉). |
/Jones/p |
只打印那些包含"Jones"的行(使用-n选项). |
s/Windows/Linux/ |
在每个输入行中, 将第一个出现的"Windows"实例替换为"Linux". |
s/BSOD/stability/g |
在每个输入行中, 将所有"BSOD"都替换为"stability". |
s/ *$// |
删除掉每行结尾的所有空格. |
s/00*/0/g |
将所有连续出现的0都压缩成单个的0. |
/GUI/d |
删除掉所有包含"GUI"的行. |
s/GUI//g |
将所有"GUI"都删除掉, 并保持剩余部分的完整性. |
看完基本用法,让我们结合demo.log来具体应用下:
例2:输出demo.log中的某个日期中的ERROR的行
来具体应用下:
2011-08-23 19:57:30,709 [] ERROR bo.CommodityCerOrderBO - order-fix.curr_id:10117,status:添加属性id,但由于认证分类参数有误默认取匹配属性名称的第一个属性id:100104
2011-08-23 19:57:31,721 [] ERROR bo.CommodityCerOrderBO - order-fix.curr_id:10117,status:添加属性id,但由于认证分类参数有误默认取匹配属性名称的第一个属性id:100105
2011-08-23 19:57:32,727 [] ERROR bo.CommodityCerOrderBO - order-fix.curr_id:10117,status:添加属性id,但由于认证分类参数有误默认取匹配属性名称的第一个属性id:100107
例3:提取demo.log中的日期,日志级别,订单id和状态。
输出:
2011-08-23 19:57:30@10117@INFO@status:attr_ids不含0跳过
sed详细用法可以参考《sed 与 awk》(第二版), 或者man之
或者点击下面这个参考链接http://www.reddragonfly.org/abscn/x17814.html
3.对记录进行排序 sort
经过了日志文件的精炼后,我们可能不想对日志进行时间排序,这时候我们就可以用sort进行排序。
基本使用
sort [options] [file...]
对于demo.log,经过了上面的sed提取后,我希望先用id进行排序,然后再用日志级别倒序进行排序,最后才是日期排序
输出:2011-08-23 19:57:30@10117@INFO@status:attr_ids不含0跳过
2011-08-23 19:57:32@10117@INFO@status:attr_ids成功保存为0|100104|0|100105|100107
2011-08-23 19:57:30@10117@ERROR@status:添加属性id,但由于认证分类参数有误默认取匹配属性名称的第一个属性id:100104
2011-08-23 19:57:31@10117@ERROR@status:添加属性id,但由于认证分类参数有误默认取匹配属性名称的第一个属性id:100105
2011-08-23 19:57:32@10117@ERROR@status:添加属性id,但由于认证分类参数有误默认取匹配属性名称的第一个属性id:100107
2011-08-23 19:57:36@10222@INFO@status:attr_ids不含0跳过
2011-08-23 19:57:36@10222@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100104
2011-08-23 19:57:36@10222@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100105
2011-08-23 19:57:36@10222@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100106
2011-08-23 19:57:36@10222@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100107
2011-08-23 19:57:36@10222@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:3
2011-08-23 19:57:36@10222@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:46
2011-08-23 19:57:37@10222@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:3
2011-08-23 19:57:32@10226@INFO@status:attr_ids不含0跳过
2011-08-23 19:57:36@10226@INFO@status:attr_ids成功保存为6|100104|0|0|100107|46|100106|100105|3|3
2011-08-23 19:57:32@10226@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100104
2011-08-23 19:57:33@10226@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100107
2011-08-23 19:57:33@10226@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:46
2011-08-23 19:57:34@10226@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100106
2011-08-23 19:57:35@10226@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100105
2011-08-23 19:57:36@10226@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:3
2011-08-23 19:57:36@10226@ERROR@status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:3
详尽手册http://ss64.com/bash/sort.html
4.统计日志相关记录数 awk
现在日志已经比较清晰了,但是如果我想对不同日志进行统计怎么办,比如我要统计所有ERROR的日志记录书,或者要统计每个订单有多少个ERROR?这就需要我们的awk帮忙了。
awk简单使用:
和sed一样,awk也支持2中方式调用,一种是把awk脚本直接在命令行写入,第二种是把awk写在文件中在命令行中调用。
awk处理方式也与sed类似,对文件中的每一个输入行进行处理,每个处理首先判断是否是模式中匹配的行,是的话就具体执行相应的语句。
不同的是,awk侧重与对每一行的列进行处理,并且,awk脚本和c语言类似也拥有变量,条件判断,循环等复杂语句,所以这里只能简单介绍一下基本应用,详细的请查看后面给出的相关链接。而且,awk在处理所有行前和处理完行后各有BEGIN和END语句做预处理和后置处理。
例子1:打印日志中的第2,3列
输出:(对于从sort得出的结果作为输入)例子2. 统计日志中INFO,ERROR出现的总数,以及总记录数
输出:
order total count:22
INFO count:5 ERROR count:17
例子3. 对指定时间范围内的日志进行统计,包括输出INFO,ERROR总数,记录总数,每个订单记录分类统计
下面的例子综合了前面sed和sort
输出:id:10117:
2011-08-23 19:57:32 INFO status:attr_ids成功保存为0|100104|0|100105|100107
2011-08-23 19:57:32 ERROR status:添加属性id,但由于认证分类参数有误默认取匹配属性名称的第一个属性id:100107
id:10226:
2011-08-23 19:57:32 INFO status:attr_ids不含0跳过
2011-08-23 19:57:32 ERROR status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100104
2011-08-23 19:57:33 ERROR status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100107
2011-08-23 19:57:33 ERROR status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:46
2011-08-23 19:57:34 ERROR status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100106
2011-08-23 19:57:35 ERROR status:添加属性id,但由于没有属性在该分类下默认取匹配属性名称的第一个属性id:100105
#这个例子只是举例说明awk的统计用法,实际运用中可能会统计超时的次数,页面访问次数等。
awk相关资料:
《sed 与 awk》(第二版)
补充:
其他实践时例子:
1. 在本地分支把代码修改从一个分支复制到另一个分支(例子的b1022st.txt是一个记录了文件新增或修改的变化的文件路径名)
通过awk和其system命令结合,这样就把文件从b1022-scm复制到b1022-lpscm下
2.内置函数 http://www.cnblogs.com/chengmo/archive/2010/10/08/1845913.html
3.内建变量 http://www.linuxsong.org/2010/09/awk-built-in-variable/
4.shell变量传递 http://www.51testing.com/?uid-225738-action-viewspace-itemid-246383
5.awk统计某个开始-结束范围内的关键字累加总数:
5.日志规范化
从前面可以看出,日志文件为了要让后续工具能够对里面的内容进行提取和处理,就必须要让日志文件规范的输出。
个人想到有几个点可以规范:
1.记录日志时候可以写入一些特殊的文本语句,一遍与工具的检索和处理。
2.记录日志最好不要用中文,因为在不同语言环境下对日志的处理可能因为编码不同导致没法处理日志。
后面再贴下淘宝中找到的一些打印日志的建议:
6.一些容易遇到的问题
a.处理中文出现乱码
这个主要是因为你的linux locale的配置,与编辑文件的语言环境,还有你登录ssh客户端的编码规则有关,所以最好还是不用中文记录日志。
b.正则表达式不同工具的区别
这个主要是因为不同工具的正则表达式定义的元字符不同,网上有总结的,可点击正则迷雾参考
OO后记:
目前只是简单介绍了grep,sed,sort,awk的几个简单应用,实际上的日志监控回根据不同的情景进行不同的处理。比如需要对调用的耗时进行统计(平均时间或者超时记录),对访问量进行统计,但是基本原理都和本文例子出发点一致。本文一方面是为了记录下学习过程中积累的东西,另一方面为了抛砖引玉引起大家对日志记录的关注。
文章浏览阅读1w次,点赞14次,收藏63次。2019之前的工程是SDK开发的, 在2019上没有launch sdk这个选项, 而是在tools/Vitis下1 升级工程这里要升级忽略2 report ip检查状态,然后升级 IP3 生产bit流这个过程有点久, 等待弹窗出来就OK4 Export Hardware5 tools/ launch vitis 启动vitis6 导入SDK环境选择eclips选择工程目录, 点击finish..._vivado2019没有sdk
文章浏览阅读1.2k次。项目需求是将线上服务器生成的日志信息实时导入kafka,采用agent和collector分层传输,app的数据通过thrift传给agent,agent通过avro sink将数据发给collector,collector将数据汇集后,发送给kafka,拓扑结构如下:现将调试过程中遇到的问题以及解决方法记录如下:1、 [ERROR - org.apache.thrift.server.Abstr..._ubuntu发送flume文件夹到节点一直处于发送状态
文章浏览阅读1.4k次,点赞4次,收藏26次。清洗数据是数据预处理的一个重要步骤,Pandas 提供了许多功能和方法来帮助您进行数据清洗。以下是一般情况下使用 Pandas 清洗数据的常见步骤:_数据清洗和准备(pandas)字符串操作
文章浏览阅读2k次。不到三个月,我在CSDN的第一个一万
文章浏览阅读3.2w次,点赞5次,收藏12次。在做图片语义分割的项目,对图片数据标注后,又对数据进行扩增,然后倒入图片,进行模型训练,但是读图片的时候提示如下错误。 image = cv2.cvtColor(cv2.imread(path,-1), cv2.COLOR_BGR2RGB)cv2.error: OpenCV(3.4.3) /io/opencv/modules/imgproc/src/color.hpp:255: err..._> invalid number of channels in input image: > 'vscn::contains(scn)' > where
文章浏览阅读1.4k次。Dedecms5.7数据结构说明文档1、dede_addonarticle:附加文章表 表名:dede_addonarticle(ENGINE=MyISAM/CHARSET=utf8)说明:附加文章表 字段名说明描述具体参数aid文章ID_数据结构说明文件
文章浏览阅读80次。在centos上安装JDK,我安装的是JDK11。 查看centos上是否已经安装了JAVA: rpm -qa | grep java 如果已经安装了java,就卸载掉: rpm -e --nodeps 包名 接下来下载jdk包,下载地址:https://www.oracle.com/java/technologies/javase-jdk11-downloads.html 解压jdk: # 找到文件存放的目录,我的目录是/u...
文章浏览阅读3w次,点赞13次,收藏42次。本文总结了几种常用的MFC字符串分割的方法,以方便自己以后查阅,也希望能帮助到有需要帮助的人。1、CString 自带的函数Tokenize1CStringT Tokenize( _In_ PCXSTR pszTokens, _Inout_ int& iStart ) const_cstring分割字符串cstringarray存储
文章浏览阅读1.9k次,点赞2次,收藏5次。第一期1.雨中龙猫考查base64编码和图片源码隐写题目给出答案格式whalectf{xxx},将whalectf进行base64编码:d2hhbGVjdGY=notepad++打开源码搜索,发现并不能搜索到因为base64编码过程会重新以6位分组,所以whalectf后面的字母可能会对whalectf的编码影响,所以搜索前几位d2hhbGVj得到d2hhbGVjdGZ7TG进行解..._00000000.png ctf
文章浏览阅读4.1k次。在python中处理字符串中的空格和换行符 string中提供了很多方法处理字符串,有空格和换行符往往影响我们观看文本,下面介绍一种处理方法。 一、去除空格 strip() " xyz ".strip() # returns "xyz" " xyz ".lstrip()_python 解析带换行符的字符串
文章浏览阅读5.0k次,点赞2次,收藏18次。EasyMock是Apache许可下发布的Java开源测试框架,它可以和jUnit很好的继承在一起。该框架允许为测试驱动开发(TDD)或行为驱动开发(BDD)创建测试双重对象1。使用EasyMock只需导入相应的jar包即可,本篇用到的所有jar包和代码都可以在我的Github下载。 在这里我们用一个进行用户验证的servlet代码作为被测代码,这段代码来自我之前看过的一篇EasyMock教程2_使用easymock+junit对附件中的loginservlet进行测试:
文章浏览阅读81次。最近做了vue的一个项目,效果要实现多选及反选,数据是从后端传过来的。代码:<div class="lableView"> <label class="lable_one" :class="{active:sz.includes(index)}" v-for="(item,index) in lableList" :key="index"._es6 inclduse