feat(docs): new docs site by vuepress2 (#2220)
@@ -0,0 +1,21 @@
|
||||
name: auto prettier
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'site-vuepress/**'
|
||||
|
||||
jobs:
|
||||
prettier:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
- name: Prettify code
|
||||
uses: creyD/prettier_action@v4.2
|
||||
with:
|
||||
prettier_options: --config ./site-vuepress/.prettierrc.json --ignore-path ./site-vuepress/.prettierignore --write ./site-vuepress
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
.temp
|
||||
.cache
|
||||
@@ -0,0 +1,2 @@
|
||||
.cache
|
||||
.temp
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"tabWidth": 2
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<h1>Arthas 文档网站<sub>(power by vuepress)</sub></h1>
|
||||
|
||||
## 项目运行
|
||||
|
||||
```shell
|
||||
# 安装依赖
|
||||
npm install
|
||||
|
||||
# 启动项目
|
||||
npm run docs:dev
|
||||
|
||||
# 发布项目(打包到 docs/.vuepress/dist 目录)
|
||||
npm run docs:build
|
||||
```
|
||||
@@ -0,0 +1,53 @@
|
||||
import { defineClientConfig } from "@vuepress/client";
|
||||
import { usePageData } from "@vuepress/client";
|
||||
import oldContributorsData from "./oldContributorsData.json";
|
||||
|
||||
const addOldDocsContributors = () => {
|
||||
const page = usePageData();
|
||||
if (!page.value.git) return;
|
||||
const filePath = page.value.filePathRelative;
|
||||
const contributors = page.value.git.contributors;
|
||||
const oldContributors = oldContributorsData[filePath];
|
||||
|
||||
const haveSameContributor = (contributors, oldContributor) => {
|
||||
return contributors.find(
|
||||
(contributor) =>
|
||||
contributor.name === oldContributor.name &&
|
||||
contributor.email === oldContributor.email
|
||||
);
|
||||
};
|
||||
|
||||
if (oldContributors) {
|
||||
oldContributors.forEach((oldContributor) => {
|
||||
if (!haveSameContributor(contributors, oldContributor)) {
|
||||
contributors.push(oldContributor);
|
||||
} else {
|
||||
haveSameContributor(contributors, oldContributor).commits +=
|
||||
oldContributor.commits;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// sort contributors by commits
|
||||
contributors?.sort((a, b) => b.commits - a.commits);
|
||||
};
|
||||
|
||||
export default defineClientConfig({
|
||||
enhance({ router }) {
|
||||
router.afterEach((to, from) => {
|
||||
if (to.fullPath !== from.fullPath) {
|
||||
addOldDocsContributors();
|
||||
}
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (typeof _hmt != "undefined") {
|
||||
if (to.path && to.fullPath !== from.fullPath) {
|
||||
_hmt.push(["_trackPageview", to.fullPath]);
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,109 @@
|
||||
const { localTheme } = require("./theme/index");
|
||||
|
||||
const { copyCodePlugin } = require("vuepress-plugin-copy-code2");
|
||||
const { redirectPlugin } = require("vuepress-plugin-redirect");
|
||||
const { searchPlugin } = require("@vuepress/plugin-search");
|
||||
|
||||
module.exports = {
|
||||
title: "arthas",
|
||||
description: "arthas user document",
|
||||
head: require("./configs/head"),
|
||||
locales: {
|
||||
"/": {
|
||||
lang: "zh-CN",
|
||||
title: "arthas",
|
||||
description: "arthas 使用文档",
|
||||
},
|
||||
"/en/": {
|
||||
lang: "en-US",
|
||||
title: "arthas",
|
||||
description: "arthas user document",
|
||||
},
|
||||
},
|
||||
theme: localTheme({
|
||||
logo: "/images/arthas_light.png",
|
||||
logoDark: "/images/arthas_dark.png",
|
||||
repo: "alibaba/arthas",
|
||||
docsDir: "site-vuepress/docs",
|
||||
docsBranch: "master",
|
||||
|
||||
locales: {
|
||||
"/": {
|
||||
selectLanguageName: "简体中文",
|
||||
selectLanguageText: "Languages",
|
||||
editLinkText: "在 GitHub 上编辑此页",
|
||||
lastUpdated: "上次更新",
|
||||
contributorsText: "贡献者",
|
||||
backToHome: "回到首页",
|
||||
warning: "注意",
|
||||
tip: "提示",
|
||||
danger: "警告",
|
||||
// 404 page
|
||||
notFound: [
|
||||
"这里什么都没有",
|
||||
"我们怎么到这来了?",
|
||||
"这是一个 404 页面",
|
||||
"看起来我们进入了错误的链接",
|
||||
],
|
||||
backToHome: "返回首页",
|
||||
openInNewWindow: "在新窗口打开",
|
||||
toggleColorMode: "切换颜色模式",
|
||||
toggleSidebar: "切换侧边栏",
|
||||
navbar: require("./configs/navbar/zh"),
|
||||
sidebar: require("./configs/sidebar/zh"),
|
||||
sidebarDepth: 0,
|
||||
},
|
||||
"/en/": {
|
||||
selectLanguageName: "English",
|
||||
selectLanguageText: "Languages",
|
||||
editLinkText: "Edit this page on GitHub",
|
||||
navbar: require("./configs/navbar/en"),
|
||||
sidebar: require("./configs/sidebar/en"),
|
||||
sidebarDepth: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
plugins: [
|
||||
copyCodePlugin({
|
||||
showInMobile: false,
|
||||
pure: true,
|
||||
locales: {
|
||||
"/": {
|
||||
hint: "复制代码",
|
||||
},
|
||||
"/en/": {
|
||||
hint: "Copy code",
|
||||
},
|
||||
},
|
||||
}),
|
||||
searchPlugin({
|
||||
locales: {
|
||||
"/": {
|
||||
placeholder: "搜索文档",
|
||||
},
|
||||
"/en/": {
|
||||
placeholder: "Search Docs",
|
||||
},
|
||||
},
|
||||
}),
|
||||
redirectPlugin({
|
||||
config: (app) => {
|
||||
const redirects = Object.fromEntries(
|
||||
app.pages
|
||||
.filter((page) => page.path.startsWith("/en/doc/"))
|
||||
.map((page) => [
|
||||
page.path.replace(/^\/en\/doc\//, "/doc/en/"),
|
||||
page.path,
|
||||
])
|
||||
);
|
||||
|
||||
delete redirects["/doc/en/"];
|
||||
redirects["/doc/en/index.html"] = "/en/doc/index.html";
|
||||
redirects["/en-us/index.html"] = "/en/index.html";
|
||||
redirects["/zh-cn/index.html"] = "/index.html";
|
||||
|
||||
return redirects;
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
module.exports = [
|
||||
["link", { rel: "icon", href: "/images/favicon.ico" }],
|
||||
[
|
||||
"meta",
|
||||
{ name: "viewport", content: "width=device-width, initial-scale=1.0" },
|
||||
],
|
||||
[
|
||||
"script",
|
||||
{},
|
||||
`
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?d5c5e25b100f0eb51a4c35c8a86ea9b4";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
`,
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,52 @@
|
||||
module.exports = [
|
||||
{
|
||||
text: "HOME",
|
||||
link: "/en/",
|
||||
},
|
||||
{
|
||||
text: "ONLINE TUTORIALS",
|
||||
link: "/doc/arthas-tutorials.html?language=en&id=arthas-basics",
|
||||
target: "_blank",
|
||||
},
|
||||
{
|
||||
text: "DOCS",
|
||||
link: "/en/doc",
|
||||
},
|
||||
{
|
||||
text: "SOLUTIONS",
|
||||
children: [
|
||||
{
|
||||
text: "Microservice solutions",
|
||||
link: "https://cn.aliyun.com/product/aliware/mse?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
{
|
||||
text: "Distributed transaction solutions",
|
||||
link: "https://www.aliyun.com/aliware/txc?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
{
|
||||
text: "High-availability solution",
|
||||
link: "https://www.aliyun.com/product/ahas?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
{
|
||||
text: "Serverless solution for miscoservices",
|
||||
link: "https://cn.aliyun.com/product/aliware/sae?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
{
|
||||
text: "PaaS solution",
|
||||
link: "https://www.aliyun.com/product/edas?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
{
|
||||
text: "Service mesh solution",
|
||||
link: "https://www.aliyun.com/product/servicemesh?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "DOWNLOAD",
|
||||
link: "/en/doc/download.md",
|
||||
},
|
||||
{
|
||||
text: "COMMUNITY",
|
||||
link: "https://github.com/alibaba/arthas/issues",
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,52 @@
|
||||
module.exports = [
|
||||
{
|
||||
text: "首页",
|
||||
link: "/",
|
||||
},
|
||||
{
|
||||
text: "在线教程",
|
||||
link: "/doc/arthas-tutorials.html?language=cn&id=arthas-basics",
|
||||
target: "_blank",
|
||||
},
|
||||
{
|
||||
text: "文档",
|
||||
link: "/doc/",
|
||||
},
|
||||
{
|
||||
text: "解决方案",
|
||||
children: [
|
||||
{
|
||||
text: "微服务解决方案",
|
||||
link: "https://cn.aliyun.com/product/aliware/mse?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
{
|
||||
text: "分布式事务解决方案",
|
||||
link: "https://www.aliyun.com/aliware/txc?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
{
|
||||
text: "高可用解决方案",
|
||||
link: "https://www.aliyun.com/product/ahas?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
{
|
||||
text: "微服务Serverless解决方案",
|
||||
link: "https://cn.aliyun.com/product/aliware/sae?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
{
|
||||
text: "PaaS解决方案",
|
||||
link: "https://www.aliyun.com/product/edas?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
{
|
||||
text: "服务网格解决方案",
|
||||
link: "https://www.aliyun.com/product/servicemesh?spm=arthas.topbar.0.0.0",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "下载",
|
||||
link: "/doc/download.md",
|
||||
},
|
||||
{
|
||||
text: "社区",
|
||||
link: "https://github.com/alibaba/arthas/issues",
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,148 @@
|
||||
module.exports = {
|
||||
"/en/doc": [
|
||||
{
|
||||
text: "DOCS",
|
||||
children: [
|
||||
"/en/doc/README.md",
|
||||
"/en/doc/quick-start.md",
|
||||
"/en/doc/install-detail.md",
|
||||
"/en/doc/download.md",
|
||||
"/en/doc/advanced-use.md",
|
||||
{
|
||||
text: "Other features",
|
||||
collapsible: true,
|
||||
children: [
|
||||
"/en/doc/async.md",
|
||||
"/en/doc/save-log.md",
|
||||
"/en/doc/batch-support.md",
|
||||
{
|
||||
text: "How to use ognl",
|
||||
link: "",
|
||||
children: [
|
||||
{
|
||||
text: "Basic ognl example",
|
||||
link: "https://github.com/alibaba/arthas/issues/11",
|
||||
},
|
||||
{
|
||||
text: "Ognl special uses",
|
||||
link: "https://github.com/alibaba/arthas/issues/71",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "Commands",
|
||||
collapsible: true,
|
||||
link: "/en/doc/commands.md",
|
||||
children: [
|
||||
{
|
||||
text: "jvm",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"/en/doc/dashboard.md",
|
||||
"/en/doc/thread.md",
|
||||
"/en/doc/jvm.md",
|
||||
"/en/doc/memory.md",
|
||||
"/en/doc/sysprop.md",
|
||||
"/en/doc/sysenv.md",
|
||||
"/en/doc/vmoption.md",
|
||||
"/en/doc/perfcounter.md",
|
||||
"/en/doc/logger.md",
|
||||
"/en/doc/mbean.md",
|
||||
"/en/doc/getstatic.md",
|
||||
"/en/doc/ognl.md",
|
||||
"/en/doc/heapdump.md",
|
||||
"/en/doc/vmtool.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "class/classloader",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"/en/doc/sc.md",
|
||||
"/en/doc/sm.md",
|
||||
"/en/doc/jad.md",
|
||||
"/en/doc/classloader.md",
|
||||
"/en/doc/mc.md",
|
||||
"/en/doc/dump.md",
|
||||
"/en/doc/retransform.md",
|
||||
"/en/doc/redefine.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "monitor/watch/trace - related",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"/en/doc/monitor.md",
|
||||
"/en/doc/watch.md",
|
||||
"/en/doc/trace.md",
|
||||
"/en/doc/stack.md",
|
||||
"/en/doc/tt.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "other",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"/en/doc/profiler.md",
|
||||
"/en/doc/cat.md",
|
||||
"/en/doc/echo.md",
|
||||
"/en/doc/grep.md",
|
||||
"/en/doc/base64.md",
|
||||
"/en/doc/tee.md",
|
||||
"/en/doc/pwd.md",
|
||||
"/en/doc/auth.md",
|
||||
"/en/doc/options.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "Basic",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"/en/doc/help.md",
|
||||
"/en/doc/cls.md",
|
||||
"/en/doc/session.md",
|
||||
"/en/doc/reset.md",
|
||||
"/en/doc/history.md",
|
||||
"/en/doc/quit.md",
|
||||
"/en/doc/stop.md",
|
||||
{
|
||||
text: "keymap",
|
||||
link: "/en/doc/keymap.md",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"/en/doc/web-console.md",
|
||||
"/en/doc/tunnel.md",
|
||||
"/en/doc/http-api.md",
|
||||
"/en/doc/docker.md",
|
||||
"/en/doc/spring-boot-starter.md",
|
||||
"/en/doc/idea-plugin.md",
|
||||
"/en/doc/faq.md",
|
||||
{
|
||||
text: "User cases",
|
||||
link: "https://github.com/alibaba/arthas/issues?q=label%3Auser-case",
|
||||
},
|
||||
{
|
||||
text: "Start me at github",
|
||||
link: "https://github.com/alibaba/arthas",
|
||||
},
|
||||
{
|
||||
text: "Compile and debug/CONTRIBUTING",
|
||||
link: "https://github.com/alibaba/arthas/blob/master/CONTRIBUTING.md",
|
||||
},
|
||||
{
|
||||
text: "Release Notes",
|
||||
link: "https://github.com/alibaba/arthas/releases",
|
||||
},
|
||||
{
|
||||
text: "Contact us",
|
||||
link: "/en/doc/contact-us.md",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,152 @@
|
||||
module.exports = {
|
||||
"/doc/": [
|
||||
{
|
||||
text: "文档",
|
||||
children: [
|
||||
"/doc/README.md",
|
||||
"/doc/quick-start.md",
|
||||
{
|
||||
text: "在线教程(阿里云)",
|
||||
link: "https://start.aliyun.com/handson-lab?category=arthas",
|
||||
},
|
||||
"/doc/install-detail.md",
|
||||
"/doc/download.md",
|
||||
"/doc/advanced-use.md",
|
||||
{
|
||||
text: "其他特性",
|
||||
collapsible: true,
|
||||
children: [
|
||||
"/doc/async.md",
|
||||
"/doc/save-log.md",
|
||||
"/doc/batch-support.md",
|
||||
{
|
||||
text: "ognl 表达式用法",
|
||||
link: "",
|
||||
children: [
|
||||
{
|
||||
text: "活用ognl表达式",
|
||||
link: "https://github.com/alibaba/arthas/issues/11",
|
||||
},
|
||||
{
|
||||
text: "一些ognl特殊用法",
|
||||
link: "https://github.com/alibaba/arthas/issues/71",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "命令列表",
|
||||
collapsible: true,
|
||||
link: "/doc/commands.md",
|
||||
children: [
|
||||
{
|
||||
text: "jvm相关",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"/doc/dashboard.md",
|
||||
"/doc/thread.md",
|
||||
"/doc/jvm.md",
|
||||
"/doc/memory.md",
|
||||
"/doc/sysprop.md",
|
||||
"/doc/sysenv.md",
|
||||
"/doc/vmoption.md",
|
||||
"/doc/perfcounter.md",
|
||||
"/doc/logger.md",
|
||||
"/doc/mbean.md",
|
||||
"/doc/getstatic.md",
|
||||
"/doc/ognl.md",
|
||||
"/doc/heapdump.md",
|
||||
"/doc/vmtool.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "class/classloader相关",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"/doc/sc.md",
|
||||
"/doc/sm.md",
|
||||
"/doc/jad.md",
|
||||
"/doc/classloader.md",
|
||||
"/doc/mc.md",
|
||||
"/doc/dump.md",
|
||||
"/doc/retransform.md",
|
||||
"/doc/redefine.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "monitor/watch/trace相关",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"/doc/monitor.md",
|
||||
"/doc/watch.md",
|
||||
"/doc/trace.md",
|
||||
"/doc/stack.md",
|
||||
"/doc/tt.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "其他",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"/doc/profiler.md",
|
||||
"/doc/cat.md",
|
||||
"/doc/echo.md",
|
||||
"/doc/grep.md",
|
||||
"/doc/base64.md",
|
||||
"/doc/tee.md",
|
||||
"/doc/pwd.md",
|
||||
"/doc/auth.md",
|
||||
"/doc/options.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "基础命令",
|
||||
collapsible: false,
|
||||
children: [
|
||||
"/doc/help.md",
|
||||
"/doc/cls.md",
|
||||
"/doc/session.md",
|
||||
"/doc/reset.md",
|
||||
"/doc/history.md",
|
||||
"/doc/quit.md",
|
||||
"/doc/stop.md",
|
||||
{
|
||||
text: "keymap",
|
||||
link: "/doc/keymap.md",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"/doc/web-console.md",
|
||||
"/doc/tunnel.md",
|
||||
"/doc/http-api.md",
|
||||
"/doc/docker.md",
|
||||
"/doc/spring-boot-starter.md",
|
||||
"/doc/idea-plugin.md",
|
||||
"/doc/faq.md",
|
||||
{
|
||||
text: "用户案列",
|
||||
link: "https://github.com/alibaba/arthas/issues?q=label%3Auser-case",
|
||||
},
|
||||
{
|
||||
text: "Start me at github",
|
||||
link: "https://github.com/alibaba/arthas",
|
||||
},
|
||||
{
|
||||
text: "编译调试/参与贡献",
|
||||
link: "https://github.com/alibaba/arthas/blob/master/CONTRIBUTING.md",
|
||||
},
|
||||
{
|
||||
text: "Release Notes",
|
||||
link: "https://github.com/alibaba/arthas/releases",
|
||||
},
|
||||
{
|
||||
text: "QQ群/钉钉群",
|
||||
link: "/doc/contact-us.md",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 199 KiB |
|
Before Width: | Height: | Size: 312 KiB After Width: | Height: | Size: 312 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 244 KiB After Width: | Height: | Size: 244 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 791 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 49 KiB |
@@ -0,0 +1,3 @@
|
||||
.site-name.can-hide {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<script>
|
||||
/* eslint-disable import/first, import/no-duplicates, import/order */
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
/* eslint-enable import/order */
|
||||
</script>
|
||||
|
||||
<script setup>
|
||||
import GitHub from "./icons/GitHub.vue";
|
||||
|
||||
import { useSiteData } from "@vuepress/client";
|
||||
import { isLinkHttp, isLinkMailto, isLinkTel } from "@vuepress/shared";
|
||||
import { computed, toRefs } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
const site = useSiteData();
|
||||
const { item } = toRefs(props);
|
||||
|
||||
// if the link has http protocol
|
||||
const hasHttpProtocol = computed(() => isLinkHttp(item.value.link));
|
||||
// if the link has non-http protocol
|
||||
const hasNonHttpProtocol = computed(
|
||||
() => isLinkMailto(item.value.link) || isLinkTel(item.value.link)
|
||||
);
|
||||
// resolve the `target` attr
|
||||
const linkTarget = computed(() => {
|
||||
if (hasNonHttpProtocol.value) return undefined;
|
||||
if (item.value.target) return item.value.target;
|
||||
if (hasHttpProtocol.value) return "_blank";
|
||||
return undefined;
|
||||
});
|
||||
// if the `target` attr is '_blank'
|
||||
const isBlankTarget = computed(() => linkTarget.value === "_blank");
|
||||
// is `<RouterLink>` or not
|
||||
const isRouterLink = computed(
|
||||
() =>
|
||||
!hasHttpProtocol.value && !hasNonHttpProtocol.value && !isBlankTarget.value
|
||||
);
|
||||
// resolve the `rel` attr
|
||||
const linkRel = computed(() => {
|
||||
if (hasNonHttpProtocol.value) return undefined;
|
||||
if (item.value.rel) return item.value.rel;
|
||||
if (isBlankTarget.value) return "noopener noreferrer";
|
||||
return undefined;
|
||||
});
|
||||
// resolve the `aria-label` attr
|
||||
const linkAriaLabel = computed(() => item.value.ariaLabel || item.value.text);
|
||||
|
||||
// should be active when current route is a subpath of this link
|
||||
const shouldBeActiveInSubpath = computed(() => {
|
||||
const localeKeys = Object.keys(site.value.locales);
|
||||
if (localeKeys.length) {
|
||||
return !localeKeys.some((key) => key === item.value.link);
|
||||
}
|
||||
return item.value.link !== "/";
|
||||
});
|
||||
// if this link is active in subpath
|
||||
const isActiveInSubpath = computed(() => {
|
||||
if (!shouldBeActiveInSubpath.value) {
|
||||
return false;
|
||||
}
|
||||
return route.path.startsWith(item.value.link);
|
||||
});
|
||||
|
||||
// if this link is active
|
||||
const isActive = computed(() => {
|
||||
if (!isRouterLink.value) {
|
||||
return false;
|
||||
}
|
||||
if (item.value.activeMatch) {
|
||||
return new RegExp(item.value.activeMatch).test(route.path);
|
||||
}
|
||||
return isActiveInSubpath.value;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RouterLink
|
||||
v-if="isRouterLink"
|
||||
:class="{ 'router-link-active': isActive }"
|
||||
:to="item.link"
|
||||
:aria-label="linkAriaLabel"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<slot name="before" />
|
||||
{{ item.text }}
|
||||
<slot name="after" />
|
||||
</RouterLink>
|
||||
<a
|
||||
v-else
|
||||
class="external-link"
|
||||
:href="item.link"
|
||||
:rel="linkRel"
|
||||
:target="linkTarget"
|
||||
:aria-label="linkAriaLabel"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<slot name="before" />
|
||||
<GitHub v-if="item.text === 'GitHub'" />
|
||||
<span v-else>{{ item.text }}</span>
|
||||
<AutoLinkExternalIcon v-if="isBlankTarget && item.text !== 'GitHub'" />
|
||||
<slot name="after" />
|
||||
</a>
|
||||
</template>
|
||||
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<a class="my-badge" :href="URL" target="_blank">
|
||||
<component :is="comp" />
|
||||
|
||||
<span>{{ number }}</span>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useThemeLocaleData } from "@vuepress/theme-default/lib/client/composables";
|
||||
import { ref } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
comp: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
data: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const number = ref(0);
|
||||
|
||||
// add number to number until number is equal to data
|
||||
var t = setInterval(() => {
|
||||
number.value += 234;
|
||||
if (number.value >= props.data) {
|
||||
number.value = props.data;
|
||||
clearInterval(t);
|
||||
}
|
||||
}, 1);
|
||||
|
||||
const themeData = useThemeLocaleData();
|
||||
const repoURL = `https://github.com/${themeData.value.repo}`;
|
||||
const repoStarsURL = repoURL;
|
||||
const repoForksURL = `${repoURL}/fork`;
|
||||
|
||||
let URL = repoURL;
|
||||
switch (props.comp.name) {
|
||||
case "Star":
|
||||
URL = repoStarsURL;
|
||||
break;
|
||||
case "Fork":
|
||||
URL = repoForksURL;
|
||||
break;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.my-badge {
|
||||
width: fit-content;
|
||||
width: -webkit-fit-content;
|
||||
width: -moz-fit-content;
|
||||
padding: 5px;
|
||||
margin: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 5px;
|
||||
color: var(--c-text);
|
||||
background-color: rgba(89, 95, 101, 0.2);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@media (max-width: 719px) {
|
||||
.my-badge {
|
||||
margin: 0 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import HomeUserBoards from "./HomeUserBoards.vue";
|
||||
import HomeFeatures from "./HomeFeatures.vue";
|
||||
import HomeHero from "./HomeHero.vue";
|
||||
|
||||
import HomeContent from "@theme/HomeContent.vue";
|
||||
import HomeFooter from "@theme/HomeFooter.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="home">
|
||||
<HomeHero />
|
||||
<HomeFeatures />
|
||||
<HomeContent />
|
||||
<HomeUserBoards />
|
||||
<HomeFooter />
|
||||
</main>
|
||||
</template>
|
||||
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div class="badges">
|
||||
<Badge :comp="Star" :data="star" />
|
||||
<Badge :comp="Fork" :data="fork" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Star from "./icons/Star.vue";
|
||||
import Fork from "./icons/Fork.vue";
|
||||
import Badge from "./Badge.vue";
|
||||
|
||||
import { ref, onBeforeMount } from "vue";
|
||||
|
||||
const star = ref(29582);
|
||||
const fork = ref(6494);
|
||||
|
||||
const getData = async () => {
|
||||
const { forks, stargazers_count } = await fetch(
|
||||
"https://api.github.com/repos/alibaba/arthas"
|
||||
).then((res) => res.json());
|
||||
|
||||
star.value = stargazers_count;
|
||||
fork.value = forks;
|
||||
};
|
||||
|
||||
onBeforeMount(getData);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.badges {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,36 @@
|
||||
<script setup>
|
||||
import { usePageFrontmatter } from "@vuepress/client";
|
||||
import { isArray } from "@vuepress/shared";
|
||||
import { computed } from "vue";
|
||||
|
||||
const frontmatter = usePageFrontmatter();
|
||||
const features = computed(() => {
|
||||
if (isArray(frontmatter.value.features)) {
|
||||
return frontmatter.value.features;
|
||||
}
|
||||
return [];
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="features.length" class="features">
|
||||
<div v-for="feature in features" :key="feature.title" class="feature">
|
||||
<div v-if="feature.icon" class="icon">{{ feature.icon }}</div>
|
||||
<h2>{{ feature.title }}</h2>
|
||||
<p>{{ feature.details }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 6px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
font-size: 30px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,102 @@
|
||||
<script setup>
|
||||
import HomeBadges from "./HomeBadges.vue";
|
||||
|
||||
import AutoLink from "@theme/AutoLink.vue";
|
||||
import {
|
||||
ClientOnly,
|
||||
usePageFrontmatter,
|
||||
useSiteLocaleData,
|
||||
withBase,
|
||||
} from "@vuepress/client";
|
||||
import { isArray } from "@vuepress/shared";
|
||||
import { computed, h } from "vue";
|
||||
import { useDarkMode } from "@vuepress/theme-default/lib/client/composables";
|
||||
|
||||
const frontmatter = usePageFrontmatter();
|
||||
const siteLocale = useSiteLocaleData();
|
||||
const isDarkMode = useDarkMode();
|
||||
|
||||
const heroImage = computed(() => {
|
||||
if (isDarkMode.value && frontmatter.value.heroImageDark !== undefined) {
|
||||
return frontmatter.value.heroImageDark;
|
||||
}
|
||||
return frontmatter.value.heroImage;
|
||||
});
|
||||
|
||||
const heroText = computed(() => {
|
||||
if (frontmatter.value.heroText === null) {
|
||||
return null;
|
||||
}
|
||||
return frontmatter.value.heroText || siteLocale.value.title || "Hello";
|
||||
});
|
||||
|
||||
const heroAlt = computed(
|
||||
() => frontmatter.value.heroAlt || heroText.value || "hero"
|
||||
);
|
||||
|
||||
const tagline = computed(() => {
|
||||
if (frontmatter.value.tagline === null) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
frontmatter.value.tagline ||
|
||||
siteLocale.value.description ||
|
||||
"Welcome to your VuePress site"
|
||||
);
|
||||
});
|
||||
|
||||
const actions = computed(() => {
|
||||
if (!isArray(frontmatter.value.actions)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return frontmatter.value.actions.map(({ text, link, type = "primary" }) => ({
|
||||
text,
|
||||
link,
|
||||
type,
|
||||
}));
|
||||
});
|
||||
|
||||
const HomeHeroImage = () => {
|
||||
if (!heroImage.value) return null;
|
||||
const img = h("img", {
|
||||
src: withBase(heroImage.value),
|
||||
style: "width: 60%;",
|
||||
alt: heroAlt.value,
|
||||
});
|
||||
if (frontmatter.value.heroImageDark === undefined) {
|
||||
return img;
|
||||
}
|
||||
// wrap hero image with <ClientOnly> to avoid ssr-mismatch
|
||||
// when using a different hero image in dark mode
|
||||
return h(ClientOnly, () => img);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="hero">
|
||||
<HomeHeroImage />
|
||||
|
||||
<div>
|
||||
<h1 v-if="heroText" id="main-title">
|
||||
{{ heroText }}
|
||||
</h1>
|
||||
|
||||
<p v-if="tagline" class="description">
|
||||
{{ tagline }}
|
||||
</p>
|
||||
|
||||
<HomeBadges />
|
||||
|
||||
<p v-if="actions.length" class="actions">
|
||||
<AutoLink
|
||||
v-for="action in actions"
|
||||
:key="action.text"
|
||||
class="action-button"
|
||||
:class="[action.type]"
|
||||
:item="action"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div class="user-boards" v-if="imgs">
|
||||
<h1>{{ pageData.users_title }}</h1>
|
||||
<p v-html="pageData.users_details"></p>
|
||||
<div class="user-logos">
|
||||
<UserBoard v-for="img in imgs" :key="img.logo" :img="img" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import UserBoard from "./UserBoard.vue";
|
||||
|
||||
import { toRaw } from "vue";
|
||||
import { usePageFrontmatter, usePageLang } from "@vuepress/client";
|
||||
|
||||
const pageData = usePageFrontmatter();
|
||||
const imgs = toRaw(pageData.value.users) || [];
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-boards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-top: 1px solid var(--c-border);
|
||||
padding: 1.2rem 0;
|
||||
margin-top: 20px;
|
||||
|
||||
.user-logos {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,127 @@
|
||||
<script setup>
|
||||
import Translate from "./icons/Translate.vue";
|
||||
|
||||
import AutoLink from "@theme/AutoLink.vue";
|
||||
import DropdownTransition from "@theme/DropdownTransition.vue";
|
||||
import { computed, ref, toRefs, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { item } = toRefs(props);
|
||||
|
||||
const dropdownAriaLabel = computed(
|
||||
() => item.value.ariaLabel || item.value.text
|
||||
);
|
||||
|
||||
const open = ref(false);
|
||||
const route = useRoute();
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
open.value = false;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Open the dropdown when user tab and click from keyboard.
|
||||
*
|
||||
* Use event.detail to detect tab and click from keyboard.
|
||||
* The Tab + Click is UIEvent > KeyboardEvent, so the detail is 0.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
|
||||
*/
|
||||
const handleDropdown = (e) => {
|
||||
const isTriggerByTab = e.detail === 0;
|
||||
if (isTriggerByTab) {
|
||||
open.value = !open.value;
|
||||
} else {
|
||||
open.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const isLastItemOfArray = (item, arr) => arr[arr.length - 1] === item;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="navbar-dropdown-wrapper" :class="{ open }">
|
||||
<button
|
||||
class="navbar-dropdown-title"
|
||||
type="button"
|
||||
:aria-label="dropdownAriaLabel"
|
||||
@click="handleDropdown"
|
||||
>
|
||||
<Translate v-if="item.text === 'Languages'" />
|
||||
<span class="title" v-else>{{ item.text }}</span>
|
||||
<span class="arrow down" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="navbar-dropdown-title-mobile"
|
||||
type="button"
|
||||
:aria-label="dropdownAriaLabel"
|
||||
@click="open = !open"
|
||||
>
|
||||
<Translate v-if="item.text === 'Languages'" />
|
||||
<span class="title" v-else>{{ item.text }}</span>
|
||||
<span class="arrow" :class="open ? 'down' : 'right'" />
|
||||
</button>
|
||||
|
||||
<DropdownTransition>
|
||||
<ul v-show="open" class="navbar-dropdown">
|
||||
<li
|
||||
v-for="child in item.children"
|
||||
:key="child.text"
|
||||
class="navbar-dropdown-item"
|
||||
>
|
||||
<template v-if="child.children">
|
||||
<h4 class="navbar-dropdown-subtitle">
|
||||
<AutoLink
|
||||
v-if="child.link"
|
||||
:item="child"
|
||||
@focusout="
|
||||
isLastItemOfArray(child, item.children) &&
|
||||
child.children.length === 0 &&
|
||||
(open = false)
|
||||
"
|
||||
/>
|
||||
|
||||
<span v-else>{{ child.text }}</span>
|
||||
</h4>
|
||||
|
||||
<ul class="navbar-dropdown-subitem-wrapper">
|
||||
<li
|
||||
v-for="grandchild in child.children"
|
||||
:key="grandchild.link"
|
||||
class="navbar-dropdown-subitem"
|
||||
>
|
||||
<AutoLink
|
||||
:item="grandchild"
|
||||
@focusout="
|
||||
isLastItemOfArray(grandchild, child.children) &&
|
||||
isLastItemOfArray(child, item.children) &&
|
||||
(open = false)
|
||||
"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<AutoLink
|
||||
:item="child"
|
||||
@focusout="
|
||||
isLastItemOfArray(child, item.children) && (open = false)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
</DropdownTransition>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<img class="users-logo" :src="img.logo" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
img: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.users-logo {
|
||||
max-width: 140px;
|
||||
object-fit: contain;
|
||||
margin: 10px;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="131 -131 512 512"
|
||||
style="
|
||||
enable-background: new 131 -131 512 512;
|
||||
height: 1rem;
|
||||
fill: var(--c-text);
|
||||
"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<g id="XMLID_2_">
|
||||
<path
|
||||
id="XMLID_8_"
|
||||
d="M312.8,317c0-8.5-3.4-16.2-9.4-23s-13.7-9.4-23-9.4c-9.3,0-16.2,3.4-23,9.4c-6,6-9.4,13.7-9.4,23
|
||||
s3.4,16.2,9.4,23c6,6,13.7,9.4,23,9.4c9.3,0,16.2-3.4,23-9.4C310.2,334,312.8,325.5,312.8,317z M312.8-67c0-8.5-3.4-16.2-9.4-23
|
||||
c-6-6-13.7-9.4-23-9.4c-9.3,0-16.2,3.4-23,9.4c-6,6-9.4,13.7-9.4,23c0,8.5,3.4,16.2,9.4,23c6,6,13.7,9.4,23,9.4
|
||||
c9.3,0,16.2-3.4,23-9.4C310.2-49.9,312.8-58.5,312.8-67z M526.1-24.3c0-8.5-3.4-16.2-9.4-23s-13.7-9.4-23-9.4s-16.2,3.4-23,9.4
|
||||
s-9.4,13.7-9.4,23s3.4,16.2,9.4,23c6,6,13.7,9.4,23,9.4s16.2-3.4,23-9.4C522.7-8.1,526.1-15.8,526.1-24.3z M557.7-24.3
|
||||
c0,11.9-2.6,22.2-8.5,32.4s-13.7,17.9-23,23c-0.9,64-25.6,110.1-75.1,138.2c-15.4,8.5-37.5,17.1-67.4,27.3
|
||||
c-28.2,8.5-46.9,17.1-56.3,23.9c-9.4,6.8-13.7,17.9-13.7,33.3v8.5c9.4,6,17.9,13.7,23,23c5.1,9.4,8.5,20.5,8.5,32.4
|
||||
c0,17.9-6,33.3-18.8,45.2c-12.8,11.9-28.1,18.1-46.1,18.1s-33.3-6-45.2-18.8s-18.8-27.3-18.8-45.2c0-11.9,2.6-22.2,8.5-32.4
|
||||
c6-10.2,13.7-17.9,23-23V-11.5c-9.4-6-17.9-13.7-23-23s-8.5-20.6-8.5-32.5c0-17.9,6-33.3,18.8-45.2c12.8-11.9,27.3-18.8,45.2-18.8
|
||||
c17.9,0,33.3,6,45.2,18.8s18.8,27.3,18.8,45.2c0,11.9-2.6,22.2-8.5,32.4c-5.9,10.2-13.7,17.9-23,23V154c11.9-6,29-11.9,51.2-18.8
|
||||
c11.9-3.4,22.2-6.8,29-10.2c6.8-3.4,15.4-6,23.9-10.2s15.4-8.5,19.6-12.8s9.4-10.2,13.7-17.1s7.7-14.5,9.4-23
|
||||
c1.7-8.5,2.6-18.8,2.6-30.7c-9.4-6-17.9-13.7-23-23s-8.5-20.5-8.5-32.4c0-17.9,6-33.3,18.8-45.2c12.8-12.8,27.3-18.8,45.2-18.8
|
||||
s33.3,6,45.2,18.8C551.7-57.6,557.7-42.3,557.7-24.3z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Fork",
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 24 24"
|
||||
style="height: 1.25rem; width: 1.25rem; vertical-align: bottom"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5c.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34c-.46-1.16-1.11-1.47-1.11-1.47c-.91-.62.07-.6.07-.6c1 .07 1.53 1.03 1.53 1.03c.87 1.52 2.34 1.07 2.91.83c.09-.65.35-1.09.63-1.34c-2.22-.25-4.55-1.11-4.55-4.92c0-1.11.38-2 1.03-2.71c-.1-.25-.45-1.29.1-2.64c0 0 .84-.27 2.75 1.02c.79-.22 1.65-.33 2.5-.33c.85 0 1.71.11 2.5.33c1.91-1.29 2.75-1.02 2.75-1.02c.55 1.35.2 2.39.1 2.64c.65.71 1.03 1.6 1.03 2.71c0 3.82-2.34 4.66-4.57 4.91c.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2Z"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MdiGithub",
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 512 512"
|
||||
style="
|
||||
enable-background: new 0 0 512 512;
|
||||
height: 1rem;
|
||||
fill: var(--c-text);
|
||||
"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
d="M175.1,168.9L13.7,186.8c-5.8,0.7-11,4.6-12.9,10.5c-1.9,5.9,0,12.1,4.3,16c48,43.8,120.1,109.4,120.1,109.4
|
||||
c-0.1,0-19.8,95.4-32.9,159.1c-1.1,5.8,1,11.9,6,15.5c5,3.7,11.4,3.7,16.5,0.9C171.3,466,256,417.7,256,417.7l141.1,80.5
|
||||
c5.1,2.8,11.6,2.8,16.6-0.9c5-3.7,7.1-9.7,6-15.5l-32.8-159.1L507,213.4c4.3-4,6.2-10.2,4.3-16.1c-1.9-5.9-7.1-9.8-12.9-10.4
|
||||
c-64.6-7.2-161.5-18-161.5-18L269.9,20.8c-2.5-5.3-7.8-9-14-9c-6.2,0-11.5,3.7-13.9,9L175.1,168.9z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Star",
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="1em"
|
||||
height="1em"
|
||||
style="height: 1.25rem; width: 1.25rem; vertical-align: bottom"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M13.35 22q-.6 0-.862-.387q-.263-.388-.063-.963l3.65-9.675q.15-.4.563-.688Q17.05 10 17.5 10q.425 0 .85.287q.425.288.575.688l3.65 9.675q.2.575-.062.963q-.263.387-.888.387q-.275 0-.5-.175q-.225-.175-.325-.425l-.85-2.45H15.1l-.875 2.45q-.1.25-.35.425q-.25.175-.525.175Zm2.35-4.8h3.6l-1.75-4.95h-.1ZM7.15 8.55q.4.725.85 1.337q.45.613 1.05 1.263q1.1-1.2 1.825-2.462Q11.6 7.425 12.1 6H2q-.425 0-.712-.287Q1 5.425 1 5t.288-.713Q1.575 4 2 4h6V3q0-.425.288-.713Q8.575 2 9 2t.713.287Q10 2.575 10 3v1h6q.425 0 .712.287Q17 4.575 17 5t-.288.713Q16.425 6 16 6h-1.9q-.525 1.775-1.425 3.45q-.9 1.675-2.225 3.15l2.4 2.45l-.75 2.05L9 14l-4.3 4.3q-.275.275-.7.275q-.425 0-.7-.275q-.275-.275-.275-.7q0-.425.275-.7l4.35-4.35q-.675-.775-1.25-1.563q-.575-.787-1.025-1.662Q5.1 8.8 5.35 8.4t.875-.4q.25 0 .525.162q.275.163.4.388Z"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -0,0 +1,18 @@
|
||||
const { defaultTheme } = require("@vuepress/theme-default");
|
||||
const { path } = require("@vuepress/utils");
|
||||
|
||||
exports.localTheme = (options) => {
|
||||
return {
|
||||
name: "vuepress-theme-arthas",
|
||||
extends: defaultTheme(options),
|
||||
|
||||
alias: {
|
||||
"@theme/Home.vue": path.resolve(__dirname, "components/Home.vue"),
|
||||
"@theme/NavbarDropdown.vue": path.resolve(
|
||||
__dirname,
|
||||
"components/NavbarDropdown.vue"
|
||||
),
|
||||
"@theme/AutoLink.vue": path.resolve(__dirname, "components/AutoLink.vue"),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
home: true
|
||||
heroImage: /images/arthas_light.png
|
||||
heroImageDark: /images/arthas_dark.png
|
||||
heroText: null
|
||||
tagline: "Java 应用诊断利器"
|
||||
actions:
|
||||
- text: 快速入门
|
||||
link: /doc/quick-start.html
|
||||
type: primary
|
||||
- text: 查看github
|
||||
link: https://github.com/alibaba/arthas
|
||||
type: secondary
|
||||
features:
|
||||
- icon: 🖥
|
||||
title: Dashboard
|
||||
details: 实时查看系统的运行状况。
|
||||
- icon: 🔬
|
||||
title: 查看入参/返回值/异常
|
||||
details: 查看函数调用的参数,返回值和异常。
|
||||
- icon: 🔩
|
||||
title: 在线热更新
|
||||
details: jad/sc/redefine 一条龙热更新代码。
|
||||
- icon: 🩺
|
||||
title: 类冲突
|
||||
details: 秒解类冲突问题,定位类加载路径。
|
||||
- icon: ⚡️
|
||||
title: 性能热点
|
||||
details: 快速定位应用的热点,生成火焰图。
|
||||
- icon: 📡
|
||||
title: WebConsole
|
||||
details: 在线诊断,点开网页诊断线上应用。
|
||||
users_title: "用户"
|
||||
users_details: "请在 <a href='https://github.com/alibaba/arthas/issues/111' target='_blank'>Wanted: who's using arthas</a> 上提供信息来帮助Arthas做的更好。"
|
||||
users:
|
||||
- name: Alibaba Group
|
||||
logo: /images/users/users_alibaba.png
|
||||
- name: Didiglobal
|
||||
logo: /images/users/users_didi.png
|
||||
- name: Kaola
|
||||
logo: /images/users/users_kaola.png
|
||||
- name: Qunar
|
||||
logo: /images/users/users_qunar.png
|
||||
- name: Telecom
|
||||
logo: /images/users/users_telecom.png
|
||||
- name: Weidian
|
||||
logo: /images/users/users_weidian.png
|
||||
- name: ICBC
|
||||
logo: /images/users/users_icbc.png
|
||||
- name: Chinaums
|
||||
logo: /images/users/users_yinlian.png
|
||||
footer: Apache-2.0 license | Copyright 2018-present, Alibaba Middleware Group, and contributors
|
||||
---
|
||||
@@ -0,0 +1,24 @@
|
||||
# 简介
|
||||
|
||||
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。
|
||||
|
||||
## Arthas(阿尔萨斯)能为你做什么?
|
||||
|
||||

|
||||
|
||||
`Arthas` 是 Alibaba 开源的 Java 诊断工具,深受开发者喜爱。
|
||||
|
||||
当你遇到以下类似问题而束手无策时,`Arthas`可以帮助你解决:
|
||||
|
||||
0. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
|
||||
1. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
|
||||
2. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
|
||||
3. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
|
||||
4. 是否有一个全局视角来查看系统的运行状况?
|
||||
5. 有什么办法可以监控到 JVM 的实时运行状态?
|
||||
6. 怎么快速定位应用的热点,生成火焰图?
|
||||
7. 怎样直接从 JVM 内查找某个类的实例?
|
||||
|
||||
`Arthas` 支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 `Tab` 自动补全功能,进一步方便进行问题的定位和诊断。
|
||||
|
||||
**如果您在使用 Arthas,请让我们知道,您的使用对我们非常重要:[查看](https://github.com/alibaba/arthas/issues/111)**
|
||||
@@ -0,0 +1,157 @@
|
||||
# 进阶使用
|
||||
|
||||
## 基础命令
|
||||
|
||||
- [help](help.md)——查看命令帮助信息
|
||||
- [cat](cat.md)——打印文件内容,和 linux 里的 cat 命令类似
|
||||
- [echo](echo.md)——打印参数,和 linux 里的 echo 命令类似
|
||||
- [grep](grep.md)——匹配查找,和 linux 里的 grep 命令类似
|
||||
- [base64](base64.md)——base64 编码转换,和 linux 里的 base64 命令类似
|
||||
- [tee](tee.md)——复制标准输入到标准输出和指定的文件,和 linux 里的 tee 命令类似
|
||||
- [pwd](pwd.md)——返回当前的工作目录,和 linux 命令类似
|
||||
- [cls](cls.md)——清空当前屏幕区域
|
||||
- [session](session.md)——查看当前会话的信息
|
||||
- [reset](reset.md)——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
|
||||
- [version](version.md)——输出当前目标 Java 进程所加载的 Arthas 版本号
|
||||
- [history](history.md)——打印命令历史
|
||||
- [quit](quit.md)——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
|
||||
- [stop](stop.md)——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
|
||||
- [keymap](keymap.md)——Arthas 快捷键列表及自定义快捷键
|
||||
|
||||
## jvm 相关
|
||||
|
||||
- [dashboard](dashboard.md)——当前系统的实时数据面板
|
||||
- [thread](thread.md)——查看当前 JVM 的线程堆栈信息
|
||||
- [jvm](jvm.md)——查看当前 JVM 的信息
|
||||
- [sysprop](sysprop.md)——查看和修改 JVM 的系统属性
|
||||
- [sysenv](sysenv.md)——查看 JVM 的环境变量
|
||||
- [vmoption](vmoption.md)——查看和修改 JVM 里诊断相关的 option
|
||||
- [perfcounter](perfcounter.md)——查看当前 JVM 的 Perf Counter 信息
|
||||
- [logger](logger.md)——查看和修改 logger
|
||||
- [getstatic](getstatic.md)——查看类的静态属性
|
||||
- [ognl](ognl.md)——执行 ognl 表达式
|
||||
- [mbean](mbean.md)——查看 Mbean 的信息
|
||||
- [heapdump](heapdump.md)——dump java heap, 类似 jmap 命令的 heap dump 功能
|
||||
- [vmtool](vmtool.md)——从 jvm 里查询对象,执行 forceGc
|
||||
|
||||
## class/classloader 相关
|
||||
|
||||
- [sc](sc.md)——查看 JVM 已加载的类信息
|
||||
- [sm](sm.md)——查看已加载类的方法信息
|
||||
- [jad](jad.md)——反编译指定已加载类的源码
|
||||
- [mc](mc.md)——内存编译器,内存编译`.java`文件为`.class`文件
|
||||
- [retransform](retransform.md)——加载外部的`.class`文件,retransform 到 JVM 里
|
||||
- [redefine](redefine.md)——加载外部的`.class`文件,redefine 到 JVM 里
|
||||
- [dump](dump.md)——dump 已加载类的 byte code 到特定目录
|
||||
- [classloader](classloader.md)——查看 classloader 的继承树,urls,类加载信息,使用 classloader 去 getResource
|
||||
|
||||
## monitor/watch/trace 相关
|
||||
|
||||
::: warning
|
||||
请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 `stop` 或将增强过的类执行 `reset` 命令。
|
||||
:::
|
||||
|
||||
- [monitor](monitor.md)——方法执行监控
|
||||
- [watch](watch.md)——方法执行数据观测
|
||||
- [trace](trace.md)——方法内部调用路径,并输出方法路径上的每个节点上耗时
|
||||
- [stack](stack.md)——输出当前方法被调用的调用路径
|
||||
- [tt](tt.md)——方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测
|
||||
|
||||
## profiler/火焰图
|
||||
|
||||
- [profiler](profiler.md)--使用[async-profiler](https://github.com/jvm-profiling-tools/async-profiler)对应用采样,生成火焰图
|
||||
|
||||
## 鉴权
|
||||
|
||||
- [auth](auth.md)——鉴权
|
||||
|
||||
## options
|
||||
|
||||
- [options](options.md)——查看或设置 Arthas 全局开关
|
||||
|
||||
## 管道
|
||||
|
||||
Arthas 支持使用管道对上述命令的结果进行进一步的处理,如`sm java.lang.String * | grep 'index'`
|
||||
|
||||
- [grep](grep.md)——搜索满足条件的结果
|
||||
- plaintext——将命令的结果去除 ANSI 颜色
|
||||
- wc——按行统计输出结果
|
||||
|
||||
## 后台异步任务
|
||||
|
||||
当线上出现偶发的问题,比如需要 watch 某个条件,而这个条件一天可能才会出现一次时,异步后台任务就派上用场了,详情请参考[这里](async.md)
|
||||
|
||||
- 使用 `>` 将结果重写向到日志文件,使用 `&` 指定命令是后台运行,session 断开不影响任务执行(生命周期默认为 1 天)
|
||||
- jobs——列出所有 job
|
||||
- kill——强制终止任务
|
||||
- fg——将暂停的任务拉到前台执行
|
||||
- bg——将暂停的任务放到后台执行
|
||||
|
||||
## Web Console
|
||||
|
||||
通过 websocket 连接 Arthas。
|
||||
|
||||
- [Web Console](web-console.md)
|
||||
|
||||
## Arthas Properties
|
||||
|
||||
- [Arthas Properties](arthas-properties.md)
|
||||
|
||||
## 以 java agent 方式启动
|
||||
|
||||
- [以 java agent 方式启动](agent.md)
|
||||
|
||||
## as.sh 和 arthas-boot 技巧
|
||||
|
||||
- 通过`select`功能选择 attach 的进程。
|
||||
|
||||
正常情况下,每次执行`as.sh`/`arthas-boot.jar`需要选择,或者指定 PID。这样会比较麻烦,因为每次启动应用,它的 PID 会变化。
|
||||
|
||||
比如,已经启动了`math-game.jar`,使用`jps`命令查看:
|
||||
|
||||
```bash
|
||||
$ jps
|
||||
58883 math-game.jar
|
||||
58884 Jps
|
||||
```
|
||||
|
||||
通过`select`参数可以指定进程名字,非常方便。
|
||||
|
||||
```bash
|
||||
$ ./as.sh --select math-game
|
||||
Arthas script version: 3.3.6
|
||||
[INFO] JAVA_HOME: /tmp/java/8.0.222-zulu
|
||||
Arthas home: /Users/admin/.arthas/lib/3.3.6/arthas
|
||||
Calculating attach execution time...
|
||||
Attaching to 59161 using version /Users/admin/.arthas/lib/3.3.6/arthas...
|
||||
|
||||
real 0m0.572s
|
||||
user 0m0.281s
|
||||
sys 0m0.039s
|
||||
Attach success.
|
||||
telnet connecting to arthas server... current timestamp is 1594280799
|
||||
Trying 127.0.0.1...
|
||||
Connected to localhost.
|
||||
Escape character is '^]'.
|
||||
,---. ,------. ,--------.,--. ,--. ,---. ,---.
|
||||
/ O \ | .--. ''--. .--'| '--' | / O \ ' .-'
|
||||
| .-. || '--'.' | | | .--. || .-. |`. `-.
|
||||
| | | || |\ \ | | | | | || | | |.-' |
|
||||
`--' `--'`--' '--' `--' `--' `--'`--' `--'`-----'
|
||||
|
||||
|
||||
wiki https://arthas.aliyun.com/doc
|
||||
tutorials https://arthas.aliyun.com/doc/arthas-tutorials.html
|
||||
version 3.3.6
|
||||
pid 58883
|
||||
```
|
||||
|
||||
## 用户数据回报
|
||||
|
||||
在`3.1.4`版本后,增加了用户数据回报功能,方便统一做安全或者历史数据统计。
|
||||
|
||||
在启动时,指定`stat-url`,就会回报执行的每一行命令,比如: `./as.sh --stat-url 'http://192.168.10.11:8080/api/stat'`
|
||||
|
||||
在 tunnel server 里有一个示例的回报代码,用户可以自己在服务器上实现。
|
||||
|
||||
[StatController.java](https://github.com/alibaba/arthas/blob/master/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/app/web/StatController.java)
|
||||
@@ -0,0 +1,43 @@
|
||||
# 表达式核心变量
|
||||
|
||||
无论是匹配表达式也好、观察表达式也罢,他们核心判断变量都是围绕着一个 Arthas 中的通用通知对象 `Advice` 进行。
|
||||
|
||||
它的简略代码结构如下
|
||||
|
||||
```java
|
||||
public class Advice {
|
||||
|
||||
private final ClassLoader loader;
|
||||
private final Class<?> clazz;
|
||||
private final ArthasMethod method;
|
||||
private final Object target;
|
||||
private final Object[] params;
|
||||
private final Object returnObj;
|
||||
private final Throwable throwExp;
|
||||
private final boolean isBefore;
|
||||
private final boolean isThrow;
|
||||
private final boolean isReturn;
|
||||
|
||||
// getter/setter
|
||||
}
|
||||
```
|
||||
|
||||
这里列一个表格来说明不同变量的含义
|
||||
|
||||
| 变量名 | 变量解释 |
|
||||
| --------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| loader | 本次调用类所在的 ClassLoader |
|
||||
| clazz | 本次调用类的 Class 引用 |
|
||||
| method | 本次调用方法反射引用 |
|
||||
| target | 本次调用类的实例 |
|
||||
| params | 本次调用参数列表,这是一个数组,如果方法是无参方法则为空数组 |
|
||||
| returnObj | 本次调用返回的对象。当且仅当 `isReturn==true` 成立时候有效,表明方法调用是以正常返回的方式结束。如果当前方法无返回值 `void`,则值为 null |
|
||||
| throwExp | 本次调用抛出的异常。当且仅当 `isThrow==true` 成立时有效,表明方法调用是以抛出异常的方式结束。 |
|
||||
| isBefore | 辅助判断标记,当前的通知节点有可能是在方法一开始就通知,此时 `isBefore==true` 成立,同时 `isThrow==false` 和 `isReturn==false`,因为在方法刚开始时,还无法确定方法调用将会如何结束。 |
|
||||
| isThrow | 辅助判断标记,当前的方法调用以抛异常的形式结束。 |
|
||||
| isReturn | 辅助判断标记,当前的方法调用以正常返回的形式结束。 |
|
||||
|
||||
所有变量都可以在表达式中直接使用,如果在表达式中编写了不符合 OGNL 脚本语法或者引入了不在表格中的变量,则退出命令的执行;用户可以根据当前的异常信息修正`条件表达式`或`观察表达式`
|
||||
|
||||
- 特殊用法请参考:[https://github.com/alibaba/arthas/issues/71](https://github.com/alibaba/arthas/issues/71)
|
||||
- OGNL 表达式官网:[https://commons.apache.org/proper/commons-ognl/language-guide.html](https://commons.apache.org/proper/commons-ognl/language-guide.html)
|
||||
@@ -0,0 +1,13 @@
|
||||
# 以 Java Agent 的方式启动
|
||||
|
||||
通常 Arthas 是以动态 attach 的方式来诊断应用,但从`3.2.0`版本起,Arthas 支持直接以 java agent 的方式启动。
|
||||
|
||||
比如下载全量的 arthas zip 包,解压之后以 `-javaagent` 的参数指定`arthas-agent.jar`来启动:
|
||||
|
||||
```
|
||||
java -javaagent:/tmp/test/arthas-agent.jar -jar math-game.jar
|
||||
```
|
||||
|
||||
默认的配置项在解压目录里的`arthas.properties`文件里。参考:[Arthas Properties](arthas-properties.md)
|
||||
|
||||
Java Agent 机制参考: https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html
|
||||
@@ -0,0 +1,62 @@
|
||||
# Arthas Properties
|
||||
|
||||
`arthas.properties`文件在 arthas 的目录下。
|
||||
|
||||
- 如果是自动下载的 arthas,则目录在`~/.arthas/lib/3.x.x/arthas/`下面
|
||||
- 如果是下载的完整包,在 arthas 解压目录下
|
||||
|
||||
## 支持的配置项
|
||||
|
||||
::: warning
|
||||
注意配置必须是`驼峰`的,和 spring boot 的`-`风格不一样。spring boot 应用才同时支持`驼峰` 和 `-`风格的配置。
|
||||
:::
|
||||
|
||||
```
|
||||
#arthas.config.overrideAll=true
|
||||
arthas.telnetPort=3658
|
||||
arthas.httpPort=8563
|
||||
arthas.ip=127.0.0.1
|
||||
|
||||
# seconds
|
||||
arthas.sessionTimeout=1800
|
||||
|
||||
#arthas.appName=demoapp
|
||||
#arthas.tunnelServer=ws://127.0.0.1:7777/ws
|
||||
#arthas.agentId=mmmmmmyiddddd
|
||||
```
|
||||
|
||||
- 如果配置 `arthas.telnetPort`为 -1 ,则不 listen telnet 端口。`arthas.httpPort`类似。
|
||||
- 如果配置 `arthas.telnetPort`为 0 ,则随机 telnet 端口,在`~/logs/arthas/arthas.log`里可以找到具体端口日志。`arthas.httpPort`类似。
|
||||
|
||||
:::tip
|
||||
如果是防止一个机器上启动多个 arthas 端口冲突。可以配置为随机端口,或者配置为 -1,并且通过 tunnel server 来使用 arthas。
|
||||
:::
|
||||
|
||||
### 禁止指定命令
|
||||
|
||||
::: tip
|
||||
since 3.5.2
|
||||
:::
|
||||
|
||||
比如配置:
|
||||
|
||||
```
|
||||
arthas.disabledCommands=stop,dump
|
||||
```
|
||||
|
||||
也可以在命令行配置: `--disabled-commands stop,dump` 。
|
||||
|
||||
::: tip
|
||||
默认情况下,arthas-spring-boot-starter 会禁掉`stop`命令。
|
||||
:::
|
||||
|
||||
## 配置的优先级
|
||||
|
||||
配置的优先级是:命令行参数 > System Env > System Properties > arthas.properties 。
|
||||
|
||||
比如:
|
||||
|
||||
- `./as.sh --telnet-port 9999` 传入的配置会覆盖掉`arthas.properties`里的默认值`arthas.telnetPort=3658`。
|
||||
- 如果应用自身设置了 system properties `arthas.telnetPort=8888`,则会覆盖掉`arthas.properties`里的默认值`arthas.telnetPort=3658`。
|
||||
|
||||
如果想要 `arthas.properties`的优先级最高,则可以配置 `arthas.config.overrideAll=true` 。
|
||||
@@ -1,7 +1,8 @@
|
||||
### Arthas3.0的新特性
|
||||
### Arthas3.0 的新特性
|
||||
|
||||
#### 在线诊断功能
|
||||
Arthas3.0中最重要的特性,不需要登陆机器就可以对应用进行诊断,体验和本地诊断完全一致
|
||||
|
||||
Arthas3.0 中最重要的特性,不需要登陆机器就可以对应用进行诊断,体验和本地诊断完全一致
|
||||
|
||||
##### 使用步骤
|
||||
|
||||
@@ -12,26 +13,26 @@ TODO
|
||||
TODO
|
||||
|
||||
#### 管道支持
|
||||
Arthas 3.0开始支持管道, 率先提供了`grep`,`wc`,`plaintext`的支持。
|
||||
|
||||
Arthas 3.0 开始支持管道, 率先提供了`grep`,`wc`,`plaintext`的支持。
|
||||
|
||||
### 去groovy依赖
|
||||
### 去 groovy 依赖
|
||||
|
||||
groovy表达式在arthas2.0中大量使用,例如watch表达式
|
||||
groovy 表达式在 arthas2.0 中大量使用,例如 watch 表达式
|
||||
|
||||
```bash
|
||||
watch com.alibaba.sample.petstore.web.store.module.screen.ItemList add "params + ' ' + returnObj" params.size()==2
|
||||
```
|
||||
|
||||
其中`"params + ' ' + returnObj"`以及`params.size()==2`背后其实都使用了groovy来进行表达式求值,如果反复大量的运行这些表达式,groovy会创建大量的classloader,打满perm区从而触发FGC。
|
||||
其中`"params + ' ' + returnObj"`以及`params.size()==2`背后其实都使用了 groovy 来进行表达式求值,如果反复大量的运行这些表达式,groovy 会创建大量的 classloader,打满 perm 区从而触发 FGC。
|
||||
|
||||
为了避免这个问题,Arthas 3.0中使用了ognl这个更加轻量的表达式求值库来代替groovy,彻底解决了groovy引起的FGC风险。但由于这个替换,导致原来使用groovy脚本编写的自定义脚本失效。这个问题留待后续解决。
|
||||
为了避免这个问题,Arthas 3.0 中使用了 ognl 这个更加轻量的表达式求值库来代替 groovy,彻底解决了 groovy 引起的 FGC 风险。但由于这个替换,导致原来使用 groovy 脚本编写的自定义脚本失效。这个问题留待后续解决。
|
||||
|
||||
在3.0中,watch命令的表达式部分的书写有了一些改变,详见[这里](https://arthas.aliyun.com/doc/watch)
|
||||
在 3.0 中,watch 命令的表达式部分的书写有了一些改变,详见[这里](https://arthas.aliyun.com/doc/watch)
|
||||
|
||||
#### 提升rt统计精度
|
||||
#### 提升 rt 统计精度
|
||||
|
||||
Arthas 2.0中,统计rt都是以`ms`为单位,对于某些比较小的方法调用,耗时在毫秒以下的都会被认为是0ms,造成trace总时间和各方法的时间相加不一致等问题(虽然这里面确实会有误差,主要Arthas自身的开销)。Arthas 3.0中所有rt的单位统一改为使用`ns`来统计,精准捕获你的方法耗时,让0ms这样无意义的统计数据不再出现!
|
||||
Arthas 2.0 中,统计 rt 都是以`ms`为单位,对于某些比较小的方法调用,耗时在毫秒以下的都会被认为是 0ms,造成 trace 总时间和各方法的时间相加不一致等问题(虽然这里面确实会有误差,主要 Arthas 自身的开销)。Arthas 3.0 中所有 rt 的单位统一改为使用`ns`来统计,精准捕获你的方法耗时,让 0ms 这样无意义的统计数据不再出现!
|
||||
|
||||
```
|
||||
$ tt -l
|
||||
@@ -45,13 +46,13 @@ $ tt -l
|
||||
1005 2017-02-24 10:57:39 814.657657 true false 0x3bd5e918 TestTraceServlet doGet
|
||||
```
|
||||
|
||||
#### watch/stack/trace命令支持按耗时过滤
|
||||
#### watch/stack/trace 命令支持按耗时过滤
|
||||
|
||||
我们在trace的时候,经常会出现某个方法间隙性的rt飙高,但是我们只想知道rt高的时候,是哪里慢了,对于正常rt的方法我们并不关心,Arthas 3.0支持了按`#cost`(方法执行耗时,单位为`ms`)进行过滤,只输出符合条件的trace路径,目前,这三个命令的相关文档已经做了更新,增加了该用法的示例。
|
||||
我们在 trace 的时候,经常会出现某个方法间隙性的 rt 飙高,但是我们只想知道 rt 高的时候,是哪里慢了,对于正常 rt 的方法我们并不关心,Arthas 3.0 支持了按`#cost`(方法执行耗时,单位为`ms`)进行过滤,只输出符合条件的 trace 路径,目前,这三个命令的相关文档已经做了更新,增加了该用法的示例。
|
||||
|
||||
#### sysprop命令操作SystemProperty
|
||||
#### sysprop 命令操作 SystemProperty
|
||||
|
||||
sysprop命令支持查看所有的系统属性,以及针对特定属性进行查看和修改。
|
||||
sysprop 命令支持查看所有的系统属性,以及针对特定属性进行查看和修改。
|
||||
|
||||
```
|
||||
$ sysprop
|
||||
@@ -77,36 +78,32 @@ Successfully changed the system property.
|
||||
production.mode=true
|
||||
```
|
||||
|
||||
#### thread命令支持指定采样时间
|
||||
#### thread 命令支持指定采样时间
|
||||
|
||||
thread命令计算线程cpu占用的逻辑,默认是采样100ms内各个线程的cpu使用情况并计算cpu消耗占比。有时候100ms的时间间隔太短,看不出问题所在,Arthas3.0中thread命令支持设置采样间隔(以`ms`为单位),可以观察任意时间段内的cpu消耗占比情况。
|
||||
thread 命令计算线程 cpu 占用的逻辑,默认是采样 100ms 内各个线程的 cpu 使用情况并计算 cpu 消耗占比。有时候 100ms 的时间间隔太短,看不出问题所在,Arthas3.0 中 thread 命令支持设置采样间隔(以`ms`为单位),可以观察任意时间段内的 cpu 消耗占比情况。
|
||||
|
||||
```
|
||||
$ thread -i 1000
|
||||
Threads Total: 74, NEW: 0, RUNNABLE: 17, BLOCKED: 0, WAITING: 15, TIMED_WAITING: 42, TERMINATED: 0
|
||||
ID NAME GROUP PRIORITY STATE %CPU TIME INTERRUPTED DAEMON
|
||||
78 com.taobao.config.client.timer main 5 TIMED_WAITING 22 0:0 false true
|
||||
92 Abandoned connection cleanup thread main 5 TIMED_WAITING 15 0:2 false true
|
||||
361 as-command-execute-daemon system 10 RUNNABLE 14 0:0 false true
|
||||
67 HSF-Remoting-Timer-10-thread-1 main 10 TIMED_WAITING 12 0:2 false true
|
||||
113 JamScheduleThread system 9 TIMED_WAITING 2 0:0 false true
|
||||
14 Thread-3 main 5 RUNNABLE 2 0:0 false false
|
||||
81 com.taobao.remoting.TimerThread main 5 TIMED_WAITING 2 0:0 false true
|
||||
104 http-bio-7001-AsyncTimeout main 5 TIMED_WAITING 2 0:0 false true
|
||||
123 nioEventLoopGroup-2-1 system 10 RUNNABLE 2 0:0 false false
|
||||
127 nioEventLoopGroup-3-2 system 10 RUNNABLE 2 0:0 false false
|
||||
345 nioEventLoopGroup-3-3 system 10 RUNNABLE 2 0:0 false false
|
||||
358 nioEventLoopGroup-3-4 system 10 RUNNABLE 2 0:0 false false
|
||||
27 qos-boss-1-1 main 5 RUNNABLE 2 0:0 false true
|
||||
22 EagleEye-AsyncAppender-Thread-BizLog main 5 TIMED_WAITING 1 0:0 false true
|
||||
$ thread -i 1000
|
||||
Threads Total: 74, NEW: 0, RUNNABLE: 17, BLOCKED: 0, WAITING: 15, TIMED_WAITING: 42, TERMINATED: 0
|
||||
ID NAME GROUP PRIORITY STATE %CPU TIME INTERRUPTED DAEMON
|
||||
78 com.taobao.config.client.timer main 5 TIMED_WAITING 22 0:0 false true
|
||||
92 Abandoned connection cleanup thread main 5 TIMED_WAITING 15 0:2 false true
|
||||
361 as-command-execute-daemon system 10 RUNNABLE 14 0:0 false true
|
||||
67 HSF-Remoting-Timer-10-thread-1 main 10 TIMED_WAITING 12 0:2 false true
|
||||
113 JamScheduleThread system 9 TIMED_WAITING 2 0:0 false true
|
||||
14 Thread-3 main 5 RUNNABLE 2 0:0 false false
|
||||
81 com.taobao.remoting.TimerThread main 5 TIMED_WAITING 2 0:0 false true
|
||||
104 http-bio-7001-AsyncTimeout main 5 TIMED_WAITING 2 0:0 false true
|
||||
123 nioEventLoopGroup-2-1 system 10 RUNNABLE 2 0:0 false false
|
||||
127 nioEventLoopGroup-3-2 system 10 RUNNABLE 2 0:0 false false
|
||||
345 nioEventLoopGroup-3-3 system 10 RUNNABLE 2 0:0 false false
|
||||
358 nioEventLoopGroup-3-4 system 10 RUNNABLE 2 0:0 false false
|
||||
27 qos-boss-1-1 main 5 RUNNABLE 2 0:0 false true
|
||||
22 EagleEye-AsyncAppender-Thread-BizLog main 5 TIMED_WAITING 1 0:0 false true
|
||||
```
|
||||
|
||||
#### trace 命令自动高亮显示最耗时方法调用
|
||||
|
||||
#### trace命令自动高亮显示最耗时方法调用
|
||||
|
||||
trace命令现在会自动显示
|
||||
trace 命令现在会自动显示
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# Arthas 后台异步任务
|
||||
|
||||
[`后台异步任务`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials?language=cn&id=case-async-jobs)
|
||||
|
||||
arthas 中的后台异步任务,使用了仿 linux 系统任务相关的命令。[linux 任务相关介绍](https://ehlxr.me/2017/01/18/Linux-%E4%B8%AD-fg%E3%80%81bg%E3%80%81jobs%E3%80%81-%E6%8C%87%E4%BB%A4/)。
|
||||
|
||||
## 1. 使用&在后台执行任务
|
||||
|
||||
比如希望执行后台执行 trace 命令,那么调用下面命令
|
||||
|
||||
```bash
|
||||
trace Test t &
|
||||
```
|
||||
|
||||
这时命令在后台执行,可以在 console 中继续执行其他命令。
|
||||
|
||||
## 2. 通过 jobs 查看任务
|
||||
|
||||
如果希望查看当前有哪些 arthas 任务在执行,可以执行 jobs 命令,执行结果如下
|
||||
|
||||
```bash
|
||||
$ jobs
|
||||
[10]*
|
||||
Stopped watch com.taobao.container.Test test "params[0].{? #this.name == null }" -x 2
|
||||
execution count : 19
|
||||
start time : Fri Sep 22 09:59:55 CST 2017
|
||||
timeout date : Sat Sep 23 09:59:55 CST 2017
|
||||
session : 3648e874-5e69-473f-9eed-7f89660b079b (current)
|
||||
```
|
||||
|
||||
可以看到目前有一个后台任务在执行。
|
||||
|
||||
- job id 是 10, `*` 表示此 job 是当前 session 创建
|
||||
- 状态是 Stopped
|
||||
- execution count 是执行次数,从启动开始已经执行了 19 次
|
||||
- timeout date 是超时的时间,到这个时间,任务将会自动超时退出
|
||||
|
||||
## 3. 任务暂停和取消
|
||||
|
||||
当任务正在前台执行,比如直接调用命令`trace Test t`或者调用后台执行命令`trace Test t &`后又通过`fg`命令将任务转到前台。这时 console 中无法继续执行命令,但是可以接收并处理以下事件:
|
||||
|
||||
- ‘ctrl + z’:将任务暂停。通过`jbos`查看任务状态将会变为 Stopped,通过`bg <job-id>`或者`fg <job-id>`可让任务重新开始执行
|
||||
- ‘ctrl + c’:停止任务
|
||||
- ‘ctrl + d’:按照 linux 语义应当是退出终端,目前 arthas 中是空实现,不处理
|
||||
|
||||
## 4. fg、bg 命令,将命令转到前台、后台继续执行
|
||||
|
||||
- 任务在后台执行或者暂停状态(`ctrl + z`暂停任务)时,执行`fg <job-id>`将可以把对应的任务转到前台继续执行。在前台执行时,无法在 console 中执行其他命令
|
||||
- 当任务处于暂停状态时(`ctrl + z`暂停任务),执行`bg <job-id>`将可以把对应的任务在后台继续执行
|
||||
- 非当前 session 创建的 job,只能由当前 session fg 到前台执行
|
||||
|
||||
## 5. 任务输出重定向
|
||||
|
||||
可通过`>`或者`>>`将任务输出结果输出到指定的文件中,可以和`&`一起使用,实现 arthas 命令的后台异步任务。比如:
|
||||
|
||||
```bash
|
||||
$ trace Test t >> test.out &
|
||||
```
|
||||
|
||||
这时 trace 命令会在后台执行,并且把结果输出到~/logs/arthas-cache/test.out。可继续执行其他命令。并可查看文件中的命令执行结果。
|
||||
|
||||
当连接到远程的 arthas server 时,可能无法查看远程机器的文件,arthas 同时支持了自动重定向到本地缓存路径。使用方法如下:
|
||||
|
||||
```bash
|
||||
$ trace Test t >> &
|
||||
job id : 2
|
||||
cache location : /Users/gehui/logs/arthas-cache/28198/2
|
||||
```
|
||||
|
||||
可以看到并没有指定重定向文件位置,arthas 自动重定向到缓存中了,执行命令后会输出 job id 和 cache location。cache location 就是重定向文件的路径,在系统 logs 目录下,路径包括 pid 和 job id,避免和其他任务冲突。命令输出结果到`/Users/gehui/logs/arthas-cache/28198/2`中,job id 为 2。
|
||||
|
||||
## 6. 停止命令
|
||||
|
||||
异步执行的命令,如果希望停止,可执行`kill <job-id>`
|
||||
|
||||
## 7. 其他
|
||||
|
||||
- 最多同时支持 8 个命令使用重定向将结果写日志
|
||||
- 请勿同时开启过多的后台异步命令,以免对目标 JVM 性能造成影响
|
||||
- 如果不想停止 arthas,继续执行后台任务,可以执行 `quit` 退出 arthas 控制台(`stop` 会停止 arthas 服务)
|
||||
@@ -1,19 +1,20 @@
|
||||
auth
|
||||
===
|
||||
# auth
|
||||
|
||||
> 验证当前会话
|
||||
::: tip
|
||||
验证当前会话
|
||||
:::
|
||||
|
||||
### 配置用户名和密码
|
||||
|
||||
在attach时,可以在命令行指定密码。比如:
|
||||
在 attach 时,可以在命令行指定密码。比如:
|
||||
|
||||
```
|
||||
java -jar arthas-boot.jar --password ppp
|
||||
```
|
||||
|
||||
* 可以通过 `--username` 选项来指定用户,默认值是`arthas`。
|
||||
* 也可以在 `arthas.properties` 里中配置 username/password。命令行的优先级大于配置文件。
|
||||
* 如果只配置`username`,没有配置`password`,则会生成随机密码,打印在`~/logs/arthas/arthas.log`中
|
||||
- 可以通过 `--username` 选项来指定用户,默认值是`arthas`。
|
||||
- 也可以在 `arthas.properties` 里中配置 username/password。命令行的优先级大于配置文件。
|
||||
- 如果只配置`username`,没有配置`password`,则会生成随机密码,打印在`~/logs/arthas/arthas.log`中
|
||||
|
||||
```
|
||||
Using generated security password: 0vUBJpRIppkKuZ7dYzYqOKtranj4unGh
|
||||
@@ -27,11 +28,11 @@ java -jar arthas-boot.jar --password ppp
|
||||
arthas.localConnectionNonAuth=true
|
||||
```
|
||||
|
||||
当配置密码时,使用本地连接,也不需要鉴权。默认配置值是true,方便本地连接使用。只有远程连接时,才需要鉴权。
|
||||
当配置密码时,使用本地连接,也不需要鉴权。默认配置值是 true,方便本地连接使用。只有远程连接时,才需要鉴权。
|
||||
|
||||
### 在telnet console里鉴权
|
||||
### 在 telnet console 里鉴权
|
||||
|
||||
连接到arthas后,直接执行命令会提示需要鉴权:
|
||||
连接到 arthas 后,直接执行命令会提示需要鉴权:
|
||||
|
||||
```bash
|
||||
[arthas@37430]$ help
|
||||
@@ -45,10 +46,9 @@ Error! command not permitted, try to use 'auth' command to authenticates.
|
||||
Authentication result: true
|
||||
```
|
||||
|
||||
* 可以通过 `--username` 选项来指定用户,默认值是`arthas`。
|
||||
- 可以通过 `--username` 选项来指定用户,默认值是`arthas`。
|
||||
|
||||
|
||||
### Web console密码验证
|
||||
### Web console 密码验证
|
||||
|
||||
打开浏览器,会有弹窗提示需要输入 用户名 和 密码。
|
||||
|
||||
@@ -56,27 +56,25 @@ Authentication result: true
|
||||
|
||||
### HTTP API 验证
|
||||
|
||||
#### Authorization Header 方式(推荐)
|
||||
|
||||
#### Authorization Header方式(推荐)
|
||||
Arthas 采用的是 HTTP 标准的 Basic Authorization,客户端请求时增加对应的header即可。
|
||||
Arthas 采用的是 HTTP 标准的 Basic Authorization,客户端请求时增加对应的 header 即可。
|
||||
|
||||
* 参考:[https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication)
|
||||
- 参考:[https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication)
|
||||
|
||||
|
||||
例如,用户名是:`admin`,密码是 `admin`,则组合为字符串: `admin:admin`,base64结果是: `YWRtaW46YWRtaW4=`,则HTTP 请求增加`Authorization` header:
|
||||
例如,用户名是:`admin`,密码是 `admin`,则组合为字符串: `admin:admin`,base64 结果是: `YWRtaW46YWRtaW4=`,则 HTTP 请求增加`Authorization` header:
|
||||
|
||||
```bash
|
||||
curl 'http://localhost:8563/api' \
|
||||
-H 'Authorization: Basic YWRtaW46YWRtaW4=' \
|
||||
--data-raw '{"action":"exec","command":"version"}'
|
||||
--data-raw '{"action":"exec","command":"version"}'
|
||||
```
|
||||
|
||||
#### URL 参数传递方式
|
||||
|
||||
为了方便各种特殊情况,支持了以 parameters 方式传递username和password。比如:
|
||||
为了方便各种特殊情况,支持了以 parameters 方式传递 username 和 password。比如:
|
||||
|
||||
```bash
|
||||
curl 'http://localhost:8563/api?password=admin' \
|
||||
--data-raw '{"action":"exec","command":"version"}'
|
||||
--data-raw '{"action":"exec","command":"version"}'
|
||||
```
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
base64
|
||||
===
|
||||
|
||||
|
||||
> base64编码转换,和linux里的 base64 命令类似。
|
||||
# base64
|
||||
|
||||
::: tip
|
||||
base64 编码转换,和 linux 里的 base64 命令类似。
|
||||
:::
|
||||
|
||||
### 对文件进行 base64 编码
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
批处理功能
|
||||
===
|
||||
# 批处理功能
|
||||
|
||||
> 通过批处理功能,arthas支持一次性批量运行多个命令,并取得命令执行的结果。
|
||||
::: tip
|
||||
通过批处理功能,arthas 支持一次性批量运行多个命令,并取得命令执行的结果。
|
||||
:::
|
||||
|
||||
### 使用方法
|
||||
|
||||
#### 第一步: 创建你的批处理脚本
|
||||
|
||||
这里我们新建了一个`test.as`脚本,为了规范,我们采用了.as后缀名,但事实上任意的文本文件都ok。
|
||||
这里我们新建了一个`test.as`脚本,为了规范,我们采用了.as 后缀名,但事实上任意的文本文件都 ok。
|
||||
|
||||
> 注意事项
|
||||
> * 目前需要每个命令占一行
|
||||
> * dashboard务必指定执行次数(`-n`),否则会导致批处理脚本无法终止
|
||||
> * watch/tt/trace/monitor/stack等命令务必指定执行次数(`-n`),否则会导致批处理脚本无法终止
|
||||
> * 可以使用异步后台任务,如 `watch c.t.X test returnObj > &`,让命令一直在后台运行,通过日志获取结果,[获取更多异步任务的信息](async.md)
|
||||
::: tip
|
||||
|
||||
- 目前需要每个命令占一行
|
||||
- dashboard 务必指定执行次数(`-n`),否则会导致批处理脚本无法终止
|
||||
- watch/tt/trace/monitor/stack 等命令务必指定执行次数(`-n`),否则会导致批处理脚本无法终止
|
||||
- 可以使用异步后台任务,如 `watch c.t.X test returnObj > &`,让命令一直在后台运行,通过日志获取结果,[获取更多异步任务的信息](async.md)
|
||||
:::
|
||||
|
||||
```
|
||||
➜ arthas git:(develop) cat /var/tmp/test.as
|
||||
@@ -42,4 +45,4 @@ sc -d org.apache.commons.lang.StringUtils
|
||||
|
||||
```bash
|
||||
cat test.out
|
||||
```
|
||||
```
|
||||
@@ -1,11 +1,11 @@
|
||||
cat
|
||||
===
|
||||
# cat
|
||||
|
||||
[`cat`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=command-cat)
|
||||
|
||||
> 打印文件内容,和linux里的cat命令类似。
|
||||
|
||||
::: tip
|
||||
打印文件内容,和 linux 里的 cat 命令类似。
|
||||
:::
|
||||
|
||||
```bash
|
||||
$ cat /tmp/a.txt
|
||||
```
|
||||
```
|
||||
@@ -1,26 +1,26 @@
|
||||
classloader
|
||||
===
|
||||
# classloader
|
||||
|
||||
[`classloader`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials?language=cn&id=command-classloader)
|
||||
|
||||
> 查看classloader的继承树,urls,类加载信息
|
||||
::: tip
|
||||
查看 classloader 的继承树,urls,类加载信息
|
||||
:::
|
||||
|
||||
`classloader` 命令将 JVM 中所有的classloader的信息统计出来,并可以展示继承树,urls等。
|
||||
|
||||
可以让指定的classloader去getResources,打印出所有查找到的resources的url。对于`ResourceNotFoundException`比较有用。
|
||||
`classloader` 命令将 JVM 中所有的 classloader 的信息统计出来,并可以展示继承树,urls 等。
|
||||
|
||||
可以让指定的 classloader 去 getResources,打印出所有查找到的 resources 的 url。对于`ResourceNotFoundException`比较有用。
|
||||
|
||||
### 参数说明
|
||||
|
||||
|参数名称|参数说明|
|
||||
|---:|:---|
|
||||
|[l]|按类加载实例进行统计|
|
||||
|[t]|打印所有ClassLoader的继承树|
|
||||
|[a]|列出所有ClassLoader加载的类,请谨慎使用|
|
||||
|`[c:]`|ClassLoader的hashcode|
|
||||
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|
||||
|`[c: r:]`|用ClassLoader去查找resource|
|
||||
|`[c: load:]`|用ClassLoader去加载指定的类|
|
||||
| 参数名称 | 参数说明 |
|
||||
| --------------------: | :----------------------------------------- |
|
||||
| [l] | 按类加载实例进行统计 |
|
||||
| [t] | 打印所有 ClassLoader 的继承树 |
|
||||
| [a] | 列出所有 ClassLoader 加载的类,请谨慎使用 |
|
||||
| `[c:]` | ClassLoader 的 hashcode |
|
||||
| `[classLoaderClass:]` | 指定执行表达式的 ClassLoader 的 class name |
|
||||
| `[c: r:]` | 用 ClassLoader 去查找 resource |
|
||||
| `[c: load:]` | 用 ClassLoader 去加载指定的类 |
|
||||
|
||||
### 使用参考
|
||||
|
||||
@@ -49,7 +49,7 @@ $ classloader -l
|
||||
Affect(row-cnt:4) cost in 2 ms.
|
||||
```
|
||||
|
||||
#### 查看ClassLoader的继承树
|
||||
#### 查看 ClassLoader 的继承树
|
||||
|
||||
```bash
|
||||
$ classloader -t
|
||||
@@ -60,7 +60,7 @@ $ classloader -t
|
||||
Affect(row-cnt:4) cost in 3 ms.
|
||||
```
|
||||
|
||||
#### 查看URLClassLoader实际的urls
|
||||
#### 查看 URLClassLoader 实际的 urls
|
||||
|
||||
```bash
|
||||
$ classloader -c 3d4eac69
|
||||
@@ -70,9 +70,9 @@ file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar
|
||||
Affect(row-cnt:9) cost in 3 ms.
|
||||
```
|
||||
|
||||
*注意* hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。
|
||||
_注意_ hashcode 是变化的,需要先查看当前的 ClassLoader 信息,提取对应 ClassLoader 的 hashcode。
|
||||
|
||||
对于只有唯一实例的ClassLoader可以通过class name指定,使用起来更加方便:
|
||||
对于只有唯一实例的 ClassLoader 可以通过 class name 指定,使用起来更加方便:
|
||||
|
||||
```bash
|
||||
$ classloader --classLoaderClass sun.misc.Launcher$AppClassLoader
|
||||
@@ -82,7 +82,7 @@ file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar
|
||||
Affect(row-cnt:9) cost in 3 ms.
|
||||
```
|
||||
|
||||
#### 使用ClassLoader去查找resource
|
||||
#### 使用 ClassLoader 去查找 resource
|
||||
|
||||
```bash
|
||||
$ classloader -c 3d4eac69 -r META-INF/MANIFEST.MF
|
||||
@@ -91,14 +91,14 @@ $ classloader -c 3d4eac69 -r META-INF/MANIFEST.MF
|
||||
jar:file:/Users/hengyunabc/.arthas/lib/3.0.5/arthas/arthas-agent.jar!/META-INF/MANIFEST.MF
|
||||
```
|
||||
|
||||
也可以尝试查找类的class文件:
|
||||
也可以尝试查找类的 class 文件:
|
||||
|
||||
```bash
|
||||
$ classloader -c 1b6d3586 -r java/lang/String.class
|
||||
jar:file:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/rt.jar!/java/lang/String.class
|
||||
```
|
||||
|
||||
#### 使用ClassLoader去加载类
|
||||
#### 使用 ClassLoader 去加载类
|
||||
|
||||
```bash
|
||||
$ classloader -c 3d4eac69 --load demo.MathGame
|
||||
@@ -125,9 +125,11 @@ load class success.
|
||||
classLoaderHash 3d4eac69
|
||||
```
|
||||
|
||||
#### 统计ClassLoader实际使用URL和未使用的URL
|
||||
#### 统计 ClassLoader 实际使用 URL 和未使用的 URL
|
||||
|
||||
> 注意,基于JVM目前已加载的所有类统计,不代表`Unused URLs`可以从应用中删掉。因为可能将来需要从`Unused URLs`里加载类,或者需要加载`resources`。
|
||||
::: warning
|
||||
注意,基于 JVM 目前已加载的所有类统计,不代表`Unused URLs`可以从应用中删掉。因为可能将来需要从`Unused URLs`里加载类,或者需要加载`resources`。
|
||||
:::
|
||||
|
||||
```
|
||||
$ classloader --url-stat
|
||||
@@ -157,4 +159,4 @@ $ classloader --url-stat
|
||||
file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/sunpkcs11.jar
|
||||
file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/jaccess.jar
|
||||
file:/tmp/jdk1.8/Contents/Home/jre/lib/ext/zipfs.jar
|
||||
```
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
# cls
|
||||
|
||||
清空当前屏幕区域。
|
||||
|
||||
::: tip
|
||||
非终端模式下使用 cls 指令,会提示"Command 'cls' is only support tty session."。
|
||||
:::
|
||||
@@ -0,0 +1,50 @@
|
||||
# 命令列表
|
||||
|
||||
- [dashboard](dashboard.md)
|
||||
- [thread](thread.md)
|
||||
- [jvm](jvm.md)
|
||||
- [memory](memory.md)
|
||||
- [sysprop](sysprop.md)
|
||||
- [sysenv](sysenv.md)
|
||||
- [vmoption](vmoption.md)
|
||||
- [perfcounter](perfcounter.md)
|
||||
- [logger](logger.md)
|
||||
- [mbean](mbean.md)
|
||||
- [getstatic](getstatic.md)
|
||||
- [ognl](ognl.md)
|
||||
- [sc](sc.md)
|
||||
- [sm](sm.md)
|
||||
- [dump](dump.md)
|
||||
- [heapdump](heapdump.md)
|
||||
- [vmtool](vmtool.md)
|
||||
- [jad](jad.md)
|
||||
- [classloader](classloader.md)
|
||||
- [mc](mc.md)
|
||||
- [retransform](retransform.md)
|
||||
- [redefine](redefine.md)
|
||||
- [monitor](monitor.md)
|
||||
- [watch](watch.md)
|
||||
- [trace](trace.md)
|
||||
- [stack](stack.md)
|
||||
- [tt](tt.md)
|
||||
- [profiler](profiler.md)
|
||||
- [cat](cat.md)
|
||||
- [echo](echo.md)
|
||||
- [grep](grep.md)
|
||||
- [base64](base64.md)
|
||||
- [tee](tee.md)
|
||||
- [pwd](pwd.md)
|
||||
- [auth](auth.md)
|
||||
- [options](options.md)
|
||||
|
||||
### Arthas 基础命令
|
||||
|
||||
- [help](help.md)
|
||||
- [cls](cls.md)
|
||||
- [session](session.md)
|
||||
- [reset](reset.md)
|
||||
- [version](version.md)
|
||||
- [history](history.md)
|
||||
- [quit](quit.md)
|
||||
- [stop](stop.md)
|
||||
- [keymap](keymap.md)
|
||||
@@ -0,0 +1,35 @@
|
||||
# 联系我们
|
||||
|
||||
## 招聘
|
||||
|
||||
- [期待你的加入](https://mp.weixin.qq.com/s/XQv8GnqGT3pzceVwzeiy-A)
|
||||
|
||||
### Issues
|
||||
|
||||
使用疑问,意见可以直接在 Issues 里提出: [https://github.com/alibaba/arthas/issues](https://github.com/alibaba/arthas/issues)
|
||||
|
||||
### 微信公众号
|
||||
|
||||
欢迎关注公众号,获取 Arthas 项目的信息、源码分析、案例实践。
|
||||
|
||||

|
||||
|
||||
### 钉钉群
|
||||
|
||||
- Arthas 开源交流钉钉群: 21965291 ,搜索群号即可加入。
|
||||
|
||||

|
||||
|
||||
- Arthas 开源交流钉钉群 2: 30707824 ,搜索群号即可加入。
|
||||
|
||||

|
||||
|
||||
### QQ 群
|
||||
|
||||
Arthas 开源交流 QQ 群: 916328269
|
||||
|
||||

|
||||
|
||||
Arthas 开源交流 QQ 群 2: 854625984
|
||||
|
||||

|
||||
@@ -1,18 +1,19 @@
|
||||
dashboard
|
||||
===
|
||||
# dashboard
|
||||
|
||||
[`dashboard`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=command-dashboard)
|
||||
|
||||
> 当前系统的实时数据面板,按 ctrl+c 退出。
|
||||
::: tip
|
||||
当前系统的实时数据面板,按 ctrl+c 退出。
|
||||
:::
|
||||
|
||||
当运行在Ali-tomcat时,会显示当前tomcat的实时信息,如HTTP请求的qps, rt, 错误数, 线程池信息等等。
|
||||
当运行在 Ali-tomcat 时,会显示当前 tomcat 的实时信息,如 HTTP 请求的 qps, rt, 错误数, 线程池信息等等。
|
||||
|
||||
### 参数说明
|
||||
|
||||
|参数名称|参数说明|
|
||||
|---:|:---|
|
||||
|[i:]|刷新实时数据的时间间隔 (ms),默认5000ms|
|
||||
|[n:]|刷新实时数据的次数|
|
||||
| 参数名称 | 参数说明 |
|
||||
| -------: | :--------------------------------------- |
|
||||
| [i:] | 刷新实时数据的时间间隔 (ms),默认 5000ms |
|
||||
| [n:] | 刷新实时数据的次数 |
|
||||
|
||||
### 使用参考
|
||||
|
||||
@@ -53,30 +54,31 @@ uptime 272s
|
||||
|
||||
### 数据说明
|
||||
|
||||
* ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应。
|
||||
* NAME: 线程名
|
||||
* GROUP: 线程组名
|
||||
* PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
|
||||
* STATE: 线程的状态
|
||||
* CPU%: 线程的cpu使用率。比如采样间隔1000ms,某个线程的增量cpu时间为100ms,则cpu使用率=100/1000=10%
|
||||
* DELTA_TIME: 上次采样之后线程运行增量CPU时间,数据格式为`秒`
|
||||
* TIME: 线程运行总CPU时间,数据格式为`分:秒`
|
||||
* INTERRUPTED: 线程当前的中断位状态
|
||||
* DAEMON: 是否是daemon线程
|
||||
- ID: Java 级别的线程 ID,注意这个 ID 不能跟 jstack 中的 nativeID 一一对应。
|
||||
- NAME: 线程名
|
||||
- GROUP: 线程组名
|
||||
- PRIORITY: 线程优先级, 1~10 之间的数字,越大表示优先级越高
|
||||
- STATE: 线程的状态
|
||||
- CPU%: 线程的 cpu 使用率。比如采样间隔 1000ms,某个线程的增量 cpu 时间为 100ms,则 cpu 使用率=100/1000=10%
|
||||
- DELTA_TIME: 上次采样之后线程运行增量 CPU 时间,数据格式为`秒`
|
||||
- TIME: 线程运行总 CPU 时间,数据格式为`分:秒`
|
||||
- INTERRUPTED: 线程当前的中断位状态
|
||||
- DAEMON: 是否是 daemon 线程
|
||||
|
||||
#### JVM内部线程
|
||||
Java 8之后支持获取JVM内部线程CPU时间,这些线程只有名称和CPU时间,没有ID及状态等信息(显示ID为-1)。
|
||||
通过内部线程可以观测到JVM活动,如GC、JIT编译等占用CPU情况,方便了解JVM整体运行状况。
|
||||
#### JVM 内部线程
|
||||
|
||||
* 当JVM 堆(heap)/元数据(metaspace)空间不足或OOM时,可以看到GC线程的CPU占用率明显高于其他的线程。
|
||||
* 当执行`trace/watch/tt/redefine`等命令后,可以看到JIT线程活动变得更频繁。因为JVM热更新class字节码时清除了此class相关的JIT编译结果,需要重新编译。
|
||||
Java 8 之后支持获取 JVM 内部线程 CPU 时间,这些线程只有名称和 CPU 时间,没有 ID 及状态等信息(显示 ID 为-1)。
|
||||
通过内部线程可以观测到 JVM 活动,如 GC、JIT 编译等占用 CPU 情况,方便了解 JVM 整体运行状况。
|
||||
|
||||
JVM内部线程包括下面几种:
|
||||
* JIT编译线程: 如 `C1 CompilerThread0`, `C2 CompilerThread0`
|
||||
* GC线程: 如`GC Thread0`, `G1 Young RemSet Sampling`
|
||||
* 其它内部线程: 如`VM Periodic Task Thread`, `VM Thread`, `Service Thread`
|
||||
- 当 JVM 堆(heap)/元数据(metaspace)空间不足或 OOM 时,可以看到 GC 线程的 CPU 占用率明显高于其他的线程。
|
||||
- 当执行`trace/watch/tt/redefine`等命令后,可以看到 JIT 线程活动变得更频繁。因为 JVM 热更新 class 字节码时清除了此 class 相关的 JIT 编译结果,需要重新编译。
|
||||
|
||||
JVM 内部线程包括下面几种:
|
||||
|
||||
- JIT 编译线程: 如 `C1 CompilerThread0`, `C2 CompilerThread0`
|
||||
- GC 线程: 如`GC Thread0`, `G1 Young RemSet Sampling`
|
||||
- 其它内部线程: 如`VM Periodic Task Thread`, `VM Thread`, `Service Thread`
|
||||
|
||||
### 截图展示
|
||||
|
||||

|
||||

|
||||
@@ -0,0 +1,118 @@
|
||||
# Docker
|
||||
|
||||
## 在 Docker 里使用 JDK
|
||||
|
||||
很多时候,应用在 docker 里出现 arthas 无法工作的问题,是因为应用没有安装 JDK ,而是安装了 JRE 。如果只安装了 JRE,则会缺少很多 JAVA 的命令行工具和类库,Arthas 也没办法正常工作。下面介绍两种常见的在 Docker 里使用 JDK 的方式。
|
||||
|
||||
### 使用公开的 JDK 镜像
|
||||
|
||||
- https://hub.docker.com/_/openjdk/
|
||||
|
||||
比如:
|
||||
|
||||
```
|
||||
FROM openjdk:8-jdk
|
||||
```
|
||||
|
||||
或者:
|
||||
|
||||
```
|
||||
FROM openjdk:8-jdk-alpine
|
||||
```
|
||||
|
||||
### 通过包管理软件来安装
|
||||
|
||||
比如:
|
||||
|
||||
```bash
|
||||
# Install OpenJDK-8
|
||||
RUN apt-get update && \
|
||||
apt-get install -y openjdk-8-jdk && \
|
||||
apt-get install -y ant && \
|
||||
apt-get clean;
|
||||
|
||||
# Fix certificate issues
|
||||
RUN apt-get update && \
|
||||
apt-get install ca-certificates-java && \
|
||||
apt-get clean && \
|
||||
update-ca-certificates -f;
|
||||
|
||||
# Setup JAVA_HOME -- useful for docker commandline
|
||||
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/
|
||||
RUN export JAVA_HOME
|
||||
```
|
||||
|
||||
或者:
|
||||
|
||||
```bash
|
||||
RUN yum install -y \
|
||||
java-1.8.0-openjdk \
|
||||
java-1.8.0-openjdk-devel
|
||||
|
||||
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk/
|
||||
RUN export JAVA_HOME
|
||||
```
|
||||
|
||||
## 通过 Docker 快速入门
|
||||
|
||||
1. 删除本地已有的`math-game` docker container(非必要)
|
||||
|
||||
```sh
|
||||
$ docker stop math-game || true && docker rm math-game || true
|
||||
```
|
||||
|
||||
1. 启动`math-game`
|
||||
|
||||
```sh
|
||||
$ docker run --name math-game -it hengyunabc/arthas:latest /bin/sh -c "java -jar /opt/arthas/math-game.jar"
|
||||
```
|
||||
|
||||
1. 启动`arthas-boot`来进行诊断
|
||||
|
||||
```sh
|
||||
$ docker exec -it math-game /bin/sh -c "java -jar /opt/arthas/arthas-boot.jar"
|
||||
* [1]: 9 jar
|
||||
|
||||
[INFO] arthas home: /opt/arthas
|
||||
[INFO] Try to attach process 9
|
||||
[INFO] Attach process 9 success.
|
||||
[INFO] arthas-client connect 127.0.0.1 3658
|
||||
,---. ,------. ,--------.,--. ,--. ,---. ,---.
|
||||
/ O \ | .--. ''--. .--'| '--' | / O \ ' .-'
|
||||
| .-. || '--'.' | | | .--. || .-. |`. `-.
|
||||
| | | || |\ \ | | | | | || | | |.-' |
|
||||
`--' `--'`--' '--' `--' `--' `--'`--' `--'`-----'
|
||||
|
||||
|
||||
wiki: https://arthas.aliyun.com/doc
|
||||
version: 3.0.5
|
||||
pid: 9
|
||||
time: 2018-12-18 11:30:36
|
||||
```
|
||||
|
||||
## 诊断 Docker 里的 Java 进程
|
||||
|
||||
```sh
|
||||
docker exec -it ${containerId} /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"
|
||||
```
|
||||
|
||||
## 诊断 k8s 里容器里的 Java 进程
|
||||
|
||||
```sh
|
||||
kubectl exec -it ${pod} --container ${containerId} -- /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"
|
||||
```
|
||||
|
||||
## 把 Arthas 安装到基础镜像里
|
||||
|
||||
可以很简单把 Arthas 安装到你的 Docker 镜像里。
|
||||
|
||||
```
|
||||
FROM openjdk:8-jdk-alpine
|
||||
|
||||
# copy arthas
|
||||
COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas
|
||||
```
|
||||
|
||||
如果想指定版本,可以查看具体的 tags:
|
||||
|
||||
[https://hub.docker.com/r/hengyunabc/arthas/tags](https://hub.docker.com/r/hengyunabc/arthas/tags)
|
||||
@@ -1,18 +1,16 @@
|
||||
下载
|
||||
===
|
||||
# 下载
|
||||
|
||||
## 下载全量包
|
||||
|
||||
### 从Maven仓库下载
|
||||
### 从 Maven 仓库下载
|
||||
|
||||
最新版本,点击下载:[](https://arthas.aliyun.com/download/latest_version?mirror=aliyun)
|
||||
|
||||
|
||||
### 从Github Releases页下载
|
||||
### 从 Github Releases 页下载
|
||||
|
||||
[https://github.com/alibaba/arthas/releases](https://github.com/alibaba/arthas/releases)
|
||||
|
||||
### 用as.sh启动
|
||||
### 用 as.sh 启动
|
||||
|
||||
解压后,在文件夹里有`as.sh`,直接用`./as.sh`的方式启动:
|
||||
|
||||
@@ -26,7 +24,7 @@
|
||||
./as.sh -h
|
||||
```
|
||||
|
||||
### 用arthas-boot启动
|
||||
### 用 arthas-boot 启动
|
||||
|
||||
或者在解压后,在文件夹里有`arthas-boot.jar`,直接用`java -jar`的方式启动:
|
||||
|
||||
@@ -40,9 +38,6 @@ java -jar arthas-boot.jar
|
||||
java -jar arthas-boot.jar -h
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 下载离线文档
|
||||
|
||||
下载文档:[](https://arthas.aliyun.com/download/doc/latest_version?mirror=aliyun)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# dump
|
||||
|
||||
[`dump`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials?language=cn&id=command-dump)
|
||||
|
||||
::: tip
|
||||
dump 已加载类的 bytecode 到特定目录
|
||||
:::
|
||||
|
||||
### 参数说明
|
||||
|
||||
| 参数名称 | 参数说明 |
|
||||
| --------------------: | :----------------------------------------- |
|
||||
| _class-pattern_ | 类名表达式匹配 |
|
||||
| `[c:]` | 类所属 ClassLoader 的 hashcode |
|
||||
| `[classLoaderClass:]` | 指定执行表达式的 ClassLoader 的 class name |
|
||||
| `[d:]` | 设置类文件的目标目录 |
|
||||
| [E] | 开启正则表达式匹配,默认为通配符匹配 |
|
||||
|
||||
### 使用参考
|
||||
|
||||
```bash
|
||||
$ dump java.lang.String
|
||||
HASHCODE CLASSLOADER LOCATION
|
||||
null /Users/admin/logs/arthas/classdump/java/lang/String.class
|
||||
Affect(row-cnt:1) cost in 119 ms.
|
||||
```
|
||||
|
||||
```bash
|
||||
$ dump demo.*
|
||||
HASHCODE CLASSLOADER LOCATION
|
||||
3d4eac69 +-sun.misc.Launcher$AppClassLoader@3d4eac69 /Users/admin/logs/arthas/classdump/sun.misc.Launcher$AppClassLoader-3d4eac69/demo/MathGame.class
|
||||
+-sun.misc.Launcher$ExtClassLoader@66350f69
|
||||
Affect(row-cnt:1) cost in 39 ms.
|
||||
```
|
||||
|
||||
```bash
|
||||
$ dump -d /tmp/output java.lang.String
|
||||
HASHCODE CLASSLOADER LOCATION
|
||||
null /tmp/output/java/lang/String.class
|
||||
Affect(row-cnt:1) cost in 138 ms.
|
||||
```
|
||||
|
||||
- 指定 classLoader
|
||||
|
||||
注意 hashcode 是变化的,需要先查看当前的 ClassLoader 信息,提取对应 ClassLoader 的 hashcode。
|
||||
|
||||
如果你使用`-c`,你需要手动输入 hashcode:`-c <hashcode>`
|
||||
|
||||
```bash
|
||||
$ dump -c 3d4eac69 demo.*
|
||||
```
|
||||
|
||||
对于只有唯一实例的 ClassLoader 可以通过`--classLoaderClass`指定 class name,使用起来更加方便:
|
||||
|
||||
```bash
|
||||
$ dump --classLoaderClass sun.misc.Launcher$AppClassLoader demo.*
|
||||
HASHCODE CLASSLOADER LOCATION
|
||||
3d4eac69 +-sun.misc.Launcher$AppClassLoader@3d4eac69 /Users/admin/logs/arthas/classdump/sun.misc.Launcher$AppClassLoader-3d4eac69/demo/MathGame.class
|
||||
+-sun.misc.Launcher$ExtClassLoader@66350f69
|
||||
Affect(row-cnt:1) cost in 39 ms.
|
||||
```
|
||||
|
||||
- 注: 这里 classLoaderClass 在 java 8 是 sun.misc.Launcher$AppClassLoader,而java 11的classloader是jdk.internal.loader.ClassLoaders$AppClassLoader,katacoda 目前环境是 java8。
|
||||
|
||||
`--classLoaderClass` 的值是 ClassLoader 的类名,只有匹配到唯一的 ClassLoader 实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
|
||||
@@ -1,11 +1,11 @@
|
||||
echo
|
||||
===
|
||||
# echo
|
||||
|
||||
[`echo`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=command-echo)
|
||||
|
||||
> 打印参数,和linux里的echo命令类似。
|
||||
|
||||
::: tip
|
||||
打印参数,和 linux 里的 echo 命令类似。
|
||||
:::
|
||||
|
||||
```bash
|
||||
$ echo 'hello'
|
||||
```
|
||||
```
|
||||
@@ -1,27 +1,27 @@
|
||||
# FAQ
|
||||
|
||||
## FAQ
|
||||
|
||||
|
||||
> 不在本列表里的问题,请到issue里搜索。 [https://github.com/alibaba/arthas/issues](https://github.com/alibaba/arthas/issues)
|
||||
|
||||
::: tip
|
||||
不在本列表里的问题,请到 issue 里搜索。 [https://github.com/alibaba/arthas/issues](https://github.com/alibaba/arthas/issues)
|
||||
:::
|
||||
|
||||
##### 日志文件在哪里?
|
||||
|
||||
日志文件路径: `~/logs/arthas/arthas.log`
|
||||
##### Arthas attach之后对原进程性能有多大的影响
|
||||
|
||||
##### Arthas attach 之后对原进程性能有多大的影响
|
||||
|
||||
[https://github.com/alibaba/arthas/issues/44](https://github.com/alibaba/arthas/issues/44)
|
||||
|
||||
|
||||
##### target process not responding or HotSpot VM not loaded
|
||||
|
||||
com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded
|
||||
|
||||
1. 检查当前用户和目标java进程是否一致。如果不一致,则切换到同一用户。JVM只能attach同样用户下的java 进程。
|
||||
2. 尝试使用 `jstack -l $pid`,如果进程没有反应,则说明进程可能假死,无法响应JVM attach信号。所以同样基于attach机制的Arthas无法工作。尝试使用`jmap` heapdump后分析。
|
||||
3. 尝试按[quick-start](quick-start.md)里的方式attach math-game。
|
||||
1. 检查当前用户和目标 java 进程是否一致。如果不一致,则切换到同一用户。JVM 只能 attach 同样用户下的 java 进程。
|
||||
2. 尝试使用 `jstack -l $pid`,如果进程没有反应,则说明进程可能假死,无法响应 JVM attach 信号。所以同样基于 attach 机制的 Arthas 无法工作。尝试使用`jmap` heapdump 后分析。
|
||||
3. 尝试按[quick-start](quick-start.md)里的方式 attach math-game。
|
||||
4. 更多情况参考: [https://github.com/alibaba/arthas/issues/347](https://github.com/alibaba/arthas/issues/347)
|
||||
##### trace/watch等命令能否增强jdk里的类?
|
||||
|
||||
##### trace/watch 等命令能否增强 jdk 里的类?
|
||||
|
||||
默认情况下会过滤掉`java.`开头的类和被`BootStrap ClassLoader`加载的类。可以通过参数开启。
|
||||
|
||||
@@ -31,7 +31,9 @@ options unsafe true
|
||||
|
||||
更多参考 [options](options.md)
|
||||
|
||||
> 通过 java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch append到`Bootstrap ClassLoader`的jar包需要开启unsafe。
|
||||
::: tip
|
||||
通过 java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch append 到`Bootstrap ClassLoader`的 jar 包需要开启 unsafe。
|
||||
:::
|
||||
|
||||
##### 怎么以`json`格式查看结果
|
||||
|
||||
@@ -41,18 +43,15 @@ options json-format true
|
||||
|
||||
更多参考 [options](options.md)
|
||||
|
||||
|
||||
##### Arthas能否跟踪 native 函数
|
||||
##### Arthas 能否跟踪 native 函数
|
||||
|
||||
不能。
|
||||
|
||||
|
||||
##### 能不能查看内存里某个变量的值
|
||||
|
||||
1. 可以使用[`vmtool`](vmtool.md)命令。
|
||||
2. 可以用一些技巧,用[`tt`](tt.md)命令拦截到对象,或者从静态函数里取到对象。
|
||||
|
||||
|
||||
##### 方法同名过滤
|
||||
|
||||
同名方法过滤可以通过匹配表达式,可以使用[表达式核心变量](advice-class.md)中所有变量作为已知条件,可以通过判断参数个数`params.length ==1`, 参数类型`params[0] instanceof java.lang.Integer`、返回值类型 `returnObj instanceof java.util.List` 等等一种或者多种组合进行过滤。
|
||||
@@ -63,25 +62,25 @@ options json-format true
|
||||
|
||||
```bash
|
||||
watch demo.MathGame primeFactors '{params,returnObj,throwExp}' 'params.length >0 && returnObj instanceof java.util.List' -v
|
||||
```
|
||||
```
|
||||
|
||||
##### 怎么watch、trace 构造函数 ?
|
||||
##### 怎么 watch、trace 构造函数 ?
|
||||
|
||||
```bash
|
||||
watch demo.MathGame <init> '{params,returnObj,throwExp}' -v
|
||||
```
|
||||
|
||||
##### 怎样watch、trace内部类?
|
||||
##### 怎样 watch、trace 内部类?
|
||||
|
||||
在JVM规范里内部类的格式是`OuterClass$InnerClass`。
|
||||
在 JVM 规范里内部类的格式是`OuterClass$InnerClass`。
|
||||
|
||||
```bash
|
||||
watch OuterClass$InnerClass
|
||||
```
|
||||
|
||||
##### 输入中文/Unicode字符
|
||||
##### 输入中文/Unicode 字符
|
||||
|
||||
把中文/Unicode字符转为`\u`表示方法:
|
||||
把中文/Unicode 字符转为`\u`表示方法:
|
||||
|
||||
```bash
|
||||
ognl '@java.lang.System@out.println("Hello \u4e2d\u6587")'
|
||||
@@ -89,16 +88,15 @@ ognl '@java.lang.System@out.println("Hello \u4e2d\u6587")'
|
||||
|
||||
##### java.lang.ClassFormatError: null、skywalking arthas 兼容使用
|
||||
|
||||
当出现这个错误日志`java.lang.ClassFormatError: null`,通常情况下都是被其他字节码工具修改过与arthas修改字节码不兼容。
|
||||
|
||||
比如: 使用 skywalking V8.1.0 以下版本 [无法trace、watch 被skywalking agent 增强过的类](https://github.com/alibaba/arthas/issues/1141), V8.1.0 以上版本可以兼容使用,更多参考skywalking配置 [skywalking compatible with other javaagent bytecode processing](https://github.com/apache/skywalking/blob/master/docs/en/FAQ/Compatible-with-other-javaagent-bytecode-processing.md#)。
|
||||
当出现这个错误日志`java.lang.ClassFormatError: null`,通常情况下都是被其他字节码工具修改过与 arthas 修改字节码不兼容。
|
||||
|
||||
比如: 使用 skywalking V8.1.0 以下版本 [无法 trace、watch 被 skywalking agent 增强过的类](https://github.com/alibaba/arthas/issues/1141), V8.1.0 以上版本可以兼容使用,更多参考 skywalking 配置 [skywalking compatible with other javaagent bytecode processing](https://github.com/apache/skywalking/blob/master/docs/en/FAQ/Compatible-with-other-javaagent-bytecode-processing.md#)。
|
||||
|
||||
#### class redefinition failed: attempted to change the schema (add/remove fields)
|
||||
|
||||
参考: [https://github.com/alibaba/arthas/issues/2165](https://github.com/alibaba/arthas/issues/2165)
|
||||
|
||||
##### Arthas能不能离线使用
|
||||
##### Arthas 能不能离线使用
|
||||
|
||||
可以。下载全量包解压即可,参考: [下载](download.md)。
|
||||
|
||||
@@ -106,8 +104,8 @@ ognl '@java.lang.System@out.println("Hello \u4e2d\u6587")'
|
||||
|
||||
参考: [https://github.com/alibaba/arthas/issues/362#issuecomment-448185416](https://github.com/alibaba/arthas/issues/362#issuecomment-448185416)
|
||||
|
||||
##### 为什么下载了新版本的Arthas,连接的却是旧版本?
|
||||
##### 为什么下载了新版本的 Arthas,连接的却是旧版本?
|
||||
|
||||
比如启动的 `as.sh/arthas-boot.jar` 版本是3.5.* 的,但是连接上之后,打印的arthas版本是 3.4.* 的。
|
||||
比如启动的 `as.sh/arthas-boot.jar` 版本是 3.5._ 的,但是连接上之后,打印的 arthas 版本是 3.4._ 的。
|
||||
|
||||
可能是之前使用旧版本的arthas诊断过目标进程。可以先执行`stop`停止掉旧版本的arthas,再重新使用新版本attach。
|
||||
可能是之前使用旧版本的 arthas 诊断过目标进程。可以先执行`stop`停止掉旧版本的 arthas,再重新使用新版本 attach。
|
||||
@@ -0,0 +1,70 @@
|
||||
# getstatic
|
||||
|
||||
[`getstatic`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=command-getstatic)
|
||||
|
||||
- 推荐直接使用[ognl](ognl.md)命令,更加灵活。
|
||||
|
||||
通过 getstatic 命令可以方便的查看类的静态属性。使用方法为`getstatic class_name field_name`
|
||||
|
||||
```bash
|
||||
$ getstatic demo.MathGame random
|
||||
field: random
|
||||
@Random[
|
||||
serialVersionUID=@Long[3905348978240129619],
|
||||
seed=@AtomicLong[120955813885284],
|
||||
multiplier=@Long[25214903917],
|
||||
addend=@Long[11],
|
||||
mask=@Long[281474976710655],
|
||||
DOUBLE_UNIT=@Double[1.1102230246251565E-16],
|
||||
BadBound=@String[bound must be positive],
|
||||
BadRange=@String[bound must be greater than origin],
|
||||
BadSize=@String[size must be non-negative],
|
||||
seedUniquifier=@AtomicLong[-3282039941672302964],
|
||||
nextNextGaussian=@Double[0.0],
|
||||
haveNextNextGaussian=@Boolean[false],
|
||||
serialPersistentFields=@ObjectStreamField[][isEmpty=false;size=3],
|
||||
unsafe=@Unsafe[sun.misc.Unsafe@2eaa1027],
|
||||
seedOffset=@Long[24],
|
||||
]
|
||||
```
|
||||
|
||||
- 指定 classLoader
|
||||
|
||||
注意 hashcode 是变化的,需要先查看当前的 ClassLoader 信息,使用`sc -d <ClassName>`提取对应 ClassLoader 的 hashcode。
|
||||
|
||||
如果你使用`-c`,你需要手动输入 hashcode:`-c <hashcode>`
|
||||
|
||||
```bash
|
||||
$ getstatic -c 3d4eac69 demo.MathGame random
|
||||
```
|
||||
|
||||
对于只有唯一实例的 ClassLoader 可以通过`--classLoaderClass`指定 class name,使用起来更加方便:
|
||||
|
||||
`getstatic --classLoaderClass sun.misc.Launcher$AppClassLoader demo.MathGame random`
|
||||
|
||||
- 注: 这里 classLoaderClass 在 java 8 是 sun.misc.Launcher$AppClassLoader,而java 11的classloader是jdk.internal.loader.ClassLoaders$AppClassLoader,katacoda 目前环境是 java8。
|
||||
|
||||
`--classLoaderClass` 的值是 ClassLoader 的类名,只有匹配到唯一的 ClassLoader 实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
|
||||
|
||||
如果该静态属性是一个复杂对象,还可以支持在该属性上通过 ognl 表示进行遍历,过滤,访问对象的内部属性等操作。
|
||||
|
||||
- OGNL 特殊用法请参考:[https://github.com/alibaba/arthas/issues/71](https://github.com/alibaba/arthas/issues/71)
|
||||
- OGNL 表达式官方指南:[https://commons.apache.org/proper/commons-ognl/language-guide.html](https://commons.apache.org/proper/commons-ognl/language-guide.html)
|
||||
|
||||
例如,假设 n 是一个 Map,Map 的 Key 是一个 Enum,我们想过滤出 Map 中 Key 为某个 Enum 的值,可以写如下命令
|
||||
|
||||
```
|
||||
$ getstatic com.alibaba.arthas.Test n 'entrySet().iterator.{? #this.key.name()=="STOP"}'
|
||||
field: n
|
||||
@ArrayList[
|
||||
@Node[STOP=bbb],
|
||||
]
|
||||
Affect(row-cnt:1) cost in 68 ms.
|
||||
|
||||
|
||||
$ getstatic com.alibaba.arthas.Test m 'entrySet().iterator.{? #this.key=="a"}'
|
||||
field: m
|
||||
@ArrayList[
|
||||
@Node[a=aaa],
|
||||
]
|
||||
```
|
||||
@@ -1,10 +1,10 @@
|
||||
grep
|
||||
===
|
||||
# grep
|
||||
|
||||
[`grep`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=command-grep)
|
||||
|
||||
> 类似传统的`grep`命令。
|
||||
|
||||
::: tip
|
||||
类似传统的`grep`命令。
|
||||
:::
|
||||
|
||||
```
|
||||
USAGE:
|
||||
@@ -36,4 +36,4 @@ grep
|
||||
-e, --regex Enable regular expression to match
|
||||
--trim-end Remove whitespaces at the end of the line
|
||||
<pattern> Pattern
|
||||
```
|
||||
```
|
||||
@@ -1,7 +1,8 @@
|
||||
groovy
|
||||
===
|
||||
# groovy
|
||||
|
||||
> Arthas 支持 groovy 脚本增强,允许像 BTrace 一样编写脚本来解决问题,可以在 groovy 脚本中进行if/for/switch/while 等控制语句,不受限制,但相比 BTrace 而言拥有更多的限制范围。
|
||||
::: tip
|
||||
Arthas 支持 groovy 脚本增强,允许像 BTrace 一样编写脚本来解决问题,可以在 groovy 脚本中进行 if/for/switch/while 等控制语句,不受限制,但相比 BTrace 而言拥有更多的限制范围。
|
||||
:::
|
||||
|
||||
### 限制内容
|
||||
|
||||
@@ -10,16 +11,16 @@ groovy
|
||||
|
||||
### 参数说明
|
||||
|
||||
|参数名称|参数说明|
|
||||
|---:|:---|
|
||||
|*class-pattern*|类名表达式匹配|
|
||||
|*method-pattern*|方法名表达式匹配|
|
||||
|*script-filepath*|groovy 脚本的绝对路径|
|
||||
|[S]|匹配所有的子类|
|
||||
|[E]|开启正则表达式匹配,默认为通配符匹配|
|
||||
| 参数名称 | 参数说明 |
|
||||
| ----------------: | :----------------------------------- |
|
||||
| _class-pattern_ | 类名表达式匹配 |
|
||||
| _method-pattern_ | 方法名表达式匹配 |
|
||||
| _script-filepath_ | groovy 脚本的绝对路径 |
|
||||
| [S] | 匹配所有的子类 |
|
||||
| [E] | 开启正则表达式匹配,默认为通配符匹配 |
|
||||
|
||||
需要说明的是,第三个输入参数是脚本的绝对路径,比如 `/tmp/test.groovy`,不建议输入相对路径,比如 `./test.groovy`
|
||||
|
||||
|
||||
### 五个关键函数声明
|
||||
|
||||
```java
|
||||
@@ -1,14 +1,14 @@
|
||||
heapdump
|
||||
===
|
||||
# heapdump
|
||||
|
||||
[`heapdump`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=command-heapdump)
|
||||
|
||||
> dump java heap, 类似jmap命令的heap dump功能。
|
||||
|
||||
::: tip
|
||||
dump java heap, 类似 jmap 命令的 heap dump 功能。
|
||||
:::
|
||||
|
||||
### 使用参考
|
||||
|
||||
#### dump到指定文件
|
||||
#### dump 到指定文件
|
||||
|
||||
```bash
|
||||
[arthas@58205]$ heapdump /tmp/dump.hprof
|
||||
@@ -16,7 +16,7 @@ Dumping heap to /tmp/dump.hprof...
|
||||
Heap dump file created
|
||||
```
|
||||
|
||||
#### 只dump live对象
|
||||
#### 只 dump live 对象
|
||||
|
||||
```bash
|
||||
[arthas@58205]$ heapdump --live /tmp/dump.hprof
|
||||
@@ -24,13 +24,10 @@ Dumping heap to /tmp/dump.hprof...
|
||||
Heap dump file created
|
||||
```
|
||||
|
||||
### dump到临时文件
|
||||
### dump 到临时文件
|
||||
|
||||
```bash
|
||||
[arthas@58205]$ heapdump
|
||||
Dumping heap to /var/folders/my/wy7c9w9j5732xbkcyt1mb4g40000gp/T/heapdump2019-09-03-16-385121018449645518991.hprof...
|
||||
Heap dump file created
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
help
|
||||
===
|
||||
# help
|
||||
|
||||
查看命令帮助信息,可以查看当前arthas版本支持的指令,或者查看具体指令的使用说明。
|
||||
查看命令帮助信息,可以查看当前 arthas 版本支持的指令,或者查看具体指令的使用说明。
|
||||
|
||||
> [help 指令]的等同于[指令 -help],都是查看具体指令的使用说明。
|
||||
::: tip
|
||||
[help 指令]的等同于[指令 -help],都是查看具体指令的使用说明。
|
||||
:::
|
||||
|
||||
### 参数说明
|
||||
|
||||
| 参数名称 | 参数说明 |
|
||||
| -------: | :--------------------------------------- |
|
||||
| 不接参数 | 查询当前arthas版本支持的指令以及指令描述 |
|
||||
| [name:] | 查询具体指令的使用说明 |
|
||||
| 参数名称 | 参数说明 |
|
||||
| -------: | :----------------------------------------- |
|
||||
| 不接参数 | 查询当前 arthas 版本支持的指令以及指令描述 |
|
||||
| [name:] | 查询具体指令的使用说明 |
|
||||
|
||||
### 使用参考
|
||||
|
||||
@@ -59,8 +60,8 @@ $ help
|
||||
tee tee command for pipes.
|
||||
profiler Async Profiler. https://github.com/jvm-profiling-tools/async-profiler
|
||||
stop Stop/Shutdown Arthas server and exit the console.
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
@@ -84,4 +85,3 @@ $ help
|
||||
-i, --interval <value> The interval (in ms) between two executions, default is 5000 ms.
|
||||
-n, --number-of-execution <value> The number of times this command will be executed.
|
||||
```
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# history
|
||||
|
||||
打印命令历史。
|
||||
|
||||
::: tip
|
||||
历史指令会通过一个名叫 history 的文件持久化,所以 history 指令可以查看当前 arthas 服务器的所有历史命令,而不仅只是当前次会话使用过的命令。
|
||||
:::
|
||||
|
||||
### 参数说明
|
||||
|
||||
| 参数名称 | 参数说明 |
|
||||
| -------: | :---------------------- |
|
||||
| [c:] | 清空历史指令 |
|
||||
| [n:] | 显示最近执行的 n 条指令 |
|
||||
|
||||
### 使用参考
|
||||
|
||||
```
|
||||
#查看最近执行的3条指令
|
||||
$ history 3
|
||||
269 thread
|
||||
270 cls
|
||||
271 history 3
|
||||
```
|
||||
|
||||
```
|
||||
#清空指令
|
||||
$ history -c
|
||||
$ history 3
|
||||
1 history 3
|
||||
```
|
||||
@@ -0,0 +1,684 @@
|
||||
# Http API
|
||||
|
||||
[`Http API`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=case-http-api)
|
||||
|
||||
### 概览
|
||||
|
||||
Http API
|
||||
提供类似 RESTful 的交互接口,请求和响应均为 JSON 格式的数据。相对于 Telnet/WebConsole 的输出非结构化文本数据,Http
|
||||
API 可以提供结构化的数据,支持更复杂的交互功能,比如特定应用场景的一系列诊断操作。
|
||||
|
||||
#### 访问地址
|
||||
|
||||
Http API 接口地址为:`http://ip:port/api`,必须使用 POST 方式提交请求参数。如 POST
|
||||
`http://127.0.0.1:8563/api` 。
|
||||
|
||||
注意:telnet 服务的 3658 端口与 Chrome 浏览器有兼容性问题,建议使用 http 端口 8563 来访问 http 接口。
|
||||
|
||||
#### 请求数据格式
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "exec",
|
||||
"requestId": "req112",
|
||||
"sessionId": "94766d3c-8b39-42d3-8596-98aee3ccbefb",
|
||||
"consumerId": "955dbd1325334a84972b0f3ac19de4f7_2",
|
||||
"command": "version",
|
||||
"execTimeout": "10000"
|
||||
}
|
||||
```
|
||||
|
||||
请求数据格式说明:
|
||||
|
||||
- `action` : 请求的动作/行为,可选值请参考"请求 Action"小节。
|
||||
- `requestId` : 可选请求 ID,由客户端生成。
|
||||
- `sessionId` : Arthas 会话 ID,一次性命令不需要设置会话 ID。
|
||||
- `consumerId` : Arthas 消费者 ID,用于多人共享会话。
|
||||
- `command` : Arthas command line 。
|
||||
- `execTimeout` : 命令同步执行的超时时间(ms),默认为 30000。
|
||||
|
||||
注意: 不同的 action 使用到参数不同,根据具体的 action 来设置参数。
|
||||
|
||||
#### 请求 Action
|
||||
|
||||
目前支持的请求 Action 如下:
|
||||
|
||||
- `exec` : 同步执行命令,命令正常结束或者超时后中断命令执行后返回命令的执行结果。
|
||||
- `async_exec` : 异步执行命令,立即返回命令的调度结果,命令执行结果通过`pull_results`获取。
|
||||
- `interrupt_job` : 中断会话当前的命令,类似 Telnet `Ctrl + c`的功能。
|
||||
- `pull_results` : 获取异步执行的命令的结果,以 http 长轮询(long-polling)方式重复执行
|
||||
- `init_session` : 创建会话
|
||||
- `join_session` : 加入会话,用于支持多人共享同一个 Arthas 会话
|
||||
- `close_session` : 关闭会话
|
||||
|
||||
#### 响应状态
|
||||
|
||||
响应中的 state 属性表示请求处理状态,取值如下:
|
||||
|
||||
- `SCHEDULED`:异步执行命令时表示已经创建 job 并已提交到命令执行队列,命令可能还没开始执行或者执行中;
|
||||
- `SUCCEEDED`:请求处理成功(完成状态);
|
||||
- `FAILED`:请求处理失败(完成状态),通常附带 message 说明原因;
|
||||
- `REFUSED`:请求被拒绝(完成状态),通常附带 message 说明原因;
|
||||
|
||||
### 一次性命令
|
||||
|
||||
与执行批处理命令类似,一次性命令以同步方式执行。不需要创建会话,不需要设置`sessionId`选项。
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "exec",
|
||||
"command": "<Arthas command line>"
|
||||
}
|
||||
```
|
||||
|
||||
比如获取 Arthas 版本号:
|
||||
|
||||
```bash
|
||||
curl -Ss -XPOST http://localhost:8563/api -d '
|
||||
{
|
||||
"action":"exec",
|
||||
"command":"version"
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
响应内容如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"state": "SUCCEEDED",
|
||||
"sessionId": "ee3bc004-4586-43de-bac0-b69d6db7a869",
|
||||
"body": {
|
||||
"results": [
|
||||
{
|
||||
"type": "version",
|
||||
"version": "3.3.7",
|
||||
"jobId": 5
|
||||
},
|
||||
{
|
||||
"jobId": 5,
|
||||
"statusCode": 0,
|
||||
"type": "status"
|
||||
}
|
||||
],
|
||||
"timeExpired": false,
|
||||
"command": "version",
|
||||
"jobStatus": "TERMINATED",
|
||||
"jobId": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
响应数据解析:
|
||||
|
||||
- `state`: 请求处理状态,参考“接口响应状态”说明
|
||||
- `sessionId `: Arthas 会话 ID,一次性命令自动创建及销毁临时会话
|
||||
- `body.jobId`: 命令的任务 ID,同一任务输出的所有 Result 都是相同的 jobId
|
||||
- `body.jobStatus`: 任务状态,同步执行正常结束为`TERMINATED `
|
||||
- `body.timeExpired`: 任务执行是否超时
|
||||
- `body/results`: 命令执行的结果列表
|
||||
|
||||
**命令结果格式说明**
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "version",
|
||||
"version": "3.3.7",
|
||||
"jobId": 5
|
||||
},
|
||||
{
|
||||
"jobId": 5,
|
||||
"statusCode": 0,
|
||||
"type": "status"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
- `type` : 命令结果类型,除了`status`等特殊的几个外,其它的保持与 Arthas 命令名称一致。请参考"[特殊命令结果](#special_command_results)"小节。
|
||||
- `jobId` : 处理命令的任务 ID。
|
||||
- 其它字段为每个不同命令的数据。
|
||||
|
||||
注意:也可以使用一次性命令的方式执行 watch/trace 等连续输出的命令,但不能中断命令执行,可能出现长时间没有结束的问题。请参考"[watch 命令输出 map 对象](#change_watch_value_to_map)"小节的示例。
|
||||
|
||||
请尽量按照以下方式处理:
|
||||
|
||||
- 设置合理的`execTimeout`,到达超时时间后强制中断命令执行,避免长时间挂起。
|
||||
- 通过`-n`参数指定较少的执行次数。
|
||||
- 保证命令匹配的方法可以成功命中和 condition-express 编写正确,如果 watch/trace 没有命中就算指定`-n 1`也会挂起等待到执行超时。
|
||||
|
||||
### 会话交互
|
||||
|
||||
由用户创建及管理 Arthas 会话,适用于复杂的交互过程。访问流程如下:
|
||||
|
||||
- 创建会话
|
||||
- 加入会话(可选)
|
||||
- 拉取命令结果
|
||||
- 执行一系列命令
|
||||
- 中断命令执行
|
||||
- 关闭会话
|
||||
|
||||
#### 创建会话
|
||||
|
||||
```bash
|
||||
curl -Ss -XPOST http://localhost:8563/api -d '
|
||||
{
|
||||
"action":"init_session"
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
响应结果:
|
||||
|
||||
```json
|
||||
{
|
||||
"sessionId": "b09f1353-202c-407b-af24-701b744f971e",
|
||||
"consumerId": "5ae4e5fbab8b4e529ac404f260d4e2d1_1",
|
||||
"state": "SUCCEEDED"
|
||||
}
|
||||
```
|
||||
|
||||
当前会话 ID 为: `b09f1353-202c-407b-af24-701b744f971e`, 当前消费者 ID 为:`5ae4e5fbab8b4e529ac404f260d4e2d1_1 `。
|
||||
|
||||
#### 加入会话
|
||||
|
||||
指定要加入的会话 ID,服务端将分配一个新的消费者 ID。多个消费者可以接收到同一个会话的命令结果。本接口用于支持多人共享同一个会话或刷新页面后重新拉取会话历史记录。
|
||||
|
||||
```bash
|
||||
curl -Ss -XPOST http://localhost:8563/api -d '
|
||||
{
|
||||
"action":"join_session",
|
||||
"sessionId" : "b09f1353-202c-407b-af24-701b744f971e"
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
响应结果:
|
||||
|
||||
```json
|
||||
{
|
||||
"consumerId": "8f7f6ad7bc2d4cb5aa57a530927a95cc_2",
|
||||
"sessionId": "b09f1353-202c-407b-af24-701b744f971e",
|
||||
"state": "SUCCEEDED"
|
||||
}
|
||||
```
|
||||
|
||||
新的消费者 ID 为`8f7f6ad7bc2d4cb5aa57a530927a95cc_2 ` 。
|
||||
|
||||
#### 拉取命令结果
|
||||
|
||||
拉取命令结果消息的 action 为`pull_results`。请使用 Http long-polling 方式,定时循环拉取结果消息。
|
||||
消费者的超时时间为 5 分钟,超时后需要调用`join_session`分配新的消费者。每个消费者单独分配一个缓存队列,按顺序拉取命令结果,不会影响到其它消费者。
|
||||
|
||||
请求参数需要指定会话 ID 及消费者 ID:
|
||||
|
||||
```bash
|
||||
curl -Ss -XPOST http://localhost:8563/api -d '
|
||||
{
|
||||
"action":"pull_results",
|
||||
"sessionId" : "b09f1353-202c-407b-af24-701b744f971e",
|
||||
"consumerId" : "8f7f6ad7bc2d4cb5aa57a530927a95cc_2"
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
用 Bash 脚本定时拉取结果消息:
|
||||
|
||||
```bash
|
||||
while true; do curl -Ss -XPOST http://localhost:8563/api -d '
|
||||
{
|
||||
"action":"pull_results",
|
||||
"sessionId" : "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a",
|
||||
"consumerId" : "8ecb9cb7c7804d5d92e258b23d5245cc_1"
|
||||
}
|
||||
' | json_pp; sleep 2; done
|
||||
```
|
||||
|
||||
注: `json_pp` 工具将输出内容格式化为 pretty json。
|
||||
|
||||
响应内容如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"body": {
|
||||
"results": [
|
||||
{
|
||||
"inputStatus": "DISABLED",
|
||||
"jobId": 0,
|
||||
"type": "input_status"
|
||||
},
|
||||
{
|
||||
"type": "message",
|
||||
"jobId": 0,
|
||||
"message": "Welcome to arthas!"
|
||||
},
|
||||
{
|
||||
"tutorials": "https://arthas.aliyun.com/doc/arthas-tutorials.html",
|
||||
"time": "2020-08-06 15:56:43",
|
||||
"type": "welcome",
|
||||
"jobId": 0,
|
||||
"pid": "7909",
|
||||
"wiki": "https://arthas.aliyun.com/doc",
|
||||
"version": "3.3.7"
|
||||
},
|
||||
{
|
||||
"inputStatus": "ALLOW_INPUT",
|
||||
"type": "input_status",
|
||||
"jobId": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionId": "b09f1353-202c-407b-af24-701b744f971e",
|
||||
"consumerId": "8f7f6ad7bc2d4cb5aa57a530927a95cc_2",
|
||||
"state": "SUCCEEDED"
|
||||
}
|
||||
```
|
||||
|
||||
#### 异步执行命令
|
||||
|
||||
```bash
|
||||
curl -Ss -XPOST http://localhost:8563/api -d '''
|
||||
{
|
||||
"action":"async_exec",
|
||||
"command":"watch demo.MathGame primeFactors \"{params, returnObj, throwExp}\" ",
|
||||
"sessionId" : "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a"
|
||||
}
|
||||
'''
|
||||
```
|
||||
|
||||
`async_exec` 的结果:
|
||||
|
||||
```json
|
||||
{
|
||||
"sessionId": "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a",
|
||||
"state": "SCHEDULED",
|
||||
"body": {
|
||||
"jobStatus": "READY",
|
||||
"jobId": 3,
|
||||
"command": "watch demo.MathGame primeFactors \"{params, returnObj, throwExp}\" "
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `state` : `SCHEDULED` 状态表示已经解析命令生成任务,但未开始执行。
|
||||
- `body.jobId` :
|
||||
异步执行命令的任务 ID,可以根据此任务 ID 来过滤在`pull_results`输出的命令结果。
|
||||
- `body.jobStatus` : 任务状态`READY`表示未开始执行。
|
||||
|
||||
查看上面自动拉取结果消息脚本的 shell 输出:
|
||||
|
||||
```json
|
||||
{
|
||||
"body" : {
|
||||
"results" : [
|
||||
{
|
||||
"type" : "command",
|
||||
"jobId" : 3,
|
||||
"state" : "SCHEDULED",
|
||||
"command" : "watch demo.MathGame primeFactors \"{params, returnObj, throwExp}\" "
|
||||
},
|
||||
{
|
||||
"inputStatus" : "ALLOW_INTERRUPT",
|
||||
"jobId" : 0,
|
||||
"type" : "input_status"
|
||||
},
|
||||
{
|
||||
"success" : true,
|
||||
"jobId" : 3,
|
||||
"effect" : {
|
||||
"listenerId" : 3,
|
||||
"cost" : 24,
|
||||
"classCount" : 1,
|
||||
"methodCount" : 1
|
||||
},
|
||||
"type" : "enhancer"
|
||||
},
|
||||
{
|
||||
"sizeLimit" : 10485760,
|
||||
"expand" : 1,
|
||||
"jobId" : 3,
|
||||
"type" : "watch",
|
||||
"cost" : 0.071499,
|
||||
"ts" : 1596703453237,
|
||||
"value" : [
|
||||
[
|
||||
-170365
|
||||
],
|
||||
null,
|
||||
{
|
||||
"stackTrace" : [
|
||||
{
|
||||
"className" : "demo.MathGame",
|
||||
"classLoaderName" : "app",
|
||||
"methodName" : "primeFactors",
|
||||
"nativeMethod" : false,
|
||||
"lineNumber" : 46,
|
||||
"fileName" : "MathGame.java"
|
||||
},
|
||||
...
|
||||
],
|
||||
"localizedMessage" : "number is: -170365, need >= 2",
|
||||
"@type" : "java.lang.IllegalArgumentException",
|
||||
"message" : "number is: -170365, need >= 2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type" : "watch",
|
||||
"cost" : 0.033375,
|
||||
"jobId" : 3,
|
||||
"ts" : 1596703454241,
|
||||
"value" : [
|
||||
[
|
||||
1
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
13,
|
||||
491
|
||||
],
|
||||
null
|
||||
],
|
||||
"sizeLimit" : 10485760,
|
||||
"expand" : 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"consumerId" : "8ecb9cb7c7804d5d92e258b23d5245cc_1",
|
||||
"sessionId" : "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a",
|
||||
"state" : "SUCCEEDED"
|
||||
}
|
||||
```
|
||||
|
||||
watch 命令结果的`value`为 watch-experss 的值,上面命令中为`{params, returnObj, throwExp}`,所以 watch 结果的 value 为一个长度为 3 的数组,每个元素分别对应相应顺序的表达式。
|
||||
请参考"[watch 命令输出 map 对象](#change_watch_value_to_map)"小节。
|
||||
|
||||
#### 中断命令执行
|
||||
|
||||
中断会话正在运行的前台 Job(前台任务):
|
||||
|
||||
```bash
|
||||
curl -Ss -XPOST http://localhost:8563/api -d '''
|
||||
{
|
||||
"action":"interrupt_job",
|
||||
"sessionId" : "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a"
|
||||
}
|
||||
'''
|
||||
```
|
||||
|
||||
```
|
||||
{
|
||||
"state" : "SUCCEEDED",
|
||||
"body" : {
|
||||
"jobStatus" : "TERMINATED",
|
||||
"jobId" : 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 关闭会话
|
||||
|
||||
指定会话 ID,关闭会话。
|
||||
|
||||
```bash
|
||||
curl -Ss -XPOST http://localhost:8563/api -d '''
|
||||
{
|
||||
"action":"close_session",
|
||||
"sessionId" : "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a"
|
||||
}
|
||||
'''
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"state": "SUCCEEDED"
|
||||
}
|
||||
```
|
||||
|
||||
### 鉴权
|
||||
|
||||
参考: [auth](auth.md)
|
||||
|
||||
### Web UI
|
||||
|
||||

|
||||
|
||||
一个基于 Http API 接口实现的 Web UI,访问地址为: [http://127.0.0.1:8563/ui](http://127.0.0.1:8563/ui) 。
|
||||
|
||||
已实现功能:
|
||||
|
||||
- 创建会话
|
||||
- 复制并打开 url 加入会话,多人共享会话
|
||||
- 周期性拉取会话命令结果消息
|
||||
- 刷新页面或者加入会话拉取会话历史命令消息
|
||||
- 输入命令/中断命令状态控制
|
||||
|
||||
待开发功能:
|
||||
|
||||
- 改进将命令结果消息可读性
|
||||
- 命令输入支持自动完成及命令模板
|
||||
- 提供命令帮助
|
||||
- 支持个人选项设置
|
||||
|
||||
<a id="special_command_results"></a>
|
||||
|
||||
### 特殊命令结果
|
||||
|
||||
#### status
|
||||
|
||||
```json
|
||||
{
|
||||
"jobId": 5,
|
||||
"statusCode": 0,
|
||||
"type": "status"
|
||||
}
|
||||
```
|
||||
|
||||
`type`为`status`表示命令执行状态:
|
||||
|
||||
每个命令执行结束后都有唯一一个 status 结果。`statusCode`
|
||||
为 0 表示执行成功,`statusCode` 为非 0 值表示执行失败,类似进程退出码(exit code)。
|
||||
|
||||
命令执行失败时一般会提供错误消息,如:
|
||||
|
||||
```json
|
||||
{
|
||||
"jobId": 3,
|
||||
"message": "The argument 'class-pattern' is required",
|
||||
"statusCode": -10,
|
||||
"type": "status"
|
||||
}
|
||||
```
|
||||
|
||||
#### input_status
|
||||
|
||||
```json
|
||||
{
|
||||
"inputStatus": "ALLOW_INPUT",
|
||||
"type": "input_status",
|
||||
"jobId": 0
|
||||
}
|
||||
```
|
||||
|
||||
`type`为`input_status`表示输入状态:
|
||||
|
||||
用于 UI 交互时控制用户输入,每次执行命令前后会发送改变的消息。
|
||||
`inputStatus` 的值说明:
|
||||
|
||||
- `ALLOW_INPUT` :
|
||||
允许用户输入命令,表示会话没有在执行的前台命令,可以接受新的命令。
|
||||
- `ALLOW_INTERRUPT` :
|
||||
允许用户中断命令执行,表示当前正在执行命令,用户可以发送`interrupt_job`中断执行。
|
||||
- `DISABLED` : 禁用状态,不能输入命令也不能中断命令。
|
||||
|
||||
#### command
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "command",
|
||||
"jobId": 3,
|
||||
"state": "SCHEDULED",
|
||||
"command": "watch demo.MathGame primeFactors \"{params, returnObj, throwExp}\" "
|
||||
}
|
||||
```
|
||||
|
||||
`type` 为`command`表示输入的命令数据:
|
||||
|
||||
用于交互 UI 回显用户输入的命令,拉取的会话命令消息历史会包含`command`类型的消息,按顺序处理即可。
|
||||
|
||||
#### enhancer
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"jobId": 3,
|
||||
"effect": {
|
||||
"listenerId": 3,
|
||||
"cost": 24,
|
||||
"classCount": 1,
|
||||
"methodCount": 1
|
||||
},
|
||||
"type": "enhancer"
|
||||
}
|
||||
```
|
||||
|
||||
`type`为`enhancer`表示类增强结果:
|
||||
|
||||
`trace/watch/jad/tt`等命令需要对类进行增强,会接收到这个`enhancer`结果。可能出现`enhancer`结果成功,但没有命中方法的情况,客户端可以根据`enhancer`结果提示用户。
|
||||
|
||||
### 案例
|
||||
|
||||
#### 获取 Java 应用的 Classpath
|
||||
|
||||
通过 Http api 查询 Java 应用的 System properties,提取`java.class.path`的值。
|
||||
|
||||
```bash
|
||||
json_data=$(curl -Ss -XPOST http://localhost:8563/api -d '
|
||||
{
|
||||
"action":"exec",
|
||||
"command":"sysprop"
|
||||
}')
|
||||
```
|
||||
|
||||
- 使用`sed`提取值:
|
||||
|
||||
```bash
|
||||
class_path=$(echo $json_data | tr -d '\n' | sed 's/.*"java.class.path":"\([^"]*\).*/\1/')
|
||||
echo "classpath: $class_path"
|
||||
```
|
||||
|
||||
- 使用`json_pp/awk`提取值
|
||||
|
||||
```bash
|
||||
class_path=$(echo $json_data | tr -d '\n' | json_pp | grep java.class.path | awk -F'"' '{ print $4 }')
|
||||
echo "classpath: $class_path"
|
||||
```
|
||||
|
||||
输出内容:
|
||||
|
||||
```
|
||||
classpath: demo-arthas-spring-boot.jar
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
- `echo $json_data | tr -d '\n'` : 删除换行符(`line.separator`的值),避免影响`sed`/`json_pp`命令处理。
|
||||
- `awk -F'"' '{ print $4 }'` : 使用双引号作为分隔符号
|
||||
|
||||
<a id="change_watch_value_to_map"></a>
|
||||
|
||||
#### watch 命令输出 map 对象
|
||||
|
||||
watch 的结果值由计算`watch-express` ognl 表达式产生,可以通过改变 ognl 表达式来生成想要的值,请参考[OGNL 文档](https://commons.apache.org/proper/commons-ognl/language-guide.html)。
|
||||
|
||||
::: tip
|
||||
Maps can also be created using a special syntax.
|
||||
|
||||
#{ "foo" : "foo value", "bar" : "bar value" }
|
||||
|
||||
This creates a Map initialized with mappings for "foo" and "bar".
|
||||
:::
|
||||
|
||||
下面的命令生成 map 格式的值:
|
||||
|
||||
```bash
|
||||
watch *MathGame prime* '#{ "params" : params, "returnObj" : returnObj, "throwExp": throwExp}' -x 2 -n 5
|
||||
```
|
||||
|
||||
在 Telnet shell/WebConsole 中执行上面的命令,输出的结果:
|
||||
|
||||
```bash
|
||||
ts=2020-08-06 16:57:20; [cost=0.241735ms] result=@LinkedHashMap[
|
||||
@String[params]:@Object[][
|
||||
@Integer[1],
|
||||
],
|
||||
@String[returnObj]:@ArrayList[
|
||||
@Integer[2],
|
||||
@Integer[241],
|
||||
@Integer[379],
|
||||
],
|
||||
@String[throwExp]:null,
|
||||
]
|
||||
```
|
||||
|
||||
用 Http api 执行上面的命令,注意对 JSON 双引号转义:
|
||||
|
||||
```bash
|
||||
curl -Ss -XPOST http://localhost:8563/api -d @- << EOF
|
||||
{
|
||||
"action":"exec",
|
||||
"execTimeout": 30000,
|
||||
"command":"watch *MathGame prime* '#{ \"params\" : params, \"returnObj\" : returnObj, \"throwExp\": throwExp}' -n 3 "
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
Http api 执行结果:
|
||||
|
||||
```json
|
||||
{
|
||||
"body": {
|
||||
...
|
||||
"results": [
|
||||
...
|
||||
{
|
||||
...
|
||||
"type": "watch",
|
||||
"value": {
|
||||
"params": [
|
||||
1
|
||||
],
|
||||
"returnObj": [
|
||||
2,
|
||||
5,
|
||||
17,
|
||||
23,
|
||||
23
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
...
|
||||
"type": "watch",
|
||||
"value": {
|
||||
"params": [
|
||||
-98278
|
||||
],
|
||||
"throwExp": {
|
||||
"@type": "java.lang.IllegalArgumentException",
|
||||
"localizedMessage": "number is: -98278, need >= 2",
|
||||
"message": "number is: -98278, need >= 2",
|
||||
"stackTrace": [
|
||||
...
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
可以看到 watch 结果的 value 变成 map 对象,程序可以通过 key 读取结果。
|
||||
@@ -0,0 +1,23 @@
|
||||
# IDEA Plugin
|
||||
|
||||
#### Arthas-idea(部分命令可视化)
|
||||
|
||||
::: tip
|
||||
插件由社区开发者提供。
|
||||
:::
|
||||
|
||||
- Jetbrains 插件获取地址: [https://plugins.jetbrains.com/plugin/13581-arthas-idea](https://plugins.jetbrains.com/plugin/13581-arthas-idea)
|
||||
- 使用文档:[https://www.yuque.com/arthas-idea-plugin](https://www.yuque.com/arthas-idea-plugin)
|
||||
- 源码地址: [https://github.com/WangJi92/arthas-idea-plugin](https://github.com/WangJi92/arthas-idea-plugin)
|
||||
|
||||
#### Alibaba Cloud Toolkit 热部署组件(一键 retransform)
|
||||
|
||||
::: tip
|
||||
热部署组件支持一键将编辑器中修改的 Java 源码快速编译,并更新到远端应用服务中,免去手动 dump、mc 的过程。此外,也可以一键还原 retransform 的类文件。
|
||||
:::
|
||||
|
||||

|
||||
|
||||
- Jetbrains 插件获取地址: [https://plugins.jetbrains.com/plugin/11386-alibaba-cloud-toolkit](https://plugins.jetbrains.com/plugin/11386-alibaba-cloud-toolkit)
|
||||
- 使用文档:[https://help.aliyun.com/document_detail/381077.html](https://help.aliyun.com/document_detail/381077.html)
|
||||
- 联系我们:请加 Alibaba Cloud Toolkit (应用观测器) 钉钉用户交流群(群号:**34965379**)
|
||||
@@ -1,5 +1,4 @@
|
||||
Arthas Install
|
||||
=============
|
||||
# Arthas Install
|
||||
|
||||
## 快速安装
|
||||
|
||||
@@ -18,11 +17,11 @@ java -jar arthas-boot.jar
|
||||
java -jar arthas-boot.jar -h
|
||||
```
|
||||
|
||||
* 如果下载速度比较慢,可以使用aliyun的镜像:
|
||||
- 如果下载速度比较慢,可以使用 aliyun 的镜像:
|
||||
|
||||
```bash
|
||||
java -jar arthas-boot.jar --repo-mirror aliyun --use-http
|
||||
```
|
||||
```bash
|
||||
java -jar arthas-boot.jar --repo-mirror aliyun --use-http
|
||||
```
|
||||
|
||||
### 使用`as.sh`
|
||||
|
||||
@@ -34,7 +33,7 @@ curl -L https://arthas.aliyun.com/install.sh | sh
|
||||
|
||||
上述命令会下载启动脚本文件 `as.sh` 到当前目录,你可以放在任何地方或将其加入到 `$PATH` 中。
|
||||
|
||||
直接在shell下面执行`./as.sh`,就会进入交互界面。
|
||||
直接在 shell 下面执行`./as.sh`,就会进入交互界面。
|
||||
|
||||
也可以执行`./as.sh -h`来获取更多参数信息。
|
||||
|
||||
@@ -54,29 +53,27 @@ java -jar arthas-boot.jar
|
||||
java -jar arthas-boot.jar -h
|
||||
```
|
||||
|
||||
|
||||
## 手动安装
|
||||
|
||||
[手动安装](manual-install.md)
|
||||
|
||||
## 通过 rpm/deb 来安装
|
||||
|
||||
在 releases 页面下载 rpm/deb 包: https://github.com/alibaba/arthas/releases
|
||||
|
||||
## 通过rpm/deb来安装
|
||||
|
||||
在releases页面下载rpm/deb包: https://github.com/alibaba/arthas/releases
|
||||
|
||||
### 安装deb
|
||||
### 安装 deb
|
||||
|
||||
```bash
|
||||
sudo dpkg -i arthas*.deb
|
||||
```
|
||||
### 安装rpm
|
||||
|
||||
### 安装 rpm
|
||||
|
||||
```bash
|
||||
sudo rpm -i arthas*.rpm
|
||||
```
|
||||
|
||||
### deb/rpm安装的用法
|
||||
### deb/rpm 安装的用法
|
||||
|
||||
在安装后,可以直接执行:
|
||||
|
||||
@@ -84,9 +81,9 @@ sudo rpm -i arthas*.rpm
|
||||
as.sh
|
||||
```
|
||||
|
||||
## 通过Cloud Toolkit插件使用Arthas
|
||||
## 通过 Cloud Toolkit 插件使用 Arthas
|
||||
|
||||
* [通过Cloud Toolkit插件使用Arthas一键诊断远程服务器](https://github.com/alibaba/arthas/issues/570)
|
||||
- [通过 Cloud Toolkit 插件使用 Arthas 一键诊断远程服务器](https://github.com/alibaba/arthas/issues/570)
|
||||
|
||||
## 离线帮助文档
|
||||
|
||||
@@ -94,12 +91,13 @@ as.sh
|
||||
|
||||
## 卸载
|
||||
|
||||
* 在 Linux/Unix/Mac 平台
|
||||
- 在 Linux/Unix/Mac 平台
|
||||
|
||||
删除下面文件:
|
||||
```bash
|
||||
rm -rf ~/.arthas/
|
||||
rm -rf ~/logs/arthas
|
||||
```
|
||||
删除下面文件:
|
||||
|
||||
* Windows平台直接删除user home下面的`.arthas`和`logs/arthas`目录
|
||||
```bash
|
||||
rm -rf ~/.arthas/
|
||||
rm -rf ~/logs/arthas
|
||||
```
|
||||
|
||||
- Windows 平台直接删除 user home 下面的`.arthas`和`logs/arthas`目录
|
||||
@@ -1,23 +1,24 @@
|
||||
jad
|
||||
===
|
||||
# jad
|
||||
|
||||
[`jad`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials?language=cn&id=command-jad)
|
||||
|
||||
> 反编译指定已加载类的源码
|
||||
::: tip
|
||||
反编译指定已加载类的源码
|
||||
:::
|
||||
|
||||
`jad` 命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑;
|
||||
|
||||
* 在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便
|
||||
* 当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解
|
||||
- 在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便
|
||||
- 当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解
|
||||
|
||||
### 参数说明
|
||||
|
||||
|参数名称|参数说明|
|
||||
|---:|:---|
|
||||
|*class-pattern*|类名表达式匹配|
|
||||
|`[c:]`|类所属 ClassLoader 的 hashcode|
|
||||
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|
||||
|[E]|开启正则表达式匹配,默认为通配符匹配|
|
||||
| 参数名称 | 参数说明 |
|
||||
| --------------------: | :----------------------------------------- |
|
||||
| _class-pattern_ | 类名表达式匹配 |
|
||||
| `[c:]` | 类所属 ClassLoader 的 hashcode |
|
||||
| `[classLoaderClass:]` | 指定执行表达式的 ClassLoader 的 class name |
|
||||
| [E] | 开启正则表达式匹配,默认为通配符匹配 |
|
||||
|
||||
### 使用参考
|
||||
|
||||
@@ -106,7 +107,7 @@ Location:
|
||||
|
||||
#### 反编译时不显示行号
|
||||
|
||||
`--lineNumber` 参数默认值为true,显示指定为false则不打印行号。
|
||||
`--lineNumber` 参数默认值为 true,显示指定为 false 则不打印行号。
|
||||
|
||||
```java
|
||||
$ jad demo.MathGame main --lineNumber false
|
||||
@@ -127,9 +128,11 @@ public static void main(String[] args) throws InterruptedException {
|
||||
}
|
||||
```
|
||||
|
||||
#### 反编译时指定ClassLoader
|
||||
#### 反编译时指定 ClassLoader
|
||||
|
||||
> 当有多个 `ClassLoader` 都加载了这个类时,`jad` 命令会输出对应 `ClassLoader` 实例的 `hashcode`,然后你只需要重新执行 `jad` 命令,并使用参数 `-c <hashcode>` 就可以反编译指定 ClassLoader 加载的那个类了;
|
||||
::: tip
|
||||
当有多个 `ClassLoader` 都加载了这个类时,`jad` 命令会输出对应 `ClassLoader` 实例的 `hashcode`,然后你只需要重新执行 `jad` 命令,并使用参数 `-c <hashcode>` 就可以反编译指定 ClassLoader 加载的那个类了;
|
||||
:::
|
||||
|
||||
```java
|
||||
$ jad org.apache.log4j.Logger
|
||||
@@ -170,6 +173,6 @@ public class Logger extends Category
|
||||
Affect(row-cnt:1) cost in 190 ms.
|
||||
```
|
||||
|
||||
对于只有唯一实例的ClassLoader还可以通过`--classLoaderClass`指定class name,使用起来更加方便:
|
||||
对于只有唯一实例的 ClassLoader 还可以通过`--classLoaderClass`指定 class name,使用起来更加方便:
|
||||
|
||||
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
|
||||
`--classLoaderClass` 的值是 ClassLoader 的类名,只有匹配到唯一的 ClassLoader 实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
|
||||
@@ -1,9 +1,10 @@
|
||||
jvm
|
||||
===
|
||||
# jvm
|
||||
|
||||
[`jvm`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=command-jvm)
|
||||
|
||||
> 查看当前JVM信息
|
||||
::: tip
|
||||
查看当前 JVM 信息
|
||||
:::
|
||||
|
||||
### 使用参考
|
||||
|
||||
@@ -46,13 +47,13 @@ RUNTIME
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
GARBAGE-COLLECTORS
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
PS Scavenge name : PS Scavenge
|
||||
[count/time (ms)] collectionCount : 7
|
||||
collectionTime : 68
|
||||
|
||||
PS MarkSweep name : PS MarkSweep
|
||||
[count/time (ms)] collectionCount : 1
|
||||
collectionTime : 47
|
||||
PS Scavenge name : PS Scavenge
|
||||
[count/time (ms)] collectionCount : 7
|
||||
collectionTime : 68
|
||||
|
||||
PS MarkSweep name : PS MarkSweep
|
||||
[count/time (ms)] collectionCount : 1
|
||||
collectionTime : 47
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
MEMORY-MANAGERS
|
||||
@@ -73,15 +74,15 @@ RUNTIME
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
MEMORY
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
HEAP-MEMORY-USAGE init : 268435456(256.0 MiB)
|
||||
[memory in bytes] used : 18039504(17.2 MiB)
|
||||
committed : 181403648(173.0 MiB)
|
||||
max : 3817865216(3.6 GiB)
|
||||
|
||||
NO-HEAP-MEMORY-USAGE init : 2555904(2.4 MiB)
|
||||
[memory in bytes] used : 33926216(32.4 MiB)
|
||||
committed : 35176448(33.5 MiB)
|
||||
max : -1(-1 B)
|
||||
HEAP-MEMORY-USAGE init : 268435456(256.0 MiB)
|
||||
[memory in bytes] used : 18039504(17.2 MiB)
|
||||
committed : 181403648(173.0 MiB)
|
||||
max : 3817865216(3.6 GiB)
|
||||
|
||||
NO-HEAP-MEMORY-USAGE init : 2555904(2.4 MiB)
|
||||
[memory in bytes] used : 33926216(32.4 MiB)
|
||||
committed : 35176448(33.5 MiB)
|
||||
max : -1(-1 B)
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
OPERATING-SYSTEM
|
||||
@@ -109,15 +110,15 @@ RUNTIME
|
||||
Affect(row-cnt:0) cost in 88 ms.
|
||||
```
|
||||
|
||||
### THREAD相关
|
||||
### THREAD 相关
|
||||
|
||||
* COUNT: JVM当前活跃的线程数
|
||||
* DAEMON-COUNT: JVM当前活跃的守护线程数
|
||||
* PEAK-COUNT: 从JVM启动开始曾经活着的最大线程数
|
||||
* STARTED-COUNT: 从JVM启动开始总共启动过的线程次数
|
||||
* DEADLOCK-COUNT: JVM当前死锁的线程数
|
||||
- COUNT: JVM 当前活跃的线程数
|
||||
- DAEMON-COUNT: JVM 当前活跃的守护线程数
|
||||
- PEAK-COUNT: 从 JVM 启动开始曾经活着的最大线程数
|
||||
- STARTED-COUNT: 从 JVM 启动开始总共启动过的线程次数
|
||||
- DEADLOCK-COUNT: JVM 当前死锁的线程数
|
||||
|
||||
### 文件描述符相关
|
||||
|
||||
* MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数
|
||||
* OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数
|
||||
- MAX-FILE-DESCRIPTOR-COUNT:JVM 进程最大可以打开的文件描述符数
|
||||
- OPEN-FILE-DESCRIPTOR-COUNT:JVM 当前打开的文件描述符数
|
||||
@@ -1,5 +1,4 @@
|
||||
Arthas 命令行快捷键
|
||||
===
|
||||
# Arthas 命令行快捷键
|
||||
|
||||
[`keymap`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=command-keymap)
|
||||
|
||||
@@ -7,42 +6,36 @@ Arthas 命令行快捷键
|
||||
|
||||
默认的快捷键如下:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
| 快捷键 | 快捷键说明 | 命令名称 | 命令说明 |
|
||||
| ------------- | ---------------- | -------------------- | ---------------- |
|
||||
| `"\C-a"` | ctrl + a | beginning-of-line | 跳到行首 |
|
||||
| ` "\C-e"` | ctrl + e | end-of-line | 跳到行尾 |
|
||||
| `"\C-f"` | ctrl + f | forward-word | 向前移动一个单词 |
|
||||
| `"\C-b"` | ctrl + b | backward-word | 向后移动一个单词 |
|
||||
| `"\e[D"` | 键盘左方向键 | backward-char | 光标向前移动一个字符 |
|
||||
| `"\e[C"` | 键盘右方向键 | forward-char | 光标向后移动一个字符 |
|
||||
| `"\e[B"` | 键盘下方向键 | next-history | 下翻显示下一个命令 |
|
||||
| `"\e[A"` | 键盘上方向键 | previous-history | 上翻显示上一个命令 |
|
||||
| `"\C-h"` | ctrl + h | backward-delete-char | 向后删除一个字符 |
|
||||
| `"\C-?"` | ctrl + shift + / | backward-delete-char | 向后删除一个字符 |
|
||||
| 快捷键 | 快捷键说明 | 命令名称 | 命令说明 |
|
||||
| ------------- | ---------------- | -------------------- | -------------------------------- |
|
||||
| `"\C-a"` | ctrl + a | beginning-of-line | 跳到行首 |
|
||||
| ` "\C-e"` | ctrl + e | end-of-line | 跳到行尾 |
|
||||
| `"\C-f"` | ctrl + f | forward-word | 向前移动一个单词 |
|
||||
| `"\C-b"` | ctrl + b | backward-word | 向后移动一个单词 |
|
||||
| `"\e[D"` | 键盘左方向键 | backward-char | 光标向前移动一个字符 |
|
||||
| `"\e[C"` | 键盘右方向键 | forward-char | 光标向后移动一个字符 |
|
||||
| `"\e[B"` | 键盘下方向键 | next-history | 下翻显示下一个命令 |
|
||||
| `"\e[A"` | 键盘上方向键 | previous-history | 上翻显示上一个命令 |
|
||||
| `"\C-h"` | ctrl + h | backward-delete-char | 向后删除一个字符 |
|
||||
| `"\C-?"` | ctrl + shift + / | backward-delete-char | 向后删除一个字符 |
|
||||
| `"\C-u"` | ctrl + u | undo | 撤销上一个命令,相当于清空当前行 |
|
||||
| `"\C-d"` | ctrl + d | delete-char | 删除当前光标所在字符 |
|
||||
| `"\C-k"` | ctrl + k | kill-line | 删除当前光标到行尾的所有字符 |
|
||||
| `"\C-i"` | ctrl + i | complete | 自动补全,相当于敲`TAB` |
|
||||
| `"\C-j"` | ctrl + j | accept-line | 结束当前行,相当于敲回车 |
|
||||
| `"\C-m"` | ctrl + m | accept-line | 结束当前行,相当于敲回车 |
|
||||
| `"\C-w"` | | backward-delete-word | |
|
||||
| `"\C-x\e[3~"` | | backward-kill-line | |
|
||||
| `"\e\C-?"` | | backward-kill-word | |
|
||||
|
||||
|
||||
* 任何时候 `tab` 键,会根据当前的输入给出提示
|
||||
* 命令后敲 `-` 或 `--` ,然后按 `tab` 键,可以展示出此命令具体的选项
|
||||
| `"\C-d"` | ctrl + d | delete-char | 删除当前光标所在字符 |
|
||||
| `"\C-k"` | ctrl + k | kill-line | 删除当前光标到行尾的所有字符 |
|
||||
| `"\C-i"` | ctrl + i | complete | 自动补全,相当于敲`TAB` |
|
||||
| `"\C-j"` | ctrl + j | accept-line | 结束当前行,相当于敲回车 |
|
||||
| `"\C-m"` | ctrl + m | accept-line | 结束当前行,相当于敲回车 |
|
||||
| `"\C-w"` | | backward-delete-word | |
|
||||
| `"\C-x\e[3~"` | | backward-kill-line | |
|
||||
| `"\e\C-?"` | | backward-kill-word | |
|
||||
|
||||
- 任何时候 `tab` 键,会根据当前的输入给出提示
|
||||
- 命令后敲 `-` 或 `--` ,然后按 `tab` 键,可以展示出此命令具体的选项
|
||||
|
||||
#### 自定义快捷键
|
||||
|
||||
在当前用户目录下新建`$USER_HOME/.arthas/conf/inputrc`文件,加入自定义配置。
|
||||
|
||||
假设我是vim的重度用户,我要把`ctrl+h`设置为光标向前一个字符,则设置如下,首先拷贝默认配置
|
||||
假设我是 vim 的重度用户,我要把`ctrl+h`设置为光标向前一个字符,则设置如下,首先拷贝默认配置
|
||||
|
||||
```
|
||||
"\C-a": beginning-of-line
|
||||
@@ -70,11 +63,7 @@ Arthas 命令行快捷键
|
||||
|
||||
#### 后台异步命令相关快捷键
|
||||
|
||||
* ctrl + c: 终止当前命令
|
||||
* ctrl + z: 挂起当前命令,后续可以 bg/fg 重新支持此命令,或 kill 掉
|
||||
* ctrl + a: 回到行首
|
||||
* ctrl + e: 回到行尾
|
||||
|
||||
|
||||
|
||||
|
||||
- ctrl + c: 终止当前命令
|
||||
- ctrl + z: 挂起当前命令,后续可以 bg/fg 重新支持此命令,或 kill 掉
|
||||
- ctrl + a: 回到行首
|
||||
- ctrl + e: 回到行尾
|
||||
@@ -1,13 +1,14 @@
|
||||
logger
|
||||
===
|
||||
# logger
|
||||
|
||||
[`logger`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials?language=cn&id=command-logger)
|
||||
|
||||
> 查看logger信息,更新logger level
|
||||
::: tip
|
||||
查看 logger 信息,更新 logger level
|
||||
:::
|
||||
|
||||
### 使用参考
|
||||
|
||||
#### 查看所有logger信息
|
||||
#### 查看所有 logger 信息
|
||||
|
||||
以下面的`logback.xml`为例:
|
||||
|
||||
@@ -46,7 +47,6 @@ logger
|
||||
</configuration>
|
||||
```
|
||||
|
||||
|
||||
使用`logger`命令打印的结果是:
|
||||
|
||||
```bash
|
||||
@@ -78,12 +78,11 @@ logger
|
||||
|
||||
从`appenders`的信息里,可以看到
|
||||
|
||||
* `CONSOLE` logger的target是`System.out`
|
||||
* `APPLICATION` logger是`RollingFileAppender`,它的file是`app.log`
|
||||
* `ASYNC`它的`appenderRef`是`APPLICATION`,即异步输出到文件里
|
||||
- `CONSOLE` logger 的 target 是`System.out`
|
||||
- `APPLICATION` logger 是`RollingFileAppender`,它的 file 是`app.log`
|
||||
- `ASYNC`它的`appenderRef`是`APPLICATION`,即异步输出到文件里
|
||||
|
||||
|
||||
#### 查看指定名字的logger信息
|
||||
#### 查看指定名字的 logger 信息
|
||||
|
||||
```bash
|
||||
[arthas@2062]$ logger -n org.springframework.web
|
||||
@@ -97,11 +96,11 @@ logger
|
||||
codeSource file:/Users/hengyunabc/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar
|
||||
```
|
||||
|
||||
#### 查看指定classloader的logger信息
|
||||
#### 查看指定 classloader 的 logger 信息
|
||||
|
||||
注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。
|
||||
注意 hashcode 是变化的,需要先查看当前的 ClassLoader 信息,提取对应 ClassLoader 的 hashcode。
|
||||
|
||||
如果你使用`-c`,你需要手动输入hashcode:`-c <hashcode>`
|
||||
如果你使用`-c`,你需要手动输入 hashcode:`-c <hashcode>`
|
||||
|
||||
```bash
|
||||
[arthas@2062]$ logger -c 2a139a55
|
||||
@@ -130,35 +129,34 @@ logger
|
||||
appenderRef [APPLICATION]
|
||||
```
|
||||
|
||||
对于只有唯一实例的ClassLoader可以通过`--classLoaderClass`指定class name,使用起来更加方便:
|
||||
对于只有唯一实例的 ClassLoader 可以通过`--classLoaderClass`指定 class name,使用起来更加方便:
|
||||
|
||||
`logger --classLoaderClass sun.misc.Launcher$AppClassLoader`
|
||||
|
||||
* 注: 这里classLoaderClass 在 java 8 是 sun.misc.Launcher$AppClassLoader,而java 11的classloader是jdk.internal.loader.ClassLoaders$AppClassLoader。
|
||||
- 注: 这里 classLoaderClass 在 java 8 是 sun.misc.Launcher$AppClassLoader,而java 11的classloader是jdk.internal.loader.ClassLoaders$AppClassLoader。
|
||||
|
||||
`--classLoaderClass` 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
|
||||
`--classLoaderClass` 的值是 ClassLoader 的类名,只有匹配到唯一的 ClassLoader 实例时才能工作,目的是方便输入通用命令,而`-c <hashcode>`是动态变化的。
|
||||
|
||||
#### 更新logger level
|
||||
#### 更新 logger level
|
||||
|
||||
```bash
|
||||
[arthas@2062]$ logger --name ROOT --level debug
|
||||
update logger level success.
|
||||
```
|
||||
|
||||
#### 指定classloader更新 logger level
|
||||
#### 指定 classloader 更新 logger level
|
||||
|
||||
默认情况下,logger命令会在SystemClassloader下执行,如果应用是传统的`war`应用,或者spring boot fat jar启动的应用,那么需要指定classloader。
|
||||
默认情况下,logger 命令会在 SystemClassloader 下执行,如果应用是传统的`war`应用,或者 spring boot fat jar 启动的应用,那么需要指定 classloader。
|
||||
|
||||
可以先用 `sc -d yourClassName` 来查看具体的 classloader hashcode,然后在更新level时指定classloader:
|
||||
可以先用 `sc -d yourClassName` 来查看具体的 classloader hashcode,然后在更新 level 时指定 classloader:
|
||||
|
||||
```bash
|
||||
[arthas@2062]$ logger -c 2a139a55 --name ROOT --level debug
|
||||
```
|
||||
|
||||
#### 查看没有appender的logger的信息
|
||||
#### 查看没有 appender 的 logger 的信息
|
||||
|
||||
|
||||
默认情况下,`logger`命令只打印有appender的logger的信息。如果想查看没有`appender`的logger的信息,可以加上参数`--include-no-appender`。
|
||||
默认情况下,`logger`命令只打印有 appender 的 logger 的信息。如果想查看没有`appender`的 logger 的信息,可以加上参数`--include-no-appender`。
|
||||
|
||||
注意,通常输出结果会很长。
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# 手动安装 Arthas
|
||||
|
||||
1. 下载最新版本
|
||||
|
||||
**最新版本,点击下载**:[](https://arthas.aliyun.com/download/latest_version?mirror=aliyun)
|
||||
|
||||
2. 解压缩 arthas 的压缩包
|
||||
|
||||
```
|
||||
unzip arthas-packaging-bin.zip
|
||||
```
|
||||
|
||||
3. 安装 Arthas
|
||||
|
||||
安装之前最好把所有老版本的 Arthas 全都删掉
|
||||
|
||||
```
|
||||
sudo su admin
|
||||
rm -rf /home/admin/.arthas/lib/*
|
||||
cd arthas
|
||||
./install-local.sh
|
||||
```
|
||||
|
||||
::: warning
|
||||
注意,这里根据你需要诊断的 Java 进程的所属用户进行切换
|
||||
:::
|
||||
|
||||
4. 启动 Arthas
|
||||
|
||||
启动之前,请确保老版本的 Arthas 已经`stop`.
|
||||
|
||||
```
|
||||
./as.sh
|
||||
```
|
||||
|
||||
## 以脚本的方式启动 as.sh/as.bat
|
||||
|
||||
### Linux/Unix/Mac
|
||||
|
||||
Arthas 支持在 Linux/Unix/Mac 等平台上一键安装,请复制以下内容,并粘贴到命令行中,敲 `回车` 执行即可:
|
||||
|
||||
```bash
|
||||
curl -L https://arthas.aliyun.com/install.sh | sh
|
||||
```
|
||||
|
||||
上述命令会下载启动脚本文件 `as.sh` 到当前目录,你可以放在任何地方或将其加入到 `$PATH` 中。
|
||||
|
||||
直接在 shell 下面执行`./as.sh`,就会进入交互界面。
|
||||
|
||||
也可以执行`./as.sh -h`来获取更多参数信息。
|
||||
|
||||
### Windows
|
||||
|
||||
最新版本,点击下载:[](https://arthas.aliyun.com/download/latest_version?mirror=aliyun)
|
||||
|
||||
下载解压后在 bin 目录有 `as.bat`。此脚本暂时只接受一个参数 pid,即只能诊断本机上的 Java 进程。(欢迎精通 bat 脚本的开发者改进)
|
||||
|
||||
```
|
||||
as.bat <pid>
|
||||
```
|
||||
|
||||
使用以下命令诊断 windows 服务模式运行的 Java 进程 (--interact 打开服务 UI 交互模式,方便诊断问题):
|
||||
|
||||
```
|
||||
as-service.bat -port <port>
|
||||
as-service.bat -pid <pid>
|
||||
as-service.bat -pid <pid> --interact
|
||||
```
|
||||
|
||||
清理 arthas windows 服务执行以下命令:
|
||||
|
||||
```
|
||||
as-service.bat -remove
|
||||
```
|
||||
|
||||
## 手动拼接命令行启动
|
||||
|
||||
如果启动遇到问题,可以尝试手动拼接出命令行参数来启动。
|
||||
|
||||
1. 查找目录 jvm 的 java 文件路径。
|
||||
|
||||
在 linux/mac 上执行`ps aux | grep java`,在 windows 上可以通过进程管理器来查看。假设是`/opt/jdk1.8/bin/java`。
|
||||
|
||||
2. 拼接出命令行
|
||||
|
||||
```bash
|
||||
/opt/jdk1.8/bin/java -Xbootclasspath/a:/opt/jdk1.8/lib/tools.jar \
|
||||
-jar /tmp/arthas-packaging/arthas-core.jar \
|
||||
-pid 15146 \
|
||||
-target-ip 127.0.0.1 -telnet-port 3658 -http-port 8563 \
|
||||
-core /tmp/arthas-packaging/arthas-core.jar \
|
||||
-agent /tmp/arthas-packaging/arthas/arthas-agent.jar
|
||||
```
|
||||
|
||||
命令行分几部分组成:
|
||||
|
||||
- `-Xbootclasspath` 增加 tools.jar
|
||||
- `-jar /tmp/arthas-packaging/arthas-core.jar` 指定 main 函数入口
|
||||
- `-pid 15146` 指定目标 java 进程 ID
|
||||
- `-target-ip 127.0.0.1` 指定 IP
|
||||
- `-telnet-port 3658 -http-port 8563` 指定 telnet 和 http 端口
|
||||
- `-core /tmp/arthas-packaging/arthas-core.jar -agent /tmp/arthas-packaging/arthas/arthas-agent.jar` 指定 core/agent jar 包
|
||||
|
||||
如果是`jdk > 9`,即 9/10/11 以上的版本,不需要指定`tools.jar`,直接去掉`-Xbootclasspath` 的配置即可。
|
||||
|
||||
启动目志输出在`~/logs/arthas/arthas.log`里。
|
||||
|
||||
3. attach 成功之后,使用 telnet 连接
|
||||
|
||||
```bash
|
||||
telnet 127.0.0.1 3658
|
||||
```
|
||||
@@ -0,0 +1,68 @@
|
||||
# mbean
|
||||
|
||||
[`mbean`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=command-mbean)
|
||||
|
||||
::: tip
|
||||
查看 Mbean 的信息
|
||||
:::
|
||||
|
||||
这个命令可以便捷的查看或监控 Mbean 的属性信息。
|
||||
|
||||
### 参数说明
|
||||
|
||||
| 参数名称 | 参数说明 |
|
||||
| ------------------: | :--------------------------------------------------- |
|
||||
| _name-pattern_ | 名称表达式匹配 |
|
||||
| _attribute-pattern_ | 属性名表达式匹配 |
|
||||
| [m] | 查看元信息 |
|
||||
| [i:] | 刷新属性值的时间间隔 (ms) |
|
||||
| [n:] | 刷新属性值的次数 |
|
||||
| [E] | 开启正则表达式匹配,默认为通配符匹配。仅对属性名有效 |
|
||||
|
||||
### 使用参考
|
||||
|
||||
列出所有 Mbean 的名称:
|
||||
|
||||
```bash
|
||||
mbean
|
||||
```
|
||||
|
||||
查看 Mbean 的元信息:
|
||||
|
||||
```bash
|
||||
mbean -m java.lang:type=Threading
|
||||
```
|
||||
|
||||
查看 mbean 属性信息:
|
||||
|
||||
```bash
|
||||
mbean java.lang:type=Threading
|
||||
```
|
||||
|
||||
mbean 的 name 支持通配符匹配:
|
||||
|
||||
```bash
|
||||
mbean java.lang:type=Th*
|
||||
```
|
||||
|
||||
::: warning
|
||||
注意:ObjectName 的匹配规则与正常的通配符存在差异,详细参见:[javax.management.ObjectName](https://docs.oracle.com/javase/8/docs/api/javax/management/ObjectName.html?is-external=true)
|
||||
:::
|
||||
|
||||
通配符匹配特定的属性字段:
|
||||
|
||||
```bash
|
||||
mbean java.lang:type=Threading *Count
|
||||
```
|
||||
|
||||
使用`-E`命令切换为正则匹配:
|
||||
|
||||
```bash
|
||||
mbean -E java.lang:type=Threading PeakThreadCount|ThreadCount|DaemonThreadCount
|
||||
```
|
||||
|
||||
使用`-i`命令实时监控:
|
||||
|
||||
```bash
|
||||
mbean -i 1000 java.lang:type=Threading *Count
|
||||
```
|
||||
@@ -1,21 +1,22 @@
|
||||
mc
|
||||
===
|
||||
# mc
|
||||
|
||||
[`mc-retransform`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials?language=cn&id=command-mc-retransform)
|
||||
|
||||
> Memory Compiler/内存编译器,编译`.java`文件生成`.class`。
|
||||
::: tip
|
||||
Memory Compiler/内存编译器,编译`.java`文件生成`.class`。
|
||||
:::
|
||||
|
||||
```bash
|
||||
mc /tmp/Test.java
|
||||
```
|
||||
|
||||
可以通过`-c`参数指定classloader:
|
||||
可以通过`-c`参数指定 classloader:
|
||||
|
||||
```bash
|
||||
mc -c 327a647b /tmp/Test.java
|
||||
```
|
||||
|
||||
也可以通过`--classLoaderClass`参数指定ClassLoader:
|
||||
也可以通过`--classLoaderClass`参数指定 ClassLoader:
|
||||
|
||||
```bash
|
||||
$ mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
|
||||
@@ -32,4 +33,6 @@ mc -d /tmp/output /tmp/ClassA.java /tmp/ClassB.java
|
||||
|
||||
编译生成`.class`文件之后,可以结合[retransform](retransform.md)命令实现热更新代码。
|
||||
|
||||
> 注意,mc命令有可能失败。如果编译失败可以在本地编译好`.class`文件,再上传到服务器。具体参考[retransform](retransform.md)命令说明。
|
||||
::: warning
|
||||
注意,mc 命令有可能失败。如果编译失败可以在本地编译好`.class`文件,再上传到服务器。具体参考[retransform](retransform.md)命令说明。
|
||||
:::
|
||||
@@ -1,8 +1,6 @@
|
||||
memory
|
||||
===
|
||||
|
||||
查看JVM 内存信息。
|
||||
# memory
|
||||
|
||||
查看 JVM 内存信息。
|
||||
|
||||
### 使用参考
|
||||
|
||||
@@ -22,4 +20,3 @@ codeheap_'non-profiled_nmethods' 685K 2496K 120032K 0.57%
|
||||
mapped 0K 0K - 0.00%
|
||||
direct 48M 48M - 100.00%
|
||||
```
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
monitor
|
||||
=======
|
||||
# monitor
|
||||
|
||||
[`monitor`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn&id=command-monitor)
|
||||
|
||||
> 方法执行监控
|
||||
::: tip
|
||||
方法执行监控
|
||||
:::
|
||||
|
||||
对匹配 `class-pattern`/`method-pattern`/`condition-express`的类、方法的调用进行监控。
|
||||
|
||||
@@ -11,33 +12,33 @@ monitor
|
||||
|
||||
实时返回命令是输入之后立即返回,而非实时返回的命令,则是不断的等待目标 Java 进程返回信息,直到用户输入 `Ctrl+C` 为止。
|
||||
|
||||
服务端是以任务的形式在后台跑任务,植入的代码随着任务的中止而不会被执行,所以任务关闭后,不会对原有性能产生太大影响,而且原则上,任何Arthas命令不会引起原有业务逻辑的改变。
|
||||
服务端是以任务的形式在后台跑任务,植入的代码随着任务的中止而不会被执行,所以任务关闭后,不会对原有性能产生太大影响,而且原则上,任何 Arthas 命令不会引起原有业务逻辑的改变。
|
||||
|
||||
### 监控的维度说明
|
||||
|
||||
|监控项|说明|
|
||||
|---:|:---|
|
||||
|timestamp|时间戳|
|
||||
|class|Java类|
|
||||
|method|方法(构造方法、普通方法)|
|
||||
|total|调用次数|
|
||||
|success|成功次数|
|
||||
|fail|失败次数|
|
||||
|rt|平均RT|
|
||||
|fail-rate|失败率|
|
||||
| 监控项 | 说明 |
|
||||
| --------: | :------------------------- |
|
||||
| timestamp | 时间戳 |
|
||||
| class | Java 类 |
|
||||
| method | 方法(构造方法、普通方法) |
|
||||
| total | 调用次数 |
|
||||
| success | 成功次数 |
|
||||
| fail | 失败次数 |
|
||||
| rt | 平均 RT |
|
||||
| fail-rate | 失败率 |
|
||||
|
||||
### 参数说明
|
||||
|
||||
方法拥有一个命名参数 `[c:]`,意思是统计周期(cycle of output),拥有一个整型的参数值
|
||||
|
||||
|参数名称|参数说明|
|
||||
|---:|:---|
|
||||
|*class-pattern*|类名表达式匹配|
|
||||
|*method-pattern*|方法名表达式匹配|
|
||||
|*condition-express*|条件表达式|
|
||||
|[E]|开启正则表达式匹配,默认为通配符匹配|
|
||||
|`[c:]`|统计周期,默认值为120秒|
|
||||
|[b]|在**方法调用之前**计算condition-express|
|
||||
| 参数名称 | 参数说明 |
|
||||
| ------------------: | :--------------------------------------- |
|
||||
| _class-pattern_ | 类名表达式匹配 |
|
||||
| _method-pattern_ | 方法名表达式匹配 |
|
||||
| _condition-express_ | 条件表达式 |
|
||||
| [E] | 开启正则表达式匹配,默认为通配符匹配 |
|
||||
| `[c:]` | 统计周期,默认值为 120 秒 |
|
||||
| [b] | 在**方法调用之前**计算 condition-express |
|
||||
|
||||
### 使用参考
|
||||
|
||||
@@ -76,52 +77,50 @@ Affect(class-cnt:1 , method-cnt:1) cost in 94 ms.
|
||||
monitor -c 5 demo.MathGame primeFactors "params[0] <= 2"
|
||||
Press Q or Ctrl+C to abort.
|
||||
Affect(class count: 1 , method count: 1) cost in 19 ms, listenerId: 5
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
-----------------------------------------------------------------------------------------------
|
||||
2020-09-02 09:42:36 demo.MathGame primeFactors 5 3 2 0.09 40.00%
|
||||
2020-09-02 09:42:36 demo.MathGame primeFactors 5 3 2 0.09 40.00%
|
||||
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
----------------------------------------------------------------------------------------------
|
||||
2020-09-02 09:42:41 demo.MathGame primeFactors 5 2 3 0.11 60.00%
|
||||
2020-09-02 09:42:41 demo.MathGame primeFactors 5 2 3 0.11 60.00%
|
||||
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
----------------------------------------------------------------------------------------------
|
||||
2020-09-02 09:42:46 demo.MathGame primeFactors 5 1 4 0.06 80.00%
|
||||
2020-09-02 09:42:46 demo.MathGame primeFactors 5 1 4 0.06 80.00%
|
||||
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
----------------------------------------------------------------------------------------------
|
||||
2020-09-02 09:42:51 demo.MathGame primeFactors 5 1 4 0.12 80.00%
|
||||
2020-09-02 09:42:51 demo.MathGame primeFactors 5 1 4 0.12 80.00%
|
||||
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
----------------------------------------------------------------------------------------------
|
||||
2020-09-02 09:42:56 demo.MathGame primeFactors 5 3 2 0.15 40.00%
|
||||
2020-09-02 09:42:56 demo.MathGame primeFactors 5 3 2 0.15 40.00%
|
||||
```
|
||||
|
||||
#### 计算条件表达式过滤统计结果(方法执行完毕之前)
|
||||
|
||||
|
||||
```bash
|
||||
monitor -b -c 5 com.test.testes.MathGame primeFactors "params[0] <= 2"
|
||||
Press Q or Ctrl+C to abort.
|
||||
Affect(class count: 1 , method count: 1) cost in 21 ms, listenerId: 4
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
----------------------------------------------------------------------------------------------
|
||||
2020-09-02 09:41:57 demo.MathGame primeFactors 1 0 1 0.10 100.00%
|
||||
2020-09-02 09:41:57 demo.MathGame primeFactors 1 0 1 0.10 100.00%
|
||||
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
----------------------------------------------------------------------------------------------
|
||||
2020-09-02 09:42:02 demo.MathGame primeFactors 3 0 3 0.06 100.00%
|
||||
2020-09-02 09:42:02 demo.MathGame primeFactors 3 0 3 0.06 100.00%
|
||||
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
----------------------------------------------------------------------------------------------
|
||||
2020-09-02 09:42:07 demo.MathGame primeFactors 2 0 2 0.06 100.00%
|
||||
2020-09-02 09:42:07 demo.MathGame primeFactors 2 0 2 0.06 100.00%
|
||||
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
----------------------------------------------------------------------------------------------
|
||||
2020-09-02 09:42:12 demo.MathGame primeFactors 1 0 1 0.05 100.00%
|
||||
2020-09-02 09:42:12 demo.MathGame primeFactors 1 0 1 0.05 100.00%
|
||||
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
timestamp class method total success fail avg-rt(ms) fail-rate
|
||||
----------------------------------------------------------------------------------------------
|
||||
2020-09-02 09:42:17 demo.MathGame primeFactors 2 0 2 0.10 100.00%
|
||||
2020-09-02 09:42:17 demo.MathGame primeFactors 2 0 2 0.10 100.00%
|
||||
```
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
ognl
|
||||
===
|
||||
# ognl
|
||||
|
||||
[`ognl`在线教程](https://arthas.aliyun.com/doc/arthas-tutorials?language=cn&id=command-ognl)
|
||||
|
||||
> 执行ognl表达式
|
||||
::: tip
|
||||
执行 ognl 表达式
|
||||
:::
|
||||
|
||||
从3.0.5版本增加
|
||||
从 3.0.5 版本增加
|
||||
|
||||
### 参数说明
|
||||
|
||||
|参数名称|参数说明|
|
||||
|---:|:---|
|
||||
|*express*|执行的表达式|
|
||||
|`[c:]`|执行表达式的 ClassLoader 的 hashcode,默认值是SystemClassLoader|
|
||||
|`[classLoaderClass:]`|指定执行表达式的 ClassLoader 的 class name|
|
||||
|[x]|结果对象的展开层次,默认值1|
|
||||
|
||||
| 参数名称 | 参数说明 |
|
||||
| --------------------: | :--------------------------------------------------------------- |
|
||||
| _express_ | 执行的表达式 |
|
||||
| `[c:]` | 执行表达式的 ClassLoader 的 hashcode,默认值是 SystemClassLoader |
|
||||
| `[classLoaderClass:]` | 指定执行表达式的 ClassLoader 的 class name |
|
||||
| [x] | 结果对象的展开层次,默认值 1 |
|
||||
|
||||
### 使用参考
|
||||
|
||||
* OGNL特殊用法请参考:[https://github.com/alibaba/arthas/issues/71](https://github.com/alibaba/arthas/issues/71)
|
||||
* OGNL表达式官方指南:[https://commons.apache.org/proper/commons-ognl/language-guide.html](https://commons.apache.org/proper/commons-ognl/language-guide.html)
|
||||
|
||||
- OGNL 特殊用法请参考:[https://github.com/alibaba/arthas/issues/71](https://github.com/alibaba/arthas/issues/71)
|
||||
- OGNL 表达式官方指南:[https://commons.apache.org/proper/commons-ognl/language-guide.html](https://commons.apache.org/proper/commons-ognl/language-guide.html)
|
||||
|
||||
调用静态函数:
|
||||
|
||||
@@ -53,15 +52,15 @@ $ ognl '@demo.MathGame@random'
|
||||
]
|
||||
```
|
||||
|
||||
通过hashcode指定ClassLoader:
|
||||
通过 hashcode 指定 ClassLoader:
|
||||
|
||||
```bash
|
||||
$ classloader -t
|
||||
+-BootstrapClassLoader
|
||||
+-jdk.internal.loader.ClassLoaders$PlatformClassLoader@301ec38b
|
||||
+-com.taobao.arthas.agent.ArthasClassloader@472067c7
|
||||
+-jdk.internal.loader.ClassLoaders$AppClassLoader@4b85612c
|
||||
+-org.springframework.boot.loader.LaunchedURLClassLoader@7f9a81e8
|
||||
+-BootstrapClassLoader
|
||||
+-jdk.internal.loader.ClassLoaders$PlatformClassLoader@301ec38b
|
||||
+-com.taobao.arthas.agent.ArthasClassloader@472067c7
|
||||
+-jdk.internal.loader.ClassLoaders$AppClassLoader@4b85612c
|
||||
+-org.springframework.boot.loader.LaunchedURLClassLoader@7f9a81e8
|
||||
|
||||
$ ognl -c 7f9a81e8 @org.springframework.boot.SpringApplication@logger
|
||||
@Slf4jLocationAwareLog[
|
||||
@@ -69,11 +68,12 @@ $ ognl -c 7f9a81e8 @org.springframework.boot.SpringApplication@logger
|
||||
name=@String[org.springframework.boot.SpringApplication],
|
||||
logger=@Logger[Logger[org.springframework.boot.SpringApplication]],
|
||||
]
|
||||
$
|
||||
$
|
||||
```
|
||||
注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode。
|
||||
|
||||
对于只有唯一实例的ClassLoader可以通过class name指定,使用起来更加方便:
|
||||
注意 hashcode 是变化的,需要先查看当前的 ClassLoader 信息,提取对应 ClassLoader 的 hashcode。
|
||||
|
||||
对于只有唯一实例的 ClassLoader 可以通过 class name 指定,使用起来更加方便:
|
||||
|
||||
```bash
|
||||
$ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader @org.springframework.boot.SpringApplication@logger
|
||||
@@ -84,8 +84,7 @@ $ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
执行多行表达式,赋值给临时变量,返回一个List:
|
||||
执行多行表达式,赋值给临时变量,返回一个 List:
|
||||
|
||||
```bash
|
||||
$ ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
|
||||
@@ -93,4 +92,4 @@ $ ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("j
|
||||
@String[/opt/java/8.0.181-zulu/jre],
|
||||
@String[OpenJDK Runtime Environment],
|
||||
]
|
||||
```
|
||||
```
|
||||