看了这篇文章,比同事更快找到bug!

时间:2020-08-11 09:24:28   收藏:0   阅读:79
这是本公众号的第 6 篇原创文章

你以为程序员只是闷着头疯狂写bug,写好了发布到服务器就完了?

不,你还要修bug!但在那之前,你还要找bug!

技术图片

那么问题来了,程序都部署都服务器了,怎么找bug呢?下面给大家介绍几种方法,帮助你轻松找到程序的bug。

日志篇

在上篇文章中,笔者介绍了《在Java代码中打日志需要注意什么?》。打日志是非常重要的,因为日志能够提供一些运行时的信息,非常有助于我们快速定位问题。

那么怎么通过日志去分析问题呢?我们首先从单机服务器说起,因为有时候可能bug是测试发现的,而测试环境一般机器都比较少,可能不会专门搭建ELK等日志收集器,所以可能是要到服务器上去看日志。

统一日志配置标准

这个其实是非常重要的,因为我们首先要找到日志文件的路径,才能找到日志进行分析。尤其在一个大点的团队,服务非常多,比较忌讳每个服务的日志文件路径乱放,找半天找不到日志放在哪。

技术图片
所以建议团队有一个统一的日志配置标准。不论是格式、路径、保存日期和清理策略等,最好都保持一致,并写进团队的建设文档里,这样开发人员才能够快速地找到自己想要的日志。

分析日志常用命令
现在服务端大多部署在Linux服务器上,所以这里介绍一些在Linux上常用的分析日志的命令。

tail
tail命令是笔者最常用的命令。我们知道,日志文件大多都是追加的方式进行的。所以最新发生的问题一般都是在日志文件的末尾。tail命令可以打印出日志倒数第n行的日志,还可以通过-f参数来实时追踪。

# 打印x.log的末尾1000行日志,默认是10
tail x.log -n1000;

# 打印x.log末尾10行日志,并继续打印出后面新增的日志
tail x.log -f

# 这个跟上面是等价的
tailf x.log

cat + grep

上面介绍的tail命令,可以输出文件的末尾n行。但有时候我们发现问题时已经有点晚了,这个时候可以在整个日志文件里面找。

通过cat命令,可以打印出整个日志文件的内容。但整个日志文件内容太多了,所以我们通常需要通过管道加上grep来结合,只提取我们需要的信息。

cat x.log | grep ‘xxx‘

这里grep的内容“xxx”,通常建议以下值:

当然了,这里的管道和grep,也可以和上面的tail命令相结合。另外,如果grep出来的内容比较多,后续还想分析,管道还可以将输出流输出到一个文件里,比如:

cat x.log | grep ‘xxx‘ > temp.log

输出到一个单独的文件里了,我们就能够对它进行下一步分析了,比如发生这个异常的数据有多少条,提取里面的关键信息。还可以通过sed命令来做。

比如:

# 打印temp.log
$ cat temp.log
error data: 124
error data: 121j
error data: 124fdsfsd

# 用正则提取里面的id
$ cat temp.log | sed -r "s/error data: (.*)/\1/g"
124
121j
124fdsfsd

vi

cat + grep虽然好,但是不是很方便查看异常周围的日志。比如我们想查看完整的日常堆栈,可以通过vi的搜索功能来做。

vi是在Linux平台上常用的文本编辑器,功能非常强大。当然,很多朋友更习惯用功能更强的vim,用法是类似的。今天要介绍的是它的一些常用的搜索功能和跳转功能。

# 从前到后搜索
/searchKey
# 从后到前搜索
?SearchKey
# 定位光标到下一个搜索的地方
快捷键n
# 定位到光标上一个搜索的地方
快捷键N
# 设置显示行号
:set nu

以上差不多能够在服务器上定位和分析日志了。如果你的服务器是分布式的,部署在很多台机器上,比如UAT环境和生产环境,那其实不建议再去服务器上手动分析日志,而是用成熟的日志框架去收集和分析日志。

比较常用的开源日志收集框架是ELK、Splunk等,它们都提供了web界面和丰富的查询语句支持。

远程Debug篇

现在JVM支持远程调试。其原理是因为Java是跨平台的,只要远程的字节码文件和本地的字节码文件相同,两个JVM可以通过调试协议进行通信。

技术图片

?
所以这里需要保证本地和服务端的代码要一致,不然可能导致某个端点无法进入。尤其使用分支开发的同学需要注意分支是否一致
?

IDEA上有一个非常好用的远程Debug工具,下面简单介绍一下如何在IDEA上如何Debug。首先通过Run -> EditConfigurations进去,然后添加一个Remote。

然后配置一下host和端口就行了,这里需要注意的是端口是服务器上面的新端口,不要与服务本身的web端口冲突了,可以在应用启动时传入下图中的JVM参数指定端口和远程debug配置。

技术图片
remote debug

创建好以后,在IDEA打开你的远程debug,就可以愉快地Debug了。

?
不推荐在生产环境使用远程Debug
?

神器Arthas

Arthas是阿里开源的一款Java诊断工具,功能非常强大。官网上有一个在线的交互式教程,几分钟入门,非常方便。支持命令的自动补全、历史命令补全,管道等。这里介绍它的一些常用的功能。

Dashboard
Arthas的dashboard命令可以显示当前系统和JVM的实时状态。包括线程的状态、JVM的状态。

技术图片
dashboard

查看线程

通过thread 1可以打印「线程id」为1的栈。而且Arthas也支持管道,可以对输出通过管道进行grep:

[arthas@37]$ thread 1
"main" Id=1 TIMED_WAITING
    at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:340)
    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
    at demo.MathGame.main(MathGame.java:17)

Affect(row-cnt:0) cost in 9 ms.
[arthas@37]$ thread 1 | grep main(
    at demo.MathGame.main(MathGame.java:17)

查看方法的运行时信息

通过watch命令可以查看方法的运行时参数/返回值/异常信息。

[arthas@37]$ watch demo.MathGame primeFactors returnObj
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 40 ms.
ts=2020-05-10 02:53:46; [cost=1.129697ms] result=null
ts=2020-05-10 02:53:47; [cost=0.056254ms] result=null
ts=2020-05-10 02:53:48; [cost=0.056249ms] result=null
ts=2020-05-10 02:53:49; [cost=0.210126ms] result=@ArrayList[
    @Integer[2],
    @Integer[3],
    @Integer[5],
    @Integer[1039],
]
ts=2020-05-10 02:53:50; [cost=0.204834ms] result=@ArrayList[
    @Integer[3],
    @Integer[3],
    @Integer[3],
    @Integer[7],
    @Integer[839],
]

动态执行代码

这是我觉得Arthas里最强大的一个功能了!使用ognl命令可以让你的应用代码执行执行任意方法,用你制定的任何参数!比如:

[arthas@37]$ ognl ‘@java.lang.System@out.println("hello ognl")‘

这个时候,你的应用代码会输出“hello ognl”。

Arthas还有很多非常强大的功能,它甚至可以热更新代码,就是动态替换你想替换的某个类!

当然,笔者觉得Arthas的命令强大归强大,使用起来还是有一些复杂的,毕竟是一个基于命令行的程序。IDEA有一个arthas idea插件,可以生成arthas命令,有兴趣的同学可以试试~

技术图片
arthas idea

以上就是关于如何更快更方便地找bug的介绍。早一秒找到bug,就早一秒挽救损失,说不定就能升职加薪哦~

关于作者
微信公众号:编了个程(blgcheng)
个人网站:https://yasinshaw.com
笔名Yasin,一个有深度,有态度,有温度的程序员。工作之余分享编程技术和生活,如果喜欢我的文章,可以顺手关注一下公众号,也欢迎转发分享给你的朋友~
技术图片

推荐阅读

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!