由于工作需要我們想要實(shí)現(xiàn)一個(gè)從頁(yè)面能夠查看tomcat后臺(tái)日志的功能洋侨,我們有兩種方案:
- 將日志保存到mongo DB中宪迟,從頁(yè)面進(jìn)行查看呀忧,mongo DB中的日志定期清理
- 通過(guò)WebSocket實(shí)現(xiàn)讀取后臺(tái)日志的功能蚜点,最簡(jiǎn)單的就是利用tail命令實(shí)現(xiàn)
下面主要說(shuō)一下我在通過(guò)WebSocket實(shí)現(xiàn)tail查看實(shí)時(shí)滾動(dòng)日志時(shí)遇到的問(wèn)題和解決方法
首先呢荆虱,我先在GitHub上找到了一個(gè)例子
文章的末尾有GitHub的地址,我down了下來(lái)纸颜, 需要注意三個(gè)地方
- pom中下面的dependency scope一定要設(shè)置成provided兽泣,避免與tomcat自帶的websocket-api沖突,我遇到問(wèn)題時(shí)查了很多帖子胁孙,有些說(shuō)沒(méi)有影響的唠倦,但是萬(wàn)一要有影響呢,包沖突還是最好避免掉
<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) {
// 接收服務(wù)端的實(shí)時(shí)日志并添加到HTML頁(yè)面中
$("#log-container div").append(event.data);
// 滾動(dòng)條滾動(dòng)到最低部
$("#log-container").scrollTop($("#log-container div").height() - $("#log-container").height());
};
});
</script>
其中
var websocket = new WebSocket('ws://192.168.80.128:8080/websocket/log');
這句的路徑一定要寫(xiě)對(duì)涮较,我從GitHub上拉下來(lái)的代碼稠鼻, 是這樣的
var websocket = new WebSocket('ws://192.168.80.128:8080/log');
看著沒(méi)什么區(qū)別,因?yàn)槟阌帽镜胤?wù)器啟動(dòng)時(shí)狂票,這個(gè)路徑取決于你再I(mǎi)DE中的設(shè)置
如果路徑是像我上面那樣寫(xiě)候齿,就要按照ws://ip:port/applicationContext/requestMapping格式去寫(xiě),否則就會(huì)報(bào)無(wú)法連接的錯(cuò)誤
如果你的application context是"/", 就按ws://ip:port/requestMapping格式寫(xiě)就OK
我就是在這就出現(xiàn)的問(wèn)題慌盯,因?yàn)槲沂窍胪ㄟ^(guò)tail命令去讀tomcat logs下的catalina.out周霉,所以我打好包,發(fā)到linux服務(wù)器進(jìn)行測(cè)試時(shí)润匙,報(bào)了404錯(cuò)誤诗眨,F(xiàn)irefox 無(wú)法建立到 ws://192.168.80.128:8080/log 服務(wù)器的連接唉匾。
因?yàn)槲掖虻陌莣ebsockettail-1.0.0.war
<groupId>com.xxg</groupId>
<artifactId>websockettail</artifactId>
<version>1.0.0</version>
所以實(shí)際上默認(rèn)的Application Context路徑并不是"/"孕讳, 而是“websockettail-1.0.0”, 對(duì)應(yīng)的ws路徑應(yīng)為ws://192.168.80.128:8080/websockettail-1.0.0/log
改好之后就可以正常輸出了巍膘, 我測(cè)試的命令是"ifconfig"
這里還是比較容易出錯(cuò)的厂财,一定要注意
- 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();
// 一定要啟動(dòng)新的線程,防止InputStream阻塞處理WebSocket的線程
TailLogThread thread = new TailLogThread(inputStream, session);
thread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
這三個(gè)地方都改好后再放到Linux服務(wù)器上啟動(dòng)峡懈,就沒(méi)問(wèn)題了璃饱。
下面再說(shuō)一下使用Nginx對(duì)Websocket進(jìn)行反向代理的配置
公司的項(xiàng)目都是走的nginx反向代理,可以通過(guò)改nginx.conf來(lái)實(shí)現(xiàn)
修改Nginx主配置文件
$ vim /usr/local/nginx/conf/nginx.conf
# 在http上下文中增加如下配置肪康,確保Nginx能處理正常http請(qǐng)求荚恶。
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反向代理沒(méi)有任何差別。
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
這里面的關(guān)鍵部分在于HTTP的請(qǐng)求中多了如下頭部:
Upgrade: websocket
Connection: Upgrade
這兩個(gè)字段表示請(qǐng)求服務(wù)器升級(jí)協(xié)議為WebSocket雾狈。服務(wù)器處理完請(qǐng)求后廓潜,響應(yīng)如下報(bào)文:
狀態(tài)碼為101
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
配置改好后執(zhí)行
nginx -s reload
就可以正常訪問(wèn)
參考博客地址:
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