欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java从服务器日志截取请求/响应XML报文或截取指定字符串

程序员文章站 2022-05-19 16:09:45
...

在做接口自动化过程中,需要获取请求/响应的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>

java从服务器日志截取请求/响应XML报文或截取指定字符串

打成jar包,用 .bat运行jar包。效果如下:

 

java从服务器日志截取请求/响应XML报文或截取指定字符串

java从服务器日志截取请求/响应XML报文或截取指定字符串

 

如果要截取其他字符,可以修改getDatagram(String logFilesPath,String target,String fieldName)和readFileAgain(int line,int beginLine,File file)方法

END