由于工作需要我們想要實現(xiàn)一個從頁面能夠查看tomcat后臺日志的功能,我們有兩種方案:
- 將日志保存到mongo DB中,從頁面進行查看,mongo DB中的日志定期清理
- 通過WebSocket實現(xiàn)讀取后臺日志的功能,最簡單的就是利用tail命令實現(xiàn)
下面主要說一下我在通過WebSocket實現(xiàn)tail查看實時滾動日志時遇到的問題和解決方法
首先呢,我先在GitHub上找到了一個例子
文章的末尾有GitHub的地址,我down了下來, 需要注意三個地方
- pom中下面的dependency scope一定要設置成provided,避免與tomcat自帶的websocket-api沖突,我遇到問題時查了很多帖子,有些說沒有影響的,但是萬一要有影響呢,包沖突還是最好避免掉
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
- index.html中的js腳本
<script>
$(document).ready(function() {
// 指定websocket路徑
var websocket = new WebSocket('ws://192.168.80.128:8080/websocket/log');
websocket.onmessage = function(event) {
// 接收服務端的實時日志并添加到HTML頁面中
$("#log-container div").append(event.data);
// 滾動條滾動到最低部
$("#log-container").scrollTop($("#log-container div").height() - $("#log-container").height());
};
});
</script>
其中
var websocket = new WebSocket('ws://192.168.80.128:8080/websocket/log');
這句的路徑一定要寫對,我從GitHub上拉下來的代碼, 是這樣的
var websocket = new WebSocket('ws://192.168.80.128:8080/log');
看著沒什么區(qū)別,因為你用本地服務器啟動時,這個路徑取決于你再IDE中的設置


如果路徑是像我上面那樣寫,就要按照ws://ip:port/applicationContext/requestMapping格式去寫,否則就會報無法連接的錯誤
如果你的application context是"/", 就按ws://ip:port/requestMapping格式寫就OK
我就是在這就出現(xiàn)的問題,因為我是想通過tail命令去讀tomcat logs下的catalina.out,所以我打好包,發(fā)到linux服務器進行測試時,報了404錯誤,F(xiàn)irefox 無法建立到 ws://192.168.80.128:8080/log 服務器的連接。
因為我打的包是websockettail-1.0.0.war
<groupId>com.xxg</groupId>
<artifactId>websockettail</artifactId>
<version>1.0.0</version>
所以實際上默認的Application Context路徑并不是"/", 而是“websockettail-1.0.0”, 對應的ws路徑應為ws://192.168.80.128:8080/websockettail-1.0.0/log
改好之后就可以正常輸出了, 我測試的命令是"ifconfig"

這里還是比較容易出錯的,一定要注意
- LogWebSocketController中的命令改成tail命令
@OnOpen
public void onOpen(Session session) {
try {
// 執(zhí)行tail -f命令
process = Runtime.getRuntime().exec("tail -f /opt/XXX/logs/catalina.out -n 500");
inputStream = process.getInputStream();
// 一定要啟動新的線程,防止InputStream阻塞處理WebSocket的線程
TailLogThread thread = new TailLogThread(inputStream, session);
thread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
這三個地方都改好后再放到Linux服務器上啟動,就沒問題了。
下面再說一下使用Nginx對Websocket進行反向代理的配置
公司的項目都是走的nginx反向代理,可以通過改nginx.conf來實現(xiàn)
修改Nginx主配置文件
$ vim /usr/local/nginx/conf/nginx.conf
# 在http上下文中增加如下配置,確保Nginx能處理正常http請求。
http{
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket {
#ip_hash;
server localhost:8010;
server localhost:8011;
}
# 以下配置是在server上下文中添加,location指用于websocket連接的path。
server {
listen 80;
server_name localhost;
access_log /var/log/nginx/yourdomain.log;
location / {
proxy_pass http://websocket;
proxy_read_timeout 300s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
}
最重要的就是在反向代理的配置中增加了如下兩行,其它的部分和普通的HTTP反向代理沒有任何差別。
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
這里面的關鍵部分在于HTTP的請求中多了如下頭部:
Upgrade: websocket
Connection: Upgrade
這兩個字段表示請求服務器升級協(xié)議為WebSocket。服務器處理完請求后,響應如下報文:
狀態(tài)碼為101
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
配置改好后執(zhí)行
nginx -s reload
就可以正常訪問

參考博客地址:
http://xxgblog.com/2015/11/25/java-websocket-tail/
https://www.hi-linux.com/posts/42176.html
以上代碼可以從github上獲取, 我修改了一些東西,致敬原創(chuàng)者
https://github.com/CarolineHuang5954/websocket-tail-demo.git