support inject into java process of windows service (#581)

* add as-service.bat to support inject into java process of windows service
* as.bat support telnet/http port args
This commit is contained in:
gongdewei 2019-03-21 14:31:17 +08:00 committed by hengyunabc
parent 0a81d7b3c6
commit 5bb70c6b96
4 changed files with 273 additions and 11 deletions

209
bin/as-service.bat Executable file
View File

@ -0,0 +1,209 @@
@echo off
REM DON'T CHANGE THE FIRST LINE OF THE FILE, WINDOWS SERVICE RUN BAT NEED IT! (@echo off)
REM specify JAVA_HOME here
REM set PRE_JAVA_HOME=C:\Program Files\Java\jdk1.8.0_131
REM set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_201
set basedir=%~dp0
set filename=%~nx0
set srv_name=arthas_srv
set srv_interact=false
set telnet_port=3658
set http_port=8563
REM parse extend args
set arg1=%1
set arg2=%2
set AS_ARGS=
set AS_WAIT=/wait
for %%a in (%*) do (
if "%%a"=="--ignore-tools" set AS_ARGS=%AS_ARGS% --ignore-tools
if "%%a"=="--interact" (
set AS_WAIT=
set AS_ARGS=%AS_ARGS% --interact
set srv_interact=true
)
)
REM from https://stackoverflow.com/a/35445653
:read_params
if not %1/==/ (
if not "%__var%"=="" (
if not "%__var:~0,1%"=="-" (
endlocal
goto read_params
)
endlocal & set %__var:~1%=%~1
) else (
setlocal & set __var=%~1
)
shift
goto read_params
)
if not "%telnet-port%"=="" set telnet_port=%telnet-port%
if not "%http-port%"=="" set http_port=%http-port%
REM decode path: '@' -> ' '
if not "%my_java_home%"=="" set JAVA_HOME=%my_java_home:@= %
REM Setup JAVA_HOME
REM set JAVA_HOME=%JAVA_HOME:"=%
if "%JAVA_HOME%" == "" goto noJavaHome
if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
set JAVACMD="%JAVA_HOME%\bin\java"
REM Runas Service, do not call 'echo' before this line
if ["%arg1%"] == ["-service"] (
set AS_ARGS=%AS_ARGS% -telnet-port %telnet_port% -http-port %http_port%
start %AS_WAIT% %basedir%\as.bat %arg2% %AS_ARGS%
exit 0
)
if ["%arg1%"] == ["-port"] (
set port=%arg2%
if "%port%" == "" goto :usage
goto :find_port
)
if ["%arg1%"] == ["-pid"] (
set pid=%arg2%
if "%pid%" == "" goto :usage
goto :prepare_srv
)
if ["%arg1%"] == ["-remove"] (
goto :remove_srv
)
goto :usage
:usage
echo Example:
echo %filename% -port java_port
echo %filename% -pid java_pid
echo %filename% -port 8080
echo %filename% -pid 2351
echo %filename% -remove ;remove arthas service
echo Need the port or pid argument.
exit /b -1
:noJavaHome
echo JAVA_HOME: %JAVA_HOME%
echo The JAVA_HOME environment variable is not defined correctly.
echo It is needed to run this program.
echo NB: JAVA_HOME should point to a JDK not a JRE.
exit /b -1
:remove_srv
echo Removing service: %srv_name% ...
sc stop %srv_name%
sc delete %srv_name%
exit /b 0
:find_port
@rem find pid by port
echo %port%| findstr /r "^[1-9][0-9]*$">nul
if %errorlevel% neq 0 (
echo port is not valid number!
goto :usage
)
echo Finding process of listening on port: %port%
set query_pid_command='netstat -ano ^^^| findstr ":%port%" ^^^| findstr "LISTENING"'
set pid=
for /f "tokens=5" %%i in (%query_pid_command%) do (
set pid=%%i
)
if "%pid%" == "" (
echo None process listening on port: %port%
goto :end
)
echo Target process pid is %pid%
:prepare_srv
echo %pid%| findstr /r "^[1-9][0-9]*$">nul
if %errorlevel% neq 0 (
echo PID is not valid number!
goto :usage
)
echo Preparing arthas service and injecting arthas agent to process: %pid% ...
REM encode path: ' ' -> '@'
set srv_java_home=-my_java_home %JAVA_HOME: =@%
set srv_port=-telnet-port %telnet_port% -http-port %http_port%
set srv_type=type= own
set srv_binpath=binPath= "%basedir%\%filename% -service %pid% %srv_port% %srv_java_home% --no-interact"
if "%srv_interact%" == "true" (
set srv_type=type= interact type= own
set srv_binpath=binPath= "%basedir%\%filename% -service %pid% %srv_port% %srv_java_home%"
)
echo arthas srv binPath: %srv_binpath%
sc start UI0Detect
sc create %srv_name% start= demand %srv_type% %srv_binpath%
sc config %srv_name% start= demand %srv_type% %srv_binpath%
sc stop %srv_name%
sc start %srv_name%
echo Waitting for arthas agent ...
set count=0
:waitfor_loop
echo checking
netstat -nao |findstr LIST |findstr :%telnet_port%
IF %ERRORLEVEL% NEQ 0 (
set /a count+=1
if %count% geq 4 (
echo Arthas agent telnet port is not ready, maybe inject failed.
goto :end
)
ping -w 1 -n 2 0.0.0.0 > nul
goto :waitfor_loop
)
echo Arthas agent telnet port is ready.
:attachSuccess
WHERE telnet
IF %ERRORLEVEL% NEQ 0 (
ECHO telnet wasn't found, please google how to install telnet under windows.
ECHO Try to visit http://127.0.0.1:%http_port% to connecto arthas server.
start http://127.0.0.1:%http_port%
) else (
telnet 127.0.0.1 %telnet_port%
)
echo
echo Checking arthas telnet port [:%telnet_port%] ...
netstat -nao |findstr LIST |findstr :%telnet_port%
IF %ERRORLEVEL% EQU 0 (
echo Arthas agent is still running!
goto :choice
) else (
echo Arthas agent is shutdown.
goto :end
)
:choice
set /P c=Are you going to shutdown arthas agent [Y/N]?
echo input: %c%
if /I "%c%" EQU "Y" goto :shutdown_agent
if /I "%c%" EQU "N" goto :end
goto :choice
:shutdown_agent
echo Shutting down arthas ...
%JAVACMD% -jar arthas-client.jar -c shutdown 127.0.0.1 %telnet_port%
@rem check telnet port agian
echo Checking arthas telnet port [:%telnet_port%] ...
netstat -nao |findstr LIST |findstr :%telnet_port%
IF %ERRORLEVEL% EQU 0 (
echo Arthas shutdown failed!
) else (
echo Arthas shutdown successfully.
)
:end

47
bin/as.bat Normal file → Executable file
View File

@ -10,10 +10,11 @@ REM ----------------------------------------------------------------------------
set ERROR_CODE=0 set ERROR_CODE=0
set TELNET_PORT=3658
set HTTP_PORT=8563
set BASEDIR=%~dp0 set BASEDIR=%~dp0
if ["%~1"]==[""] ( if ["%~1"]==[""] (
echo Example: echo Example:
echo %~nx0 452 echo %~nx0 452
@ -40,13 +41,37 @@ if %errorlevel% neq 0 (
goto exit_bat goto exit_bat
) )
REM parse extend args
if "%2"=="--ignore-tools" ( set ignoreTools=0
set ignoreTools=1 set exitProcess=0
) else ( for %%a in (%*) do (
set ignoreTools=0 if "%%a"=="--no-interact" set exitProcess=1
if "%%a"=="--ignore-tools" set ignoreTools=1
) )
REM from https://stackoverflow.com/a/35445653
:read_params
if not %1/==/ (
if not "%__var%"=="" (
if not "%__var:~0,1%"=="-" (
endlocal
goto read_params
)
endlocal & set %__var:~1%=%~1
) else (
setlocal & set __var=%~1
)
shift
goto read_params
)
if not "%telnet-port%"=="" set TELNET_PORT=%telnet-port%
if not "%http-port%"=="" set HTTP_PORT=%http-port%
echo JAVA_HOME: %JAVA_HOME%
echo telnet port: %TELNET_PORT%
echo http port: %HTTP_PORT%
REM Setup JAVA_HOME REM Setup JAVA_HOME
if "%JAVA_HOME%" == "" goto noJavaHome if "%JAVA_HOME%" == "" goto noJavaHome
if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
@ -74,8 +99,9 @@ goto exit_bat
:okJava :okJava
set JAVACMD="%JAVA_HOME%"\bin\java set JAVACMD="%JAVA_HOME%"\bin\java
%JAVACMD% -Dfile.encoding=UTF-8 %BOOT_CLASSPATH% -jar "%CORE_JAR%" -pid "%PID%" -target-ip 127.0.0.1 -telnet-port 3658 -http-port 8563 -core "%CORE_JAR%" -agent "%AGENT_JAR%" %JAVACMD% -Dfile.encoding=UTF-8 %BOOT_CLASSPATH% -jar "%CORE_JAR%" -pid "%PID%" -target-ip 127.0.0.1 -telnet-port %TELNET_PORT% -http-port %HTTP_PORT% -core "%CORE_JAR%" -agent "%AGENT_JAR%"
if %ERRORLEVEL% NEQ 0 goto exit_bat if %ERRORLEVEL% NEQ 0 goto exit_bat
if "%exitProcess%" == "true" goto :exit_bat
goto attachSuccess goto attachSuccess
@ -83,11 +109,12 @@ goto attachSuccess
WHERE telnet WHERE telnet
IF %ERRORLEVEL% NEQ 0 ( IF %ERRORLEVEL% NEQ 0 (
ECHO telnet wasn't found, please google how to install telnet under windows. ECHO telnet wasn't found, please google how to install telnet under windows.
ECHO Try to visit http://127.0.0.1:8563 to connecto arthas server. ECHO Try to visit http://127.0.0.1:%HTTP_PORT% to connecto arthas server.
start http://127.0.0.1:8563 start http://127.0.0.1:%HTTP_PORT%
) else ( ) else (
telnet 127.0.0.1 3658 telnet 127.0.0.1 %TELNET_PORT%
) )
:exit_bat :exit_bat
if "%exitProcess%" == "true" exit %ERROR_CODE%
exit /B %ERROR_CODE% exit /B %ERROR_CODE%

View File

@ -59,6 +59,19 @@ Download and unzip, then find `as.bat` from 'bin' directory. For now this script
as.bat <pid> as.bat <pid>
``` ```
If you want to diagnose Java process run as windows service, try these commands:
```bash
as-service.bat -port <port>
as-service.bat -pid <pid>
as-service.bat -pid <pid> --interact
```
Use this command to remove arthas service:
```bash
as-service.bat -remove
```
## Manual command line startup ## Manual command line startup
If you fail to boot Arthas with the provided batch file, you could try to assemble the bootstrap command in the following way. If you fail to boot Arthas with the provided batch file, you could try to assemble the bootstrap command in the following way.

View File

@ -67,6 +67,19 @@ curl -L https://alibaba.github.io/arthas/install.sh | sh
as.bat <pid> 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
```
## 手动拼接命令行启动 ## 手动拼接命令行启动
如果启动遇到问题,可以尝试手动拼接出命令行参数来启动。 如果启动遇到问题,可以尝试手动拼接出命令行参数来启动。