Arthas
是一个 Java 诊断工具,它可以帮助你监控和诊断 Java 应用在运行时的各种问题。如果你想使用 Arthas 来监控方法的入参,你可以使用 trace
命令来追踪方法的调用路径,并查看入参值。
以下是如何使用 Arthas 的 trace
命令来监控方法的入参:
- 启动 Arthas:
首先,你需要启动 Arthas 并连接到你的 Java 应用。你可以使用as.sh
或as.bat
脚本来启动 Arthas,并连接到你的应用。 - 使用 trace 命令:
使用trace
命令来追踪特定方法的调用。例如,如果你想追踪com.example.MyClass.myMethod
的调用,你可以执行:
trace com.example.MyClass myMethod
这会开始追踪 myMethod
的调用,并显示调用路径和入参值。
\3. 查看输出:
Arthas 会显示追踪到的调用路径和入参值。你可以根据这些信息来分析方法的调用和参数传递。
\4. 停止 trace:
当你完成追踪后,可以使用 stop
命令来停止追踪。
注意:使用 trace
命令可能会对应用的性能产生影响,因为它需要插入字节码来追踪方法的调用。因此,在生产环境中使用时需要谨慎,并确保只在需要时使用。
此外,Arthas 还提供了其他许多有用的命令和功能,如查看线程堆栈、查看实例引用等。你可以根据需要探索和使用这些功能。
Arthas 并连接到你的 Java 应用
要连接Arthas到你的Java应用,你需要确保Arthas的agent已经附加到你的Java进程上。这通常通过启动Arthas客户端,并提供Java进程的ID (PID) 来实现。以下是如何使用Arthas并连接到Java应用的步骤:
- 启动Java应用:
首先,确保你的Java应用正在运行。你可以通过运行jps
命令(如果你的Java环境变量配置正确的话)来查看正在运行的Java进程和它们的PID。
jps
这将列出所有Java进程及其PID。
- 启动Arthas:
使用Arthas的启动脚本arthas-boot.sh
(Linux/Unix)或arthas-boot.bat
(Windows)来启动Arthas。这个脚本会提示你输入Java进程的PID。
在Linux/Unix上,可以运行:
bash./arthas-boot.sh
在Windows上,可以运行:
batarthas-boot.bat
- 连接到Java进程:
当Arthas启动脚本运行时,它会列出所有可用的Java进程及其PID。你需要输入你想要连接的Java进程的PID。
* [1]: 12345 com.example.MyApplication
假设你想连接到PID为12345
的进程,输入1
并按回车。
- Arthas命令行界面:
成功连接后,你将看到Arthas的命令行界面(CLI),并可以开始输入Arthas命令来监控和诊断你的Java应用。
welcome to arthas!version: 3.x.xpid: 12345time: 2023-04-01 10:00:00
现在你可以使用各种Arthas命令来监控你的Java应用,例如trace
、watch
、stack
等。
请注意,Arthas需要在Java应用启动时加入-javaagent
参数来启动agent,或者你可以在Java应用运行后使用java -jar arthas-client.jar [your-java-pid]
来连接。如果你没有权限重启Java应用或者无法加入-javaagent
参数,你可能需要联系你的运维团队或者使用其他方式来监控你的应用。
cat catlina.out | grep '====>abc'weaver-component-web 在 10.12.12.98 上才可以
ps -ef | grep java
ps -ef |grep 'component-web'weaver-customer-service 在 10.12.12.124 机器上才可以
ps -ef |grep 'customer-service'
sudo /usr/local/jdk8/bin/java -jar /opt/arthas/arthas-boot.jar 712226
arth sudo su root // 切换为管理员权限
sudo /usr/weaver/jdk/bin/java -jar /opt/arthas-boot.jar 16771watch org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker doInvoke
'{
params,@com.weaver.framework.rpc.context.impl.TenantRpcContext@getTenantKey(),
@com.weaver.common.cas.context.WeaverCasInfoContext@getTenantKey(),
@com.weaver.framework.rpc.context.impl.TenantRpcContext@getFrameworkTenantKey(),
returnObj,throwExp
}'
'params[0].getTargetServiceUniqueName().contains("dubbo接口全路径")¶ms[0].getMethodName().equals("方法名称")' -b -n 5 -x 3 watch org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker,doInvoke
'{
params,
@com.weaver.framework.rpc.context.impl.TenantRpcContext@getTenantKey(),
@com.weaver.common.cas.context.WeaverCasInfoContext@getTenantKey(),
@com.weaver.framework.rpc.context.impl.TenantRpcContext@getFrameworkTenantKey()
,returnObj
,throwExp
}''params[0].getTargetServiceUniqueName().contains("com.weaver.ebuilder.form.client.service.emobile.IEtFormDatasetService")&¶ms[0].getMethodName().equals("getFields")' -b -n 5 -x com.weaver.customerservice.component.share.utils.RpcUtil,invoke '{params,returnObj}' 'params[0].getMethodName().contains("employeeLimit")'
如果您想要使用 ps -ef
结合 grep java
来只输出Java进程的PID和类名信息,您可以使用 awk
命令来提取这些信息。以下是一个例子:
ps -ef | grep java | grep -v grep | awk '{print $2, $NF}'
这里的命令做了以下几件事:
ps -ef
:列出所有进程。grep java
:从所有进程中筛选出包含“java”的行。grep -v grep
:排除掉包含“grep”的行,这是因为我们不想看到grep java
本身的进程。awk '{print $2, $NF}'
:使用awk
命令来打印每行的第二个字段(通常是PID)和最后一个字段(通常是Java类名或命令行的最后一部分)。
这样,您将会得到每个Java进程的PID和类名(或命令行最后的部分)。请注意,如果Java类名包含空格或特殊字符,这可能会导致输出不准确。此外,如果Java进程是以不同的方式启动的(例如,使用不同的JVM参数或脚本),那么$NF
可能不会总是包含类名。
如果您确实想要提取类名,并且类名是在命令行参数中的最后一个,那么上面的命令应该可以工作。但是,如果您需要更精确的控制或更复杂的解析,您可能需要使用更强大的文本处理工具,如perl
或python
,或者考虑使用jps
命令,它专门为Java进程设计,可以更准确地显示Java类名。
[d]{}
如果您想要使用 ps -ef
结合 grep java
来只输出Java进程的PID和类名信息,您可以使用 awk
命令来提取这些信息。以下是一个例子:
ps -ef | grep java | grep -v grep | awk '{print $2, $NF}'
这里的命令做了以下几件事:
ps -ef
:列出所有进程。grep java
:从所有进程中筛选出包含“java”的行。grep -v grep
:排除掉包含“grep”的行,这是因为我们不想看到grep java
本身的进程。awk '{print $2, $NF}'
:使用awk
命令来打印每行的第二个字段(通常是PID)和最后一个字段(通常是Java类名或命令行的最后一部分)。
这样,您将会得到每个Java进程的PID和类名(或命令行最后的部分)。请注意,如果Java类名包含空格或特殊字符,这可能会导致输出不准确。此外,如果Java进程是以不同的方式启动的(例如,使用不同的JVM参数或脚本),那么$NF
可能不会总是包含类名。
如果您确实想要提取类名,并且类名是在命令行参数中的最后一个,那么上面的命令应该可以工作。但是,如果您需要更精确的控制或更复杂的解析,您可能需要使用更强大的文本处理工具,如perl
或python
,或者考虑使用jps
命令,它专门为Java进程设计,可以更准确地显示Java类名。
要搜索指定类名的 Java 进程的 PID,您可以使用 pgrep
结合 jps
或者 ps
命令。但是,请注意,pgrep
本身不能直接搜索类名,因为它只搜索命令行参数。相反,jps
命令可以直接显示 Java 进程的类名。
如果您知道完整的类名(包括包名),您可以使用 jps
命令来查找特定的类名,并获取其 PID。例如,要查找名为 com.example.MyClass
的类名的 Java 进程的 PID,您可以这样做:
jps -l | grep 'com.example.MyClass'
这里 -l
参数让 jps
输出主类的完整包名或类名。grep
命令则用来过滤出包含 com.example.MyClass
的行。
如果您必须使用 ps
命令和 grep
来实现,并且知道类名的一部分或者确切的命令行参数,您可以尝试:
ps -ef | grep java | grep 'com.example.MyClass' | grep -v grep | awk '{print $2}'
在这个命令中:
ps -ef
列出所有进程。grep java
筛选出包含 “java” 的行。grep 'com.example.MyClass'
筛选出包含指定类名的行。grep -v grep
排除掉包含 “grep” 的行,即排除掉grep
命令自身的进程。awk '{print $2}'
打印每行的第二个字段,即 PID。
pgrep -f java
命令本身并不直接输出Java类名,它只输出与 “java” 相关的进程的PID。如果你想要同时获取PID和类名信息,你可以使用 jps
命令,这是 JDK 提供的一个专门用来显示 Java 虚拟机(JVM)启动的主类名的工具。
jps
命令的输出将直接给出每个 Java 进程的 PID 和类名。如果你想要通过 pgrep
来达到类似的效果,你需要结合其他命令来提取类名。不过,这通常不是最直接或最准确的方法。
使用 jps
的命令如下:
jps
这将列出所有 Java 进程的 PID 和类名。
如果你确实想要使用 pgrep
来查找 PID,并尝试从 ps
命令的输出中提取类名,你可以使用以下命令:
pgrep -f java | xargs -I {} ps -fp {} | awk '/java/ {print $2, $NF}'
这里的命令解释如下:
pgrep -f java
:查找所有命令行中包含 “java” 的进程,并输出它们的 PID。xargs -I {} ps -fp {}
:对于pgrep
输出的每个 PID,使用ps -fp
命令来获取该进程的完整信息。-I {}
表示将pgrep
的输出作为ps
命令的参数。awk '/java/ {print $2, $NF}'
:使用awk
来过滤出包含 “java” 的行,并打印每行的第二个字段(通常是 PID)和最后一个字段(通常是 Java 类名或命令行参数的最后一部分)。
请注意,$NF
可能不会总是给出类名,因为它取决于命令行参数的形式。如果类名不在命令行参数的最后一个位置,这种方法可能不会工作。
最推荐的方法仍然是使用 jps
,因为它专门设计用来列出 Java 进程的 PID 和类名,而且输出准确。
在 Linux 系统中,如果你只知道文件名的一部分,你可以使用 find
命令来搜索该文件。find
命令允许你在文件系统的指定目录(及其子目录)中搜索匹配指定模式的文件。
以下是一个基本的使用 find
命令的例子,它会在当前目录及其子目录中搜索包含特定字符串的文件名:
find . -type f -name '*部分文件名*'
这里的参数解释如下:
.
表示从当前目录开始搜索。-type f
表示只搜索文件,不包括目录。-name '*部分文件名*'
表示搜索文件名中包含“部分文件名”的文件。星号(*)是通配符,代表任意数量的任意字符。
例如,如果你想要找到文件名中包含 “example” 的文件,你可以执行:
find . -type f -name '*example*'
这个命令会列出当前目录及其所有子目录中所有文件名包含 “example” 的文件,并显示它们的完整路径。
如果你想要搜索整个文件系统,你可以从根目录 /
开始搜索:
find / -type f -name '*部分文件名*'
但是,请注意,从根目录开始搜索可能需要一些时间,并且可能需要适当的权限,因为不是所有目录都是对所有用户开放的。
如果你知道文件所在的大致目录,你可以将搜索范围限制在那个目录及其子目录中,以加快搜索速度。
另外,如果你知道文件的其他属性(如大小、修改日期等),你还可以使用 find
命令的其他选项来进一步缩小搜索范围。
请注意,如果你没有适当的权限,某些目录可能无法访问,并且find
命令可能会显示权限被拒绝的错误消息。为了避免这些错误消息,你可以将错误消息重定向到/dev/null
:
find / -name "example.txt" 2>/dev/null
所以最终可以组合成:
find / -type f -name '*arthas*' 2>/dev/null
如果没有权限直接执行 sudo 命令:
sudo java -jar arthas-boot.jar 21245
服务重启了,现在复现不了了,我擦,下次如果问题还复现了,第一时间在消费者调用之前执行下这个命令,我怀疑是哪个dubbo filter 里面的逻辑导致了,我这边也在开发dubbo http filter 埋点的,到时候问题复现了,采集埋点信息,分析到底哪个filter 造成的
watch org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker doInvoke ‘{params,@com.weaver.framework.rpc.context.impl.TenantRpcContext@getTenantKey(),@com.weaver.common.cas.context.WeaverCasInfoContext@getTenantKey(),@com.weaver.framework.rpc.context.impl.TenantRpcContext@getFrameworkTenantKey(),returnObj,throwExp}’ ‘params[0].getTargetServiceUniqueName().contains(“dubbo接口全路径”)&¶ms[0].getMethodName().equals(“方法名称”)’ -b -n 5 -x 3
watch org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker,doInvoke
'{
params,
@com.weaver.framework.rpc.context.impl.TenantRpcContext@getTenantKey(),
@com.weaver.common.cas.context.WeaverCasInfoContext@getTenantKey(),
@com.weaver.framework.rpc.context.impl.TenantRpcContext@getFrameworkTenantKey()
,returnObj
,throwExp
}’
‘params[0].getTargetServiceUniqueName().contains(“com.weaver.ebuilder.form.client.service.emobile.IEtFormDatasetService”)&¶ms[0].getMethodName().equals(“getFields”)’
-b -n 5 -x
com.weaver.customerservice.component.share.utils.RpcUtil,invoke
‘{params,returnObj}’ ‘params[0].getMethodName().contains(“employeeLimit”)’