logstash 啟動報無法找到主類解決方案
當logstash啟動時,首先要注意正確配置java
並且最近版本的logstash要求java8
在搞定以上后確認環境變量沒有問題
再確認logstash所在的目錄 不存在含有空格的文件夾名稱
在這所有所有之后還是會報錯:找不到或無法加載主類 (亂序地址)
解決方案
廢話不多說:找到logstash/bin目錄下的logstash.bat
打開編輯,找到如下行
%JAVA% %JAVA_OPTS% -cp "%CLASSPATH%" org.logstash.Logstash %*
這行與你的應該有所區別,沒錯
將%CLASSPATH%改為"%CLASSPATH%"即可解決
讓我學習一下批處理寫法 理解一下這行為什么這樣,之后,有空再解釋原因
2018年3月9日17:19:19更新
產生原因
PS G:\Users\XXX\Desktop> ./logstash.bat
錯誤: 找不到或無法加載主類 Files\Java\jdk1.8.0_161\lib;G:"Program
以上是錯誤命令運行的輸出 可以看到 找不到或無法加載主類,而后跟着的目錄為
Files\Java\jdk1.8.0_161\lib;G:"Program
因為我的jdk 放在G:\Program Files\java\jdk1.8.0_161\lib下了,因此一開始百思不得其解,什么錯誤會產生位置字符串中間截斷然后顛倒這種迷之錯誤。
因為logstash啟動文件是個批處理,這樣調試起來就很方便在,在各行插入pause語句調試,最后將錯誤定位到52行
%JAVA% %JAVA_OPTS% -cp %CLASSPATH% org.logstash.Logstash %*
今天學習了一下批處理語法,這一句無非是將一些變量組合成為新的語句再執行而已,那么錯誤不在批處理程序,因為自己再寫批處理的話難保拿到的變量與運行時完全一樣所以直接在logstash.bat中插入了一些語句將其輸出(因為沒那么多時間閱讀全文,前面已經提到了直接定位到了出錯是這一句)
%JAVA% %JAVA_OPTS% -cp %CLASSPATH% org.logstash.Logstash %*
pause
echo %JAVA% >>a.txt echo " " >>a.txt echo %JAVA_OPTS%>>a.txt echo " " >>a.txt echo %CLASSPATH%>>a.txt echo " " >>a.txt echo %*>>a.txt echo " " >>a.txt echo "%CLASSPATH%" >>a.txt pause
將上面的語句改寫成這樣,將變量全部輸出到a.txt,檢查該文件
"G:\Program Files\Java\jdk1.8.0_161\bin\java.exe"
-Xms1------很長的字符串------/urandom
.;G:\Program Files\Java\jdk1.8.0_161\lib;G:\Program Files\Java\jdk1.8.0_161\lib\tools.jar;"E:\logstash-6.2.2\logstash-core\lib\jars\animal-sniffer-annotations-1.14.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\commons-compiler-3.0.8.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\error_prone_annotations-2.0.18.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\google-java-format-1.5.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\guava-22.0.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\j2objc-annotations-1.1.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\jackson-annotations-2.9.1.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\jackson-core-2.9.1.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\jackson-databind-2.9.1.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\jackson-dataformat-cbor-2.9.1.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\janino-3.0.8.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\javac-shaded-9-dev-r4023-3.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\jruby-complete-9.1.13.0.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\jsr305-1.3.9.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\log4j-api-2.9.1.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\log4j-core-2.9.1.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\log4j-slf4j-impl-2.9.1.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\logstash-core.jar";"E:\logstash-6.2.2\logstash-core\lib\jars\slf4j-api-1.7.25.jar"
-f ../config/pipeline.conf
抱歉我知道上面這坨太冗雜了但是相信我,比較重要吧。
觀察上面這些輸出,再結合logstash.bat中的實際語序,可以發現這實際上是一句簡單的java程序啟動的cmd.
java -opt1 -opt2 -cp "classpath" org.logstash.Logstash -f ../config/pipeline.conf
那么到這一步 再結合錯誤輸出為找不到或無法加載主類,可以猜測是-cp 之后的classpath出現了問題。
仔細觀察classpath,發現一些問題,該字符串明顯為拼接字符串,然而有些地址用雙引號("")括起來了,有些沒有。再觀察,可以發現括起來的為logstash自己的jar包,沒有的則為系統本身的CLASSPATH環境變量的值。
猜測由雙引號引起該問題,再加上前面的解決方案是在整個%CLASSPATH%變量外面加 "" 可以猜測為系統本身的CLASSPATH沒有加上雙引號引起的,按照他的style將雙引號加在每個地址上,問題解決。
繼續研究。回到logstash/bat文件,發現
:concat
IF not defined CLASSPATH ( set CLASSPATH="%~1" ) ELSE ( set CLASSPATH=%CLASSPATH%;"%~1" )
很明顯 該代碼段產生了整個批處理文件中實際調用的CLASSPATH
調用該代碼段的地方是
for %%i in ("%LS_HOME%\logstash-core\lib\jars\*.jar") do ( call :concat "%%i" )
很容易懂的一個循環,對logstash目錄下的\logstash-core\lib\jars\下的所有jar包循環,將包名作為參數執行上上的那個代碼段,即
將logstash jar包目錄下的所有jar包的所在路徑連接到系統本身的CLASSPATH路徑之后
那么到此CLASSPATH的產生方式已經很明顯了,錯誤也很明顯了,產生CLASSPATH時,因為系統中有CLASSPATH變量因此直接執行ELSE部分,將系統變量通過 "%CLASSPATH%" 的方式直接讀取,在之后加上;"%~1"
這里%~1的作用是取第一個參數並去掉雙引號,第一個參數是循環的當時系數,而去掉雙引號之后又加上了雙引號所以最后的結果是有雙引號的,這也就是我們看到的 調用的CLASSPATH后面的logstash的包都有雙引號的原因。而在循環第一次執行的時候,直接用了系統的%CLASSPATH%這里是沒有雙引號的,因此結果也沒有(不能在這里加雙引號,因為隨着循環,引號會被遞歸加上,整個路徑會亂掉)
這里有一個另外的思考,前面的輸出a.txt文件可以看到,直接用%JAVA%輸出的java.exe所在目錄實際上竟然是有雙引號的,而我自己寫了個批處理 "echo %JAVA%顯示的是echo 開關狀態,證明找不到JAVA這個系統變量,這是顯然的,但是我在logstash.bat中竟然沒有找到對變量JAVA的set操作,也就是說找不到這個JAVA地址是在何處獲得並賦值的,也就無法研究java.exe的路徑為何是有雙引號的。
重要的解釋
我認為還需要解釋一下為什么不加引號就會炸,大家還記得最開始的錯誤輸出吧
PS G:\Users\XXX\Desktop> ./logstash.bat
錯誤: 找不到或無法加載主類 Files\Java\jdk1.8.0_161\lib;G:"Program
這其實並不是地址斷掉了或者說倒置了,而是Program FIile 中間有一個空格,批處理文件以空格作為分格符,由於我的jdk放置在系統盤的program file文件夾下,因此我的環境變量的classpath中有兩個包含空格的路徑,批處理命令將第一個空格前的內容作為java -cp命令中的classpath地址傳入, 后兩個空格間的"Files\Java\jdk1.8.0_161\lib;G:"Program"自然就作為主類傳入了,因此產生了如此奇怪的輸出。而解決空格的方法就是: