问题描述
即使我已经找到了解决方法(请参阅答案),我还是要问这个问题,以免其他人遭受同样的痛苦。
我需要一种方法来向我的 log4j 记录器显示我的数据集。我这样做了:
void org.apache.spark.sql.Dataset.show(int numRows,boolean truncate)
它只是记录到 stdOut。为了捕获 stdOut,我执行了以下操作(在 stackoverflow 上的其他地方找到了灵感):
void myMethod(Dataset<Row> data){
// Save the old System.out
PrintStream originalPrintStream = System.out;
// Tell Java to use your special stream
ByteArrayOutputStream logCollection = new ByteArrayOutputStream();
PrintStream printStreamForCollectingLogs = new PrintStream(logCollection);
System.setout(printStreamForCollectingLogs);
// Print some output: goes to your special stream
data.show(MAX_disPLAY_ROWS,false);
// Put things back
System.out.flush();
System.setout(originalPrintStream);
logger.info("\n"+logCollection.toString());
logCollection.reset();
}
这仅适用一次,后续对同一数据集调用同一方法将无法捕获任何内容。 我正在使用:
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.4.5</version>
解决方法
这个问题似乎是由于数据集保留了它第一次遇到的字节流作为 stdOut 引起的,因为我能够通过将我的备用 stdOut 流提取为类变量来解决这个问题:
private static ByteArrayOutputStream logCollection = new ByteArrayOutputStream();
private static PrintStream printStreamForCollectingLogs = new PrintStream(logCollection);
这意味着我每次都在 logger.info("\n"+logCollection.toString())
中使用相同的字节流。这使我可以随时调用 myMethod 并每次都捕获输出。