背景
项目中有个实现是从java启动PowerShell, 然后执行ps1脚本,返回结果到java app处理。
历史原因,某代开发者的逻辑是这样:
- 读取PowerShell响应的输出流(json)作为业务返回数据,反序列化后使用
- 读物PowerShell响应的Error流作为异常数据
- PowerShell脚本产生的日志通过Write-Warning输出,在java app读取的时候通过"WARNING"关键词过滤
代码
public static void main(String[] args) {
try {
String script = "powershell C:\\test.ps1";
Process p = Runtime.getRuntime().exec(script);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String s = null;
while ((s = reader.readLine()) != null) {
//包含"WARNING"则认为是PowerShell脚本中的日志
//logic
System.out.println(s);
}
BufferedReader reader2 = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String s2 = null;
while ((s2 = reader2.readLine()) != null) {
System.out.println(s2);
}
} catch (Exception e) {
System.out.println("app error: " + e.getMessage());
}
}
问题
某一天,我在PowerShell脚本中输出了一个用于连接SQLServer的连接字符串看下日志,结果程序就异常了。
排查
查看java app读取返回的内容,发现我的日志(连接字符串)被截断,只留下字符串的后半部分。
前面说了,没被忽略的内容就当作业务处理了,自然在反序列换的时候出错了。
可是为什么日志会被截断?
之前也有日志输出过,没有问题。截断...莫不是因为字符串太长了?
于是改一下PowerShell脚本:
Write-Warning "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
输出一个巨长的Warning(对于我们项目的设定,这就是日志),200个"A"。
java app读取,换行了。
这个BufferedReader
有问题啊, 看下源代码:
/**
* Creates a buffering character-input stream that uses a default-sized
* input buffer.
*
* @param in A Reader
*/
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize);
}
private static int defaultCharBufferSize = 8192;
打脸了打脸了。默认能读老长了。
那在PowerShell脚本中换个输入方式试试
Write-Output "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
没有换行!
同样的我测试了Write-Error
也会输出换行
为什么?
官方资料并没有详细的解释。
但是根据我的测试,发现Write-Warning
和Write-Error
的输出最大宽度就是控制台的宽度(换行位置取决于控制台大小),超出即换行输出。