在我们线上项目中,版本迭代很多操作需要重新、关闭、开启应用程序,这样我们就需要登录服务器去命令中操作。
如果我们定制开发一个web程序去控制项目的重启与关闭,这样就需要在web界面中实时反馈重启与关闭时的日志反馈信息,这样如果出现异常方便我们及时处理。如果要实时反馈的话,这里提供解决方案是使用websocket + sh 命令
tail 这样来实时获取日志文件里面信息,java 获取到对应流信息并输出到websocket 中 反馈给客户端
这里使用的是Spring Boot websocket
package cn.jiangzeyin.socket;
import cn.jiangzeyin.system.log.SystemLog;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by jiangzeyin on 2017/9/8.
*/
@ServerEndpoint("/log")
@Component
public class LogWebSocketHandle implements TailLogThread.Evn {
private Process process;
private InputStream inputStream;
private TailLogThread thread;
/**
* 新的WebSocket请求开启
*/
@OnOpen
public void onOpen(Session session) {
try {
SystemLog.LOG().info("创建 socket id " + session.getId());
// 执行tail -f命令
process = Runtime.getRuntime().exec("tail -f /test/run.log");
inputStream = process.getInputStream();
// 一定要启动新的线程,防止InputStream阻塞处理WebSocket的线程
thread = new TailLogThread(inputStream, session, this);
Thread thread_ = new Thread(thread);
thread_.start();
} catch (IOException e) {
SystemLog.ERROR().error("打开异常", e);
}
}
@OnMessage
public void onMessage(String message, Session session) {
SystemLog.LOG().info("客户端消息:" + message);
}
/**
* WebSocket请求关闭
*/
@OnClose
public void onClose() {
try {
if (inputStream != null)
inputStream.close();
} catch (Exception e) {
SystemLog.ERROR().error("关闭异常", e);
}
if (process != null)
process.destroy();
if (thread != null)
thread.stop();
SystemLog.LOG().info(" socket 关闭");
}
@OnError
public void onError(Throwable thr) {
onClose();
SystemLog.ERROR().error("socket 异常", thr);
}
@Override
public void onError() {
onClose();
}
}
package cn.jiangzeyin.socket;
import cn.jiangzeyin.system.log.SystemLog;
import javax.websocket.Session;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Created by jiangzeyin on 2017/9/8.
*/
public class TailLogThread implements Runnable {
private BufferedReader reader;
private Session session;
private boolean run = true;
private Evn evn;
public TailLogThread(InputStream in, Session session, Evn evn) {
this.reader = new BufferedReader(new InputStreamReader(in));
this.session = session;
this.evn = evn;
}
public void stop() {
run = false;
}
@Override
public void run() {
String line;
int errorCount = 0;
try {
while (run && (line = reader.readLine()) != null) {
// 将实时日志通过WebSocket发送给客户端,给每一行添加一个HTML换行
try {
session.getBasicRemote().sendText(line + "<br>");
} catch (Exception e) {
SystemLog.ERROR().error("发送消息失败", e);
errorCount++;
if (errorCount == 10) {
SystemLog.LOG().info("失败次数超过10次,结束本次事件");
if (evn != null)
evn.onError();
break;
}
}
}
} catch (IOException e) {
SystemLog.ERROR().error("读取异常", e);
}
SystemLog.LOG().info("结束本次读取地址事件");
}
public interface Evn {
void onError();
}
}