java从服务器日志截取请求/响应XML报文或截取指定字符串
在做接口自动化过程中,需要获取请求/响应的xml报文,因为是银行系统,服务器组报文了发送到ESB服务器,请求和响应的报文会打印在ESB服务器的日志中,当要截取N个请求的报文时通过人工截取显然效率低下,所有写了一个报文截取工具。
<?xml version="1.0" encoding="UTF-8"?>
<service>
<sys-header>
<data name="SYS_HEAD">
<struct>
<data name="field1">
<field type="string" length="17" scale="0">20180000000000000</field>
</data>
<data name="SEQ_NO">
<field type="string" length="52" scale="0">1111111111111111111</field>
</data>
<data name="field3">
<field type="string" length="2" scale="0">AA</field>
</data>
<data name="field4">
<field type="string" length="2" scale="0">00</field>
</data>
<data name="field5">
<field type="string" length="30" scale="0">00000000000</field>
</data>
<data name="field6">
<field type="string" length="30" scale="0">000000</field>
</data>
</struct>
</data>
</sys-header>
<app-header>
<data name="field7">
<struct>
<data name="field8">
<field type="string" length="22" scale="0">000000000000</field>
</data>
</struct>
</data>
</app-header>
<body>
<data name="field9">
<field type="string" length="3" scale="0">000</field>
</data>
<data name="Bfield10">
<field type="string" length="50" scale="0">000</field>
</data>
<data name="field11">
<field type="string" length="1" scale="0">000</field>
</data>
<data name="TRAN_ARRAY">
<array>
<struct>
<data name="field9">
<field type="string" length="3" scale="0">000</field>
</data>
<data name="field12">
<field type="string" length="10" scale="0">000</field>
</data>
</struct>
</array>
</data>
<data name="field13">
<field type="string" length="60" scale="0">000000</field>
</data>
<data name="field14">
<field type="string" length="6" scale="0"></field>
</data>
</body>
</service>
如上图所示,xml请求报文长这样,我需要在服务器中找到他所在的日志文件,并截取这个报文。
代码如下:
依赖jar包:ganymed-ssh2.jar
一:
此方法是连接服务器,并执行linux命令,多条命令用分好隔开,并将服务器的文件复制到本地
执行顺序是,连接服务器 -> 执行命令如 cd /home/wlt/log/20180730 ; grep -lr 213234234 * ; grep -lr 651254 * (这里三个命令会按照顺序执行,并将返回的执行结果保存在list中 ) -> 执行完查找命令后,会返回包含自定字符串的文件名称,并将文件名称保存下来 -> 遍历list依次从服务器下载对应的文件,并保存在本地
package cn.com;
import ch.ethz.ssh2.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class ConnectServer
{
public void connect (final String ip,final int port, final String username, final String password, String cd, String cmd, String localPath)
{
//连接服务器
Connection conn = new Connection(ip,port);
Session session = null;
List<String> resultList = new ArrayList<String>();
try {
conn.connect();
boolean isAuthenticated = conn.authenticateWithPassword(username, password);
if (isAuthenticated == false)
throw new IOException("连接到服务器时发生异常");
//执行远程命令,成功
session = conn.openSession();
if(cmd.contains(";"))
{
cmd = cmd.replace(";", " ; ");
}
System.out.println("正在服务器"+ip+"查找日志文件...");
System.out.println("执行多条命令:"+"cd "+cd +" ; " + cmd);
session.execCommand("cd "+cd +" ; " + cmd);//分号";"隔开执行多条命令,会逐条执行,并返回执行结果
//显示执行命令后的信息
InputStream stdout = new StreamGobbler(session.getStdout());
BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
String lineStr = null;
int count = 0;
StringBuffer sb = new StringBuffer();
while((lineStr = br.readLine()) != null)
{
if(lineStr.trim().length() != 0)
{
resultList.add(lineStr);
}
if(lineStr.contains("."))
{
sb.append(", "+lineStr.trim());
count++;
}
}
if(sb.toString().trim().length() != 0)
{
System.out.println("查找完成,共查到"+count+"个日志文件包含指定字符串, ["+sb.toString().substring(1)+"]");
}else
{
System.out.println("没有找到相关的日志");
}
session.close();
SCPClient client = new SCPClient(conn);
if(resultList.size() != 0)
{
System.out.println("开始复制日志文件到本地...");
for(String str : resultList)
{
String logFileName = cd.replace("cd", "").trim() ;
if(str.contains("."))
{
logFileName = str.endsWith("/") ? logFileName+str : logFileName+"/"+str ;
//System.out.println("logFileName:"+logFileName+" " +localPath );
client.get(logFileName, localPath); //将服务器文件复制到本地
}
//System.out.println(str);
}
System.out.println("文件复制完成");
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("连接到服务器时发生异常");
if (conn != null) {
conn.close();
}
if (session != null) {
session.close();
}
} finally {
if (conn != null) {
conn.close();
}
if (session != null) {
session.close();
}
}
System.out.println("已断开服务器连接");
}
public static void main(String[] args)
{
//测试
ConnectServer connectServer = new ConnectServer();
connectServer.connect("192.168.1.1", 22, "username", "000000", "cd /aaa/bbb/ccc/ddd", "grep -lr 213234234 * ; grep -lr aabbcc * ; ", "d:/test");
}
}
二.
这个类主要是读取服务器下载到的日志文件,找到指定的字符串,并截取字符串所在的xml报文。
如:想要找到包含seq_no=1111111111111111111的所有报文,先找到这个字段所在的行,然后再根据这行截取整个报文。
.....
<data name="SEQ_NO">
<field type="string" length="52" scale="0">1111111111111111111</field>
</data>
.....
三.主运行程序
报文命名、去掉重复报文等等
package cn.com;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ReadFile
{
//第二次读取文件,并截取xml报文
public String readFileAgain(int line,int beginLine,File file)
{
BufferedReader readerAgain = null;
int tmpLine = 0;
StringBuffer stringBuffer = new StringBuffer();
String messageStr = "";
FileInputStream in = null;
boolean boolBegain = false;
boolean boolEnd = false;
try
{
in = new FileInputStream(file);
readerAgain = new BufferedReader(new InputStreamReader(in, "UTF-8"));
//readerAgain = new BufferedReader(new FileReader(file));
tmpLine = line; //seq_no
int lineAgain = 1;
int linethree = 0;
String tempStringAgain = null;
while((tempStringAgain = readerAgain.readLine()) != null ) //&& lineAgain <= tmpLine
{
if(tempStringAgain.contains("<?xml") && lineAgain >= beginLine)
{
linethree = lineAgain;//上一次seq_no的位置
boolBegain = true;
}
if(linethree != 0 && lineAgain >= linethree && lineAgain <= tmpLine) //
{
//System.out.println(lineAgain + ": " + tempStringAgain);
stringBuffer.append(tempStringAgain.trim() );//+ "\r\n"
if(tempStringAgain.contains("</service>"))
{
boolEnd = true;
break;
}
}
if(lineAgain > tmpLine )
{
//System.out.println(lineAgain + ": " + tempStringAgain);
stringBuffer.append(tempStringAgain.trim() );//+ "\r\n"
if(tempStringAgain.contains("</service>"))
{
boolEnd = true;
break;
}
}
lineAgain ++;
}
if(boolBegain && boolEnd)
{
messageStr = stringBuffer.toString();
//System.out.println(messageStr);
messageStr = messageStr.substring(messageStr.indexOf("<?xml"));
messageStr = messageStr.substring(0,messageStr.indexOf("</service>")+10);
//System.out.println(messageStr);
}else{
System.out.println("文件第"+tmpLine+"行的seq_no可能不在报文中");
}
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}finally
{
try
{
in.close();
readerAgain.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
return messageStr;
}
/*
*读取文件,找到指定字符的位置
**/
public List<String> getDatagram(String logFilesPath,String target,String fieldName)
{
File file = new File(logFilesPath);
BufferedReader reader = null;
FileInputStream in = null;
int line = 1;
String str = "";
List<String> list = new ArrayList<String>();
boolean bool = false;
int headLine = 1;
try
{
in = new FileInputStream(file);
reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
String tempString = null;
while((tempString = reader.readLine()) != null)
{
if(tempString.contains("<?xml"))
{
headLine = line;//报文头开始的位置,始终保持最大行
}
if(tempString.contains(target) && line >= headLine)
{
bool = true;
str = readFileAgain(line,headLine, file);
//因为此字符是xml报文中两个字段拼接而成的
if(fieldName.substring(0, fieldName.indexOf(":")).equalsIgnoreCase("service_code"))//如果根据service_code查找,拼接service_code判断是否是指定的值
{
String servicecode = getValue("SERVICE_CODE" , str) + getValue("SERVICE_SCENE" , str);
//System.out.println(fieldName.substring(fieldName.indexOf(":")+1)+":"+servicecode);
if(fieldName.substring(fieldName.indexOf(":")+1).equalsIgnoreCase(servicecode))
{
list.add(str);
}
}else
{
list.add(str);
}
//System.out.println(str);
}
line ++;
}
//System.out.println("line = "+line);
if(!bool){
//System.err.println("文件"+logFilesPath.substring(logFilesPath.lastIndexOf("\\")+1)+"中未找到 SEQ_NO:"+target+" 请检查SEQ_NO是否正确");
}
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}finally
{
try
{
reader.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
return list;
}
/*
* 写入到文件
*/
public boolean writeFile(String fileName,String content)
{
boolean bool = false;
createFile(fileName);
File file = new File(System.getProperty("user.dir")+"\\"+getProperties("datagramfileName")+"\\"+fileName);
BufferedWriter bufferedWriter = null;
FileOutputStream fileOutputStream = null;
try
{
fileOutputStream = new FileOutputStream(file,false);
bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileOutputStream, "UTF-8"));
bufferedWriter.write(content);
bool = true;
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}finally
{
try
{
bufferedWriter.close();
fileOutputStream.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
return bool;
}
/*
* 新建文件
*/
public void createFile(String FileName)
{
String dirPath = System.getProperty("user.dir") + "\\datagramfiles";
File dir = new File(dirPath);
if (!dir.exists())
{
dir.mkdir();
} else
{
File file = new File(dirPath + "\\" + FileName);
try
{
if (!file.exists())
{
file.createNewFile();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
}
/*
* 获取目录下所有文件路径+名称
*/
public List<String> getFileName(String dirPath)
{
File file = new File(dirPath);
File[] files = file.listFiles();
List<String> fileNameList = new ArrayList<String>();
for(File file1 : files)
{
if(file1.getName().contains(".")){
fileNameList.add(file1.getAbsolutePath());
}
}
file.getAbsolutePath();
return fileNameList;
}
/*
* 查找报文的字段值
*/
public String getValue(String key, String datagram)
{
if(datagram.trim().length() == 0)
{
System.out.println("报文为空");
return "";
}
if(key.trim().length() == 0 || !datagram.contains(key))
{
System.out.println("报文中没有字段:"+key);
return "";
}
key = key.toUpperCase();
int index = datagram.indexOf(key);
datagram = datagram.substring(index);
datagram = datagram.substring(datagram.indexOf("<field"),datagram.indexOf("</field>"));
String fieldValue = datagram.substring(datagram.indexOf(">")+1);
return fieldValue;
}
/*
* 获取properties文件中的值
*/
public String getProperties(String key)
{
InputStream in = null;
String value = "";
try
{
in = new BufferedInputStream(new FileInputStream(System.getProperty("user.dir") + "\\args.properties"));
Properties properties = new Properties();
properties.load(in);
value = properties.getProperty(key);
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return value;
}
/*
*替换空格、换行符等等
*/
public String replaceBlank(String str)
{
String dest = "";
if(str!=null)
{
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(str);
dest = m.replaceAll("");
}
return dest;
}
/*
* 格式化报文
*/
public String format(String str)
{
if(str.trim().length() == 0)
{
return "";
}
str = str.replace("<", "\r<").replace("\r</field>", "</field>").replace("\r<?xml", "<?xml");
return str;
}
/*
* 取流水号对应的交易名称
*/
public String getDatagramName(String key, String datagramName)
{
String value = "";
if(key != null && datagramName.trim().length() != 0)
{
Map<String, String> map = new HashMap<String, String>();
String[] datagramNameArr = datagramName.contains(",") ? datagramName.split(",") : new String[] { datagramName };
for (String name : datagramNameArr)
{
if (name.contains(":"))
{
map.put(name.substring(0, name.indexOf(":")).trim(), name.substring(name.indexOf(":") + 1).trim());
}else
{
System.out.println("datagramName格式错误,例:seq_no1:aaaaaaa,seq_no2:bbbbbbbb");
}
}
if(map != null)
{
value = map.get(key);
}
}
return value;
}
}
四.
将相关信息写在配置文件 args.properties
#可查找任何唯一的字段,字段的名称(不区分大小写),一次只能查找一个字段,如:SERVICE_CODE , SEQ_NO , BUSS_SEQ_NO...
fieldName = SEQ_NO
#输入字段的值,一直能查找多个值,多个值用逗号隔开 如:2000001020180310093900000007,201000010201803100930000000
fieldValue = 2049180727001194073486
#存放日志的文件夹,默认logfiles文件夹,不用更改
logfileName = logfiles
#存放报文的文件夹,默认datagramfiles文件夹,不用更改
datagramfileName = datagramfiles
#自定义报文名称,多个用英文逗号隔开, 如果想要流水号05082208461425894的报文名称包含指定名字,写成这样 2018030520180305082208461425894:xxx-xxxx
#报文最终保存的名称, 如:xxx-xxxx&0100100000204(2018030520180305082208461425894)20180725-697070请求报文_1.xml
#datagramName = 2018030520180305082208461425894:xxx-xxxx,2018030520180305082208461425894:yyyy-yy
#是否需要连接服务器获取日志,连接:true/不连接:false
is_connect = true
#服务器地址
ip = 00.000.0.000
#端口号
port = 00
#账号
username = uesrname
#密码
password = 123456
#服务器保存日志的文件夹
logfilesDirPath = /wts/logs/rrylog/Server
#linux命令,多个命令用逗号隔开,如 grep -lr 213234234 * ; grep -lr 651254 * ,
#如果有多个流水号,可用#代替,运行时会自动将#替换成seq_no
#默认此查找命令不用修改
cmd = grep -lr # *
#本地保存日志的路径,如果需要保存在其他地方,可写上路径,默认保存在logfilename文件夹
#localPath=D:/abcdefg
#如果按其他字段查找可增加,格式如:tran_timestamp=<field type="string" length="17" scale="0">#</field> , 字段名小写,字段值用#代替
service_code=<field type="string" length="30" scale="0">#</field>
seq_no=<field type="string" length="52" scale="0">#</field>
buss_seq_no=<field type="string" length="22" scale="0">#</field>
打成jar包,用 .bat运行jar包。效果如下:
如果要截取其他字符,可以修改getDatagram(String logFilesPath,String target,String fieldName)和readFileAgain(int line,int beginLine,File file)方法
END
上一篇: PHP获取数据库表中的数据插入新的表再原删除数据方法
下一篇: 服务器上无法访问项目