Skip to content

Commit fc64337

Browse files
authored
Reduce memory pressure in FormattingTestReporter (#737)
Reduce memory pressure in FormattingTestReporter
1 parent f61e6da commit fc64337

1 file changed

Lines changed: 62 additions & 18 deletions

File tree

gradle-witchcraft-logging/src/main/groovy/com/palantir/witchcraft/java/logging/gradle/testreport/FormattingTestReporter.java

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222
import com.palantir.witchcraft.java.logging.format.LogParser;
2323
import java.io.File;
2424
import java.io.IOException;
25-
import java.io.StringWriter;
25+
import java.io.UncheckedIOException;
2626
import java.io.Writer;
27+
import java.util.function.BiConsumer;
2728
import org.gradle.api.Action;
2829
import org.gradle.api.internal.tasks.testing.junit.result.TestClassResult;
2930
import org.gradle.api.internal.tasks.testing.junit.result.TestResultsProvider;
@@ -58,9 +59,24 @@ private static final class FormattingTestResultsProvider implements TestResultsP
5859
(include, formatted) -> include
5960
? writer -> {
6061
writer.write(formatted);
61-
writer.write("\n");
62+
writer.write('\n');
6263
}
6364
: Writable.NOP));
65+
private static final BiConsumer<String, Writer> LINE_PROCESSOR = (line, outputWriter) -> {
66+
try {
67+
PARSER.tryParse(line)
68+
.orElseGet(() -> out -> {
69+
try {
70+
out.write(line);
71+
} catch (IOException e) {
72+
throw new UncheckedIOException(e);
73+
}
74+
})
75+
.write(outputWriter);
76+
} catch (IOException e) {
77+
throw new UncheckedIOException(e);
78+
}
79+
};
6480

6581
private final TestResultsProvider delegate;
6682

@@ -69,30 +85,58 @@ private static final class FormattingTestResultsProvider implements TestResultsP
6985
}
7086

7187
@Override
72-
@SuppressWarnings("StringSplitter")
7388
public void writeAllOutput(long classId, TestOutputEvent.Destination destination, Writer writer) {
7489
if (destination == TestOutputEvent.Destination.StdErr
7590
|| destination == TestOutputEvent.Destination.StdOut) {
76-
StringWriter stringWriter = new StringWriter();
77-
delegate.writeAllOutput(classId, destination, stringWriter);
78-
String contents = stringWriter.toString();
79-
for (String line : contents.split("\n")) {
80-
try {
81-
PARSER.tryParse(line)
82-
.orElseGet(() -> out -> {
83-
out.write(line);
84-
out.write("\n");
85-
})
86-
.write(writer);
87-
} catch (IOException e) {
88-
throw new RuntimeException(e);
89-
}
90-
}
91+
delegate.writeAllOutput(classId, destination, new LineProcessingWriter(writer, LINE_PROCESSOR));
9192
} else {
9293
delegate.writeAllOutput(classId, destination, writer);
9394
}
9495
}
9596

97+
private static class LineProcessingWriter extends Writer {
98+
private final Writer delegate;
99+
private final BiConsumer<String, Writer> lineProcessor;
100+
private final StringBuilder lineBuffer = new StringBuilder();
101+
102+
LineProcessingWriter(Writer delegate, BiConsumer<String, Writer> lineProcessor) {
103+
this.delegate = delegate;
104+
this.lineProcessor = lineProcessor;
105+
}
106+
107+
@Override
108+
public void write(char[] cbuf, int off, int len) throws IOException {
109+
for (int i = off; i < off + len; i++) {
110+
char ch = cbuf[i];
111+
if (ch == '\n') {
112+
processLine();
113+
} else {
114+
lineBuffer.append(ch);
115+
}
116+
}
117+
}
118+
119+
@Override
120+
public void flush() throws IOException {
121+
delegate.flush();
122+
}
123+
124+
@Override
125+
public void close() throws IOException {
126+
if (!lineBuffer.isEmpty()) {
127+
processLine();
128+
}
129+
delegate.close();
130+
}
131+
132+
private void processLine() throws IOException {
133+
String line = lineBuffer.toString();
134+
lineProcessor.accept(line, delegate);
135+
delegate.write('\n');
136+
lineBuffer.setLength(0);
137+
}
138+
}
139+
96140
@Override
97141
public void writeNonTestOutput(long classId, TestOutputEvent.Destination destination, Writer writer) {
98142
delegate.writeNonTestOutput(classId, destination, writer);

0 commit comments

Comments
 (0)