通过Nigix进行转发查看堡垒机日志功能和远程控制jar启动或者关闭
调用此接口进行获取堡垒机日志信息,可以及时解决问题。
代码有很多可以优化部分,这个只是几个小时写出来的,
下列代码实现放入配置nigix的服务即可。
传入参数对象LogsBean
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* @author JMW
*/
@Data
public class LogsBean {
@JsonProperty(value = "path")
private String path;
@JsonProperty(value = "cows")
private String cows;
@JsonProperty(value = "model")
private String model="段末";
@JsonProperty(value = "ip")
private String ip;
}
工具类方法功能LogsUtils
package cn.com.wind.windbdgriskvalidserver.logs;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author JMW
*/
public class LogsUtils {
public static String readLastLinesFor(String osPath, String line, String charset, StringBuilder errorMsg) {
int lines = Integer.valueOf(line);
//通过获取文件偏移量
RandomAccessFile randomAccessFile = null;
StringBuilder sb = new StringBuilder();
try {
File file = new File(osPath);
if (!file.exists() || file.isDirectory() || !file.canRead()) {
return null;
}
randomAccessFile = new RandomAccessFile(file, "r");
//文件总的偏移量
long len = randomAccessFile.length();
if (len == 0l) {
return "";
} else {
//取其前一位,循环找到200行的具体偏移量
long pos = len - 1;
while (pos > 0 && lines > 0) {
pos--;
//获取当前pos
randomAccessFile.seek(pos);
if (randomAccessFile.readByte() == '\n') {
lines--;
}
}
//根据偏移量创建byte数组
byte[] bytes = new byte[(int) (len - pos)];
randomAccessFile.read(bytes);
//编码按照个人需要,源码默认是"GB-2312"
if (charset == null) {
return new String(bytes);
} else {
return new String(bytes, charset);
}
}
} catch (Exception e) {
StackTraceElement[] stackTrace = e.getStackTrace();
for (int i = 0; i < stackTrace.length; i++) {
StackTraceElement stackTraceElements = stackTrace[i];
errorMsg.append(stackTraceElements.toString()+"\n");
}
e.printStackTrace();
} finally {
try {
if (randomAccessFile != null) {
randomAccessFile.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return "";
}
/**
* 获取Ip地址的方法
*
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request,StringBuilder errorMsg) {
String ipAddress = null;
try {
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1")) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
StackTraceElement[] stackTrace = e.getStackTrace();
for (int i = 0; i < stackTrace.length; i++) {
StackTraceElement stackTraceElements = stackTrace[i];
errorMsg.append(stackTraceElements.toString()+"\n");
}
}
ipAddress = inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
// "***.***.***.***".length()
if (ipAddress != null && ipAddress.length() > 15) {
// = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
} catch (Exception e) {
ipAddress = "";
}
return ipAddress;
}
public static int readLinesLength(String osPath, List list, StringBuilder errorMsg) {
//使用缓冲区的方法将数据读入到缓冲区中
BufferedReader br = null;
LineNumberReader reader = null;
//定义行数
String s = null;
int lines = 0;
//确定行数
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(osPath)));
reader = new LineNumberReader(br);
s = reader.readLine();
while (s != null) {
s = reader.readLine();
list.add(s);
lines++;
}
} catch (Exception e) {
StackTraceElement[] stackTrace = e.getStackTrace();
for (int i = 0; i < stackTrace.length; i++) {
StackTraceElement stackTraceElements = stackTrace[i];
errorMsg.append(stackTraceElements.toString()+"\n");
}
} finally {
try {
if (reader!=null){
reader.close();
}
if (br!=null){
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//返回行数
return lines;
}
public static String APIExplain() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("┌──────────────────────────────────────────────────────────────────────────────────────────────┐\n");
stringBuilder.append("│【API说明:】\n");
stringBuilder.append("│ 参数一:path传入需要访问地址最好使用【/】符合Linux路径\n");
stringBuilder.append("│ 【如果只写入path参数可以查询当前路径下的目录结构】:前提是一切路径服务 /data/wind/XXX/ \n");
stringBuilder.append("│ 参数二:cows传入需要行数使用字符串形式JSON:\n");
stringBuilder.append("│ 1.\"100\":默认后100行,可以不传入model因为不传入默认为后续查找\n");
stringBuilder.append("│ 2.\"100-200\":100-200行,当使用范围模式时候才可以写成如下命令\n");
stringBuilder.append("│ 参数三:model传入需要模式字段 比如【范围】【段末】【匹配】模式。默认为段末,最后几百行\n");
stringBuilder.append("│ 参数四:ip传入你想要进行操作的IP地址\n");
stringBuilder.append("├──────────────────────────────────────────────────────────────────────────────────────────────┤\n");
stringBuilder.append("│【使用案例:】\n");
stringBuilder.append("│{\n");
stringBuilder.append("│ \"path\":\"C:/Users/jmwang.erics/Desktop/新建文件夹/release/src/logs/info.log\",\n");
stringBuilder.append("│ \"cows\":\"100-200\",\n");
stringBuilder.append("│ \"model\":\"范围\"\n");
stringBuilder.append("│ \"ip\":\"127.0.0.1\"\n");
stringBuilder.append("│}\n");
stringBuilder.append("│{\n");
stringBuilder.append("│ \"path\":\"C:/Users/jmwang.erics/Desktop/新建文件夹/release/src/logs/info.log\",\n");
stringBuilder.append("│ \"cows\":\"100\",\n");
stringBuilder.append("│ \"ip\":\"127.0.0.1\"\n");
stringBuilder.append("│}\n");
stringBuilder.append("│{\n");
stringBuilder.append("│ \"path\":\"C:/Users/jmwang.erics/Desktop/新建文件夹/release/src/logs/\",\n");
stringBuilder.append("│ \"ip\":\"127.0.0.1\"\n");
stringBuilder.append("│}\n");
stringBuilder.append("│{\n");
stringBuilder.append("│ \"path\":\"C:/Users/jmwang.erics/Desktop/新建文件夹/release/src/logs/info.log\",\n");
stringBuilder.append("│ \"cows\":\"匹配字段\",\n");
stringBuilder.append("│ \"model\":\"匹配\"\n");
stringBuilder.append("│ \"ip\":\"127.0.0.1\"\n");
stringBuilder.append("│}\n");
stringBuilder.append("└──────────────────────────────────────────────────────────────────────────────────────────────┘\n");
return stringBuilder.toString();
}
/**
* 匹配操作
*/
public static String getMatching(List<String> list, String match) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (StringUtils.isNotBlank(s) && s.contains(match)) {
stringBuilder.append(selfAdaptionString(i) + s + "\n");
}
}
return stringBuilder.toString();
}
static Map<Integer,String> selfAdaptionStringMap = (Map<Integer, String>) new HashMap()
.put(1," ");
/**
* 自动补全函数
*/
public static String selfAdaptionString(int i) {
String length = String.valueOf(i);
switch (length.length()) {
case 1: {
return i + " ";
}
case 2: {
return i + " ";
}
case 3: {
return i + " ";
}
case 4: {
return i + " ";
}
case 5: {
return i + " ";
}
default: {
return i + "";
}
}
}
public static boolean isNumeric(String str){
for(int i=str.length();--i>=0;){
int chr=str.charAt(i);
if(chr<48 || chr>57)
return false;
}
return true;
}
}
前端接口提供 LogsController
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* @author JMW
*/
@RestController
@Slf4j
public class LogsController {
final static String STRING = "^[\\/]data[\\/]wind[\\/].+[\\/]";
final static Pattern pattern = Pattern.compile(STRING);
@PostMapping(value = "/log", consumes = {"application/json"})
public String getLogs(@RequestBody LogsBean logsBean) {
StringBuilder errorMsg = new StringBuilder();
String path = logsBean.getPath();
String cows = logsBean.getCows();
String model = logsBean.getModel();
String ip = logsBean.getIp();
StringBuilder stringBuilder = new StringBuilder();
if (!pattern.matcher(path).find()) {
stringBuilder.append("传入参数非.log文件,请参考API调用:\n" + LogsUtils.APIExplain());
return stringBuilder.toString();
}
//如果只有path
if (StringUtils.isNotBlank(path)
&& StringUtils.isBlank(cows)
&& model.equals("段末")) {
stringBuilder.append("当前目录结构为:\n");
File file = new File(path);
if (!file.exists()) {
stringBuilder.delete(0, stringBuilder.length());
stringBuilder.append("当前目录结构不存在或没有正确使用API,请参考API调用:\n" + LogsUtils.APIExplain());
} else {
PathTree.getPath(new File(path), stringBuilder);
}
return stringBuilder.toString();
}
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String ipAddr = LogsUtils.getIpAddr(request, errorMsg);
List list = new ArrayList<>();
//int cowslength
int cowsLength = 0;
try {
InetAddress addr = InetAddress.getLocalHost();
String hostName = addr.getHostName();
String hostAddress = addr.getHostAddress();
if (StringUtils.isNotBlank(ip)
&& !ComPIp(hostAddress, ip)) {
stringBuilder.append("【输入IP】:" + ip + "\n");
stringBuilder.append("【主机IP】:" + hostAddress + "\n");
stringBuilder.append("IP输出错误或者IP地址与本机不相等,请参考API调用:" + "\n" + LogsUtils.APIExplain());
stringBuilder.append(errorMsg.toString());
return stringBuilder.toString();
}
if (StringUtils.isNotBlank(hostName) || StringUtils.isNotBlank(hostAddress))
stringBuilder.append("主机名 为:【" + addr.getHostName() + "】\n主机地址为:【" + addr.getHostAddress() + "】\n");
cowsLength = LogsUtils.readLinesLength(path, list, errorMsg);
stringBuilder.append("日志行数为:【" + cowsLength + "】\n");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
log.error("【" + ipAddr + "】" + "调用了主站日志");
System.out.println("【" + ipAddr + "】" + "调用了主站日志");
String[] split = null;
if (StringUtils.isNotBlank(cows)) {
split = cows.split("-");
} else {
stringBuilder.delete(0, stringBuilder.length());
stringBuilder.append("当前目录结构不存在或传入参数错误,请参考API调用:" + "\n" + LogsUtils.APIExplain());
stringBuilder.append(errorMsg.toString());
return stringBuilder.toString();
}
switch (model) {
case "范围":
if (split.length == 2
&& (Integer.valueOf(split[1]) - Integer.valueOf(split[0])) < cowsLength
&& Integer.valueOf(split[1]) < cowsLength) {
for (int i = Integer.valueOf(split[0]); i < Integer.valueOf(split[1]); i++) {
stringBuilder.append(list.get(i) + "\n");
}
} else {
stringBuilder.delete(0, stringBuilder.length());
stringBuilder.append("文件最大值为:【" + cowsLength + "】,您已经超过了文件最大值,希望年轻人不要不讲武德!\n");
stringBuilder.append("【范围】查找失败!请按照规定调用API" + "\n" + LogsUtils.APIExplain());
}
break;
case "段末": {
if (split.length == 1 && LogsUtils.isNumeric(cows)) {
stringBuilder.append(LogsUtils.readLastLinesFor(path, cows, "UTF-8", errorMsg));
} else {
stringBuilder.delete(0, stringBuilder.length());
stringBuilder.append("【段末】查找失败!请按照规定调用API" + "\n" + LogsUtils.APIExplain());
}
break;
}
case "匹配": {
String matching = LogsUtils.getMatching(list, cows);
if (StringUtils.isBlank(matching)) {
stringBuilder.append("【匹配】结果为空");
} else {
stringBuilder.append(matching);
}
break;
}
default: {
stringBuilder.delete(0, stringBuilder.length());
stringBuilder.append("传入参数错误请参考API调用:" + "\n" + LogsUtils.APIExplain());
}
}
if (errorMsg.length() != 0) {
stringBuilder.delete(0, stringBuilder.length());
stringBuilder.append("传入参数错误请参考API调用:" + "\n" + LogsUtils.APIExplain());
stringBuilder.append(errorMsg.toString());
}
return stringBuilder.toString();
}
final static String linuxExec = "^[\\/]data[\\/]wind[\\/].+[\\/]bin[\\/]$";
final static Pattern linuxExecP = Pattern.compile(linuxExec);
final static String linuxExeS = "^(sh\\sstart.sh|sh\\sstop.sh)$";
final static Pattern linuxExecS = Pattern.compile(linuxExeS);
@PostMapping(value = "/linuxExec", consumes = {"application/json"})
public String getLogs(@RequestBody LinuxBean linuxBean) {
StringBuilder errorString = new StringBuilder();
StringBuilder stringBuilder = new StringBuilder();
String path = linuxBean.getPath();
String shell = linuxBean.getShell();
String ip = linuxBean.getIp();
InetAddress addr = null;
try {
addr = InetAddress.getLocalHost();
String hostAddress = addr.getHostAddress();
if (StringUtils.isNotBlank(ip)
&& !ComPIp(hostAddress, ip)) {
stringBuilder.append("【输入IP】:" + ip + "\n");
stringBuilder.append("【主机IP】:" + hostAddress + "\n");
stringBuilder.append("IP输出错误或者IP地址与本机不相等,请参考API调用:" + "\n" + LogsUtils.APIExplain());
stringBuilder.append(errorString.toString());
return stringBuilder.toString();
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
if (StringUtils.isNotBlank(shell)
&& StringUtils.isNotBlank(path)
&& linuxExecP.matcher(path).find()
&& linuxExecS.matcher(shell).find()
) {
List<String> list = new ArrayList();
list.add(shell);
if (path != null) {
list.add(path);
}
List<String> list1 = StarterTerminator.executeNewFlow(list, errorString);
for (int i = 0; i < list1.size(); i++) {
stringBuilder.append(list.get(i));
}
} else {
stringBuilder.append("我寻思你这参数传入的也不对吧 。◕‿◕。\n");
stringBuilder.append(LinuxUtils.APIExplain());
}
return stringBuilder.toString();
}
/**
* ip地址校验
*/
public static boolean ComPIp(String LocalIp, String CurIp) {
return LocalIp.equals(CurIp);
}
}
传入参数对象LinuxBean
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* @author JMWANG
*/
@Data
public class LinuxBean {
@JsonProperty(value = "path")
private String path;
@JsonProperty(value = "shell")
private String shell;
@JsonProperty(value = "ip")
private String ip;
}
工具类方法功能LinuxUtils
/**
* @author JMWANG
*/
public class LinuxUtils {
public static String APIExplain() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("┌──────────────────────────────────────────────────────────────────────────────────────────────┐\n");
stringBuilder.append("│【API说明:】\n");
stringBuilder.append("│ 参数一:path传入需要访问地址最好使用【/】符合Linux路径\n");
stringBuilder.append("│ 【如果只写入path参数可以查询当前路径下的目录结构】:前提是一切路径服务 /data/wind/XXX/bin/ \n");
stringBuilder.append("│ 参数二:shell传入需要行数使用字符串形式JSON:\n");
stringBuilder.append("│ 只可以存在 sh start.sh | sh stop.sh\n");
stringBuilder.append("│ 参数三:ip传入你想要进行操作的IP地址\n");
stringBuilder.append("├──────────────────────────────────────────────────────────────────────────────────────────────┤\n");
stringBuilder.append("│【使用案例:】\n");
stringBuilder.append("│{\n");
stringBuilder.append("│ \"shell\":\"sh start.sh\",\n");
stringBuilder.append("│ \"path\":\"/wind/Wind.BDG.RiskValidServer/Codi/bin/\"\n");
stringBuilder.append("│ \"ip\":\"127.0.0.1\"\n");
stringBuilder.append("│}\n");
stringBuilder.append("└──────────────────────────────────────────────────────────────────────────────────────────────┘\n");
return stringBuilder.toString();
}
}
路径树PathTree
import java.io.File;
import java.util.Stack;
/**
* @author JMWANG
*/
public class PathTree {
public static void getPath(File file, StringBuilder sb) {
sb.append("┌──────────────────────────────────────────────────────────────────────────────────────────────┐\n");
traversal(file, 1, sb);
sb.append("└──────────────────────────────────────────────────────────────────────────────────────────────┘\n");
}
public static void traversal(File file, int depth, StringBuilder sb) {
printName(file, depth, sb);
File[] fileArray = file.listFiles();
if (fileArray==null){
return;
}
Stack<File> stack = new Stack<File>();
for (File f : fileArray) {
if (f.isFile()) {
printName(f, depth + 1, sb);
} else {
stack.add(f);
}
}
while (stack.isEmpty() == false) {
traversal(stack.pop(), depth + 1, sb);
}
}
public static void printName(File f, int signNum, StringBuilder sb) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < signNum; i++) {
if (i == signNum - 1)
stringBuilder.append("│--");
else if (i == 0) stringBuilder.append("│ ");
else stringBuilder.append(" ");
}
if (f.isDirectory())
stringBuilder.append("/" + f.getName() + "/");
else
stringBuilder.append(f.getName());
int length = stringBuilder.length();
for (int i = 0; i < 96 - length; i++) {
if (i == 96 - length - 1) {
stringBuilder.append("│");
} else {
stringBuilder.append(" ");
}
}
sb.append(stringBuilder.toString() + "\n");
}
}
远程方法linux shell器StarterTerminator
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* @author JMWANG
*/
public class StarterTerminator {
public static List<String> executeNewFlow(List<String> commands,StringBuilder errorString) {
List<String> rspList = new ArrayList<String>();
Runtime run = Runtime.getRuntime();
try {
// Process proc = run.exec("sh start.sh", null, new File("/wind/Wind.BDG.RiskValidServer/Codi/bin/"));
Process proc = null;
if (commands.size() == 2)
proc = run.exec(commands.get(0), null, new File(commands.get(1)));
else
proc = run.exec(commands.get(0), null, null);
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
for (String line : commands) {
out.println(line);
}
out.println("exit");// 这个命令必须执行,否则in流不结束。
String rspLine = "";
while ((rspLine = in.readLine()) != null) {
System.out.println(rspLine);
rspList.add(rspLine);
}
proc.waitFor();
in.close();
out.close();
proc.destroy();
} catch (Exception e) {
StackTraceElement[] stackTrace = e.getStackTrace();
for (int i = 0; i < stackTrace.length; i++) {
StackTraceElement stackTraceElements = stackTrace[i];
errorString.append(stackTraceElements.toString()+"\n");
}
}
return rspList;
}
}
如有错误欢迎指正